Index: oup/releases/0.34a/DataAccess/Access_OUP_ADB.pas
===================================================================
--- oup/releases/0.34a/DataAccess/Access_OUP_ADB.pas	(revision 200)
+++ oup/releases/0.34a/DataAccess/Access_OUP_ADB.pas	(revision 200)
@@ -0,0 +1,632 @@
+unit Access_OUP_ADB;
+interface
+
+uses DataAccess, ABSMain, TypeDefs, Classes;
+
+type
+  TAccess_OUP_ADB = class(TDataAccess)
+  private
+    FDatabase:          TABSDatabase;
+    FQuery:             TABSQuery;
+    Fdat_files:         TFiles;
+    Fdat_extensionsmap: TExtensionsMap;
+  protected
+  public
+    constructor Create(DBFilename: String; ConnectionID: Integer; var Msg: TStatusMessages); override;
+    procedure Close; override;
+
+    procedure UpdateListCache;
+
+    function GetLinksToFile(FileID: Integer): TLinks;
+
+    function GetFileInfo(FileID: Integer): TFileInfo; override;
+    function GetFilesList(Ext: String; Pattern: String;
+      NoEmptyFiles: Boolean; SortType: TSortType): TStrings; override;
+    function GetFileCount: Integer; override;
+    function GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings; override;
+
+    procedure LoadDatFile(FileID: Integer; var Target: TStream); overload; override;
+    procedure UpdateDatFile(FileID: Integer; Src: TStream); overload; override;
+    procedure LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream); overload; override;
+    procedure UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream); overload; override;
+
+    function GetDatLinks(FileID: Integer): TDatLinkList; override;
+    function GetDatLink(FileID, DatOffset: Integer): TDatLink; override;
+    function GetRawList(FileID: Integer): TRawDataList; override;
+    function GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo; override;
+
+    procedure LoadRawFile(FileID, DatOffset: Integer; var Target: TStream); overload; override;
+    procedure UpdateRawFile(FileID, DatOffset: Integer; Src: TStream); overload; override;
+    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream); overload; override;
+    procedure UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream); overload; override;
+  published
+  end;
+
+
+implementation
+
+uses
+  SysUtils, Data, Functions, ABSDecUtil, DB, DatLinks, StrUtils;
+
+
+(*
+================================================================================
+                     Implementation of  TOniDataADB
+*)
+
+
+constructor TAccess_OUP_ADB.Create(DBFilename: String; ConnectionID: Integer; var Msg: TStatusMessages);
+begin
+  Msg := SM_UnknownError;
+  if not FileExists(DBFilename) then
+  begin
+    Msg := SM_FileNotFound;
+    Exit;
+  end;
+  FFileName := DBFilename;
+
+  FDatabase := TABSDatabase.Create(nil);
+  FDatabase.Exclusive := True;
+  FDatabase.MultiUser := False;
+  FDatabase.DatabaseName := 'OLDBcon' + IntToStr(ConnectionID);
+  FDatabase.DatabaseFileName := DBFilename;
+  FDatabase.Open;
+  FQuery := TABSQuery.Create(FDatabase);
+  FQuery.DisableControls;
+  FQuery.RequestLive := False;
+  FQuery.DatabaseName := 'OLDBcon' + IntToStr(ConnectionID);
+  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
+        Msg := SM_IncompatibleDBVersion;
+        FQuery.Close;
+        Exit;
+      end;
+    end;
+    if FQuery.FieldByName('name').AsString = 'lvl' then
+      FLevelNumber := StrToInt(FQuery.FieldByName('value').AsString);
+    if FQuery.FieldByName('name').AsString = 'os' then
+    begin
+      if FQuery.FieldByName('value').AsString = 'WIN' then
+        FDataOS := DOS_WIN
+      else if FQuery.FieldByName('value').AsString = 'WINDEMO' then
+        FDataOS := DOS_WINDEMO
+      else if FQuery.FieldByName('value').AsString = 'MAC' then
+        FDataOS := DOS_MAC
+      else if FQuery.FieldByName('value').AsString = 'MACBETA' then
+        FDataOS := DOS_MACBETA;
+    end;
+    FQuery.Next;
+  until FQuery.EOF;
+  FQuery.Close;
+
+  Msg := SM_OK;
+  FBackend := DB_ADB;
+
+  FConnectionID := ConnectionID;
+  FChangeRights := [CR_EditDat, CR_EditRaw, CR_ResizeDat, CR_ResizeRaw];
+
+  UpdateListCache;
+end;
+
+
+
+
+procedure TAccess_OUP_ADB.Close;
+begin
+  FQuery.Free;
+  FDatabase.Close;
+  FDatabase.Free;
+  Self.Free;
+end;
+
+
+
+procedure TAccess_OUP_ADB.UpdateListCache;
+var
+  i:     Integer;
+  temps: String;
+begin
+  FQuery.SQL.Text := 'SELECT id,name,extension,[size],contenttype FROM datfiles ORDER BY id ASC;';
+  FQuery.Open;
+  SetLength(Fdat_files, FQuery.RecordCount);
+  if FQuery.RecordCount > 0 then
+  begin
+    FQuery.First;
+    i := 0;
+    repeat
+      Fdat_files[i].ID := FQuery.FieldByName('id').AsInteger;
+      Fdat_files[i].Name := FQuery.FieldByName('name').AsString;
+      Fdat_files[i].Extension := FQuery.FieldByName('extension').AsString;
+      Fdat_files[i].Size := FQuery.FieldByName('size').AsInteger;
+      Fdat_files[i].FileType := StrToInt('$'+FQuery.FieldByName('contenttype').AsString);
+      Fdat_files[i].DatAddr := 0;
+      Inc(i);
+      FQuery.Next;
+    until FQuery.EOF;
+  end;
+  FQuery.Close;
+
+  FQuery.SQL.Text :=
+    'SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;';
+  FQuery.Open;
+  SetLength(Fdat_extensionsmap, FQuery.RecordCount);
+  if FQuery.RecordCount > 0 then
+  begin
+    i := 0;
+    repeat
+      temps := FQuery.FieldByName('extension').AsString;
+      Fdat_extensionsmap[i].Extension[3] := temps[1];
+      Fdat_extensionsmap[i].Extension[2] := temps[2];
+      Fdat_extensionsmap[i].Extension[1] := temps[3];
+      Fdat_extensionsmap[i].Extension[0] := temps[4];
+      Fdat_extensionsmap[i].ExtCount := FQuery.FieldByName('x').AsInteger;
+      Inc(i);
+      FQuery.Next;
+    until FQuery.EOF;
+  end;
+  FQuery.Close;
+end;
+
+
+
+function TAccess_OUP_ADB.GetLinksToFile(FileID: Integer): TLinks;
+var
+  i: Integer;
+begin
+  SetLength(Result.ByName, 0);
+  FQuery.SQL.Text := 'SELECT src_link_offset, src_id FROM linkmap WHERE target_id = ' + IntToStr(FileID) + ' ORDER BY src_id ASC;';
+  FQuery.Open;
+  SetLength(Result.ByID, FQuery.RecordCount);
+  if FQuery.RecordCount > 0 then
+  begin
+    i := 0;
+    repeat
+      Result.ByID[i].SrcOffset := FQuery.FieldByName('src_link_offset').AsInteger;
+      Result.ByID[i].Destination := FQuery.FieldByName('src_id').AsInteger;
+      Inc(i);
+      FQuery.Next;
+    until FQuery.EOF;
+  end;
+  FQuery.Close;
+end;
+
+
+
+function TAccess_OUP_ADB.GetFileInfo(fileid: Integer): TFileInfo;
+begin
+  if fileid = -1 then
+  begin
+    Result := inherited GetFileInfo(fileid);
+    Exit;
+  end;
+  if fileid < Self.GetFileCount then
+    Result    := Fdat_files[fileid]
+  else
+    Result.ID := -1;
+end;
+
+
+
+  function CompareItems(List: TStringList; I1, I2: Integer): Integer;
+  var
+    s1, s2: String;
+  begin
+    s1 := MidStr(List[I1], 1, PosEx(';', List[I1], 6) - 1);
+    s2 := MidStr(List[I2], 1, PosEx(';', List[I2], 6) - 1);
+    Result := CompareStr(s1, s2);
+  end;
+
+function TAccess_OUP_ADB.GetFilesList(ext: String; pattern: String;
+  NoEmptyFiles: Boolean; SortType: TSortType): TStrings;
+var
+  i:      Integer;
+  list:   TStringList;
+  id, name, extension: String;
+  fields: TStrings;
+
+  procedure getfields;
+  begin
+    fields.CommaText := StringReplace(AnsiQuotedStr(list.Strings[i], '"'), ';', '","', [rfReplaceAll]);
+    if SortType in [ST_IDAsc, ST_IDDesc] then
+    begin
+      id := fields.Strings[0];
+      name := fields.Strings[1];
+      extension := fields.Strings[2];
+    end;
+    if SortType in [ST_NameAsc, ST_NameDesc] then
+    begin
+      id := fields.Strings[1];
+      name := fields.Strings[0];
+      extension := fields.Strings[2];
+    end;
+    if SortType in [ST_ExtAsc, ST_ExtDesc] then
+    begin
+      id := fields.Strings[1];
+      name := fields.Strings[2];
+      extension := fields.Strings[0];
+    end;
+    if SortType in [ST_ExtNameAsc, ST_ExtNameDesc] then
+    begin
+      id := fields.Strings[2];
+      name := fields.Strings[1];
+      extension := fields.Strings[0];
+    end;
+  end;
+
+begin
+  list := TStringList.Create;
+  if SortType in [ST_ExtNameAsc, ST_ExtNameDesc] then
+    list.Sorted := False
+  else
+    list.Sorted := True;
+  for i := 0 to GetFileCount - 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
+        id := FormatNumber(Fdat_files[i].ID, 5, '0');
+        name := Fdat_files[i].Name;
+        extension := Fdat_files[i].Extension;
+
+        case SortType of
+          ST_IDAsc, ST_IDDesc:     list.Add(id + ';' + name + ';' + extension);
+          ST_NameAsc, ST_NameDesc: list.Add(name + ';' + id + ';' + extension);
+          ST_ExtAsc, ST_ExtDesc:   list.Add(extension + ';' + id + ';' + name);
+          ST_ExtNameAsc, ST_ExtNameDesc: list.Add(extension + ';' + name + ';' + id);
+        end;
+      end;
+    end;
+  end;
+  if SortType in [ST_ExtNameAsc, ST_ExtNameDesc] then
+    list.CustomSort(CompareItems);
+  if not Assigned(Result) then
+    Result := TStringList.Create;
+  if list.Count > 0 then
+  begin
+    fields := TStringList.Create;
+    if SortType in [ST_IDAsc, ST_NameAsc, ST_ExtAsc, ST_ExtNameAsc] then
+      for i := 0 to list.Count - 1 do
+      begin
+        getfields;
+        Result.Add(id + '-' + name + '.' + extension);
+      end
+    else
+      for i := list.Count - 1 downto 0 do
+      begin
+        getfields;
+        Result.Add(id + '-' + name + '.' + extension);
+      end;
+    fields.Free;
+  end;
+  list.Free;
+end;
+
+
+
+
+function TAccess_OUP_ADB.GetFileCount: Integer;
+begin
+  Result := Length(Fdat_files);
+end;
+
+
+function TAccess_OUP_ADB.GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings;
+var
+  i: Integer;
+begin
+  if not Assigned(Result) then
+    Result := TStringList.Create;
+  if Result is TStringList then
+    TStringList(Result).Sorted := True;
+  for i := 0 to Length(Fdat_extensionsmap) - 1 do
+  begin
+    with Fdat_extensionsmap[i] do
+    begin
+      case ExtListFormat of
+        EF_ExtOnly:
+          Result.Add(Extension[3] + Extension[2] + Extension[1] + Extension[0]);
+        EF_ExtCount:
+          Result.Add(Extension[3] + Extension[2] + Extension[1] + Extension[0] +
+                ' (' + IntToStr(ExtCount) + ')');
+      end;
+    end;
+  end;
+end;
+
+
+procedure TAccess_OUP_ADB.LoadDatFile(FileID: Integer; var Target: TStream);
+var
+  mem: TStream;
+  streampos: Integer;
+begin
+  if fileid < GetFileCount then
+  begin
+    if not Assigned(Target) then
+      Target := TMemoryStream.Create;
+
+    streampos := Target.Position;
+
+    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(0, soFromBeginning);
+      Target.CopyFrom(mem, mem.Size);
+      mem.Free;
+    end;
+    FQuery.Close;
+
+    Target.Seek(streampos, soFromBeginning);
+  end;
+end;
+
+procedure TAccess_OUP_ADB.UpdateDatFile(FileID: Integer; Src: TStream);
+var
+  MimeCoder: TStringFormat_MIME64;
+  mem: TMemoryStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    mimecoder := TStringFormat_MIME64.Create;
+    mem := TMemoryStream.Create;
+    mem.CopyFrom(Src, Src.Size); 
+    FQuery.SQL.Text := 'UPDATE datfiles SET data=MimeToBin("' +
+      MimeCoder.StrTo(mem.Memory, mem.Size) + '"), size=' + IntToStr(mem.Size) +
+      ' WHERE id=' + IntToStr(fileid) + ';';
+    FQuery.ExecSQL;
+    mem.Free;
+    mimecoder.Free;
+  end;
+end;
+
+
+
+procedure TAccess_OUP_ADB.LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream);
+var
+  streampos: Integer;
+  mem: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    if not Assigned(Target) then
+      Target := TMemoryStream.Create;
+    streampos := Target.Position;
+
+    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);
+      Target.CopyFrom(mem, size);
+      mem.Free;
+    end;
+    FQuery.Close;
+    Target.Seek(streampos, soFromBeginning);
+  end;
+end;
+
+
+
+procedure TAccess_OUP_ADB.UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream);
+var
+  MimeCoder: TStringFormat_MIME64;
+  mem:  TMemoryStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    mem := nil;
+    LoadDatFile(fileid, TStream(mem));
+    mem.Seek(Offset, soFromBeginning);
+    mem.CopyFrom(Src, Size);
+    mem.Seek(0, soFromBeginning);
+    mimecoder := TStringFormat_MIME64.Create;
+    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 TAccess_OUP_ADB.GetDatLink(FileID, DatOffset: Integer): TDatLink;
+begin
+  Result := DatLinksManager.GetDatLink(FConnectionID, FileID, DatOffset);
+  FQuery.SQL.Text := 'SELECT target_id FROM linkmap WHERE src_id = ' + IntToStr(FileID) + ' and src_link_offset = ' + IntToStr(DatOffset) + ';';
+  FQuery.Open;
+  if FQuery.RecordCount > 0 then
+    Result.DestID := FQuery.FieldByName('target_id').AsInteger;
+  FQuery.Close;
+end;
+
+
+function TAccess_OUP_ADB.GetDatLinks(FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+  SrcOffset, DestID: Integer;
+begin
+  Result := DatLinksManager.GetDatLinks(FConnectionID, FileID);
+  if Length(Result) > 0 then
+  begin
+    FQuery.SQL.Text := 'SELECT src_link_offset, target_id FROM linkmap WHERE src_id = ' + IntToStr(FileID) + ' ORDER BY src_link_offset ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount > 0 then
+    begin
+      repeat
+        SrcOffset := FQuery.FieldByName('src_link_offset').AsInteger;
+        DestID := FQuery.FieldByName('target_id').AsInteger;
+        for i := 0 to High(Result) do
+          if Result[i].SrcOffset = SrcOffset then
+            Break;
+        if i < Length(Result) then
+          Result[i].DestID := DestID
+        else
+          Result[i].DestID := -1;
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+end;
+
+
+function TAccess_OUP_ADB.GetRawList(FileID: Integer): TRawDataList;
+var
+  i: Integer;
+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].SrcID     := fileid;
+      Result[i].SrcOffset := FQuery.FieldByName('src_link_offset').AsInteger;
+      Result[i].RawAddr   := 0;
+      Result[i].RawSize   := FQuery.FieldByName('size').AsInteger;
+      Result[i].LocSep    := FQuery.FieldByName('sep').AsBoolean;
+      Inc(i);
+      FQuery.Next;
+    until FQuery.EOF;
+  end;
+  FQuery.Close;
+end;
+
+
+function TAccess_OUP_ADB.GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo;
+var
+  i: Integer;
+  rawlist: TRawDataList;
+begin
+  rawlist := GetRawList(FileID);
+  if Length(rawlist) > 0 then
+  begin
+    for i := 0 to High(rawlist) do
+      if rawlist[i].SrcOffset = DatOffset then
+        Break;
+    if i < Length(rawlist) then
+      Result := rawlist[i]
+    else begin
+      Result.SrcID     := -1;
+      Result.SrcOffset := -1;
+      Result.RawAddr   := -1;
+      Result.RawSize   := -1;
+    end;
+  end;
+end;
+
+
+
+procedure TAccess_OUP_ADB.LoadRawFile(FileID, DatOffset: Integer; var Target: TStream);
+var
+  mem: TStream;
+  streampos: Integer;
+begin
+  if fileid < GetFileCount then
+  begin
+    if not Assigned(Target) then
+      Target := TMemoryStream.Create;
+    streampos := Target.Position;
+    FQuery.SQL.Text := 'SELECT data FROM rawmap WHERE (src_id=' +
+      IntToStr(FileID) + ') AND (src_link_offset=' + IntToStr(DatOffset) + ');';
+    FQuery.Open;
+    if FQuery.RecordCount > 0 then
+    begin
+      mem := FQuery.CreateBlobStream(FQuery.FieldByName('data'), bmRead);
+      mem.Seek(0, soFromBeginning);
+      Target.CopyFrom(mem, mem.Size);
+      mem.Free;
+    end;
+    FQuery.Close;
+    Target.Seek(streampos, soFromBeginning);
+  end;
+end;
+
+
+procedure TAccess_OUP_ADB.UpdateRawFile(FileID, DatOffset: Integer; Src: TStream);
+var
+  MimeCoder: TStringFormat_MIME64;
+  mem: TMemoryStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    mimecoder := TStringFormat_MIME64.Create;
+    mem := TMemoryStream.Create;
+    mem.CopyFrom(Src, Src.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(DatOffset) + ');';
+    FQuery.ExecSQL;
+    mem.Free;
+    mimecoder.Free;
+  end;
+end;
+
+
+
+
+procedure TAccess_OUP_ADB.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream);
+var
+  mem:  TMemoryStream;
+  streampos: Integer;
+begin
+  if fileid < GetFileCount then
+  begin
+    if not Assigned(Target) then
+      Target := TMemoryStream.Create;
+    streampos := Target.Position;
+    mem := nil;
+    LoadRawFile(FileID, DatOffset, TStream(mem));
+    mem.Seek(Offset, soFromBeginning);
+    Target.CopyFrom(mem, Size);
+    mem.Free;
+    Target.Seek(streampos, soFromBeginning);
+  end;
+end;
+
+
+
+
+procedure TAccess_OUP_ADB.UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream);
+var
+  MimeCoder: TStringFormat_MIME64;
+  mem:  TMemoryStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    mem := nil;
+    LoadRawFile(fileid, offset, TStream(mem));
+    mem.Seek(offset, soFromBeginning);
+    mem.CopyFrom(Src, Size);
+    mem.Seek(0, soFromBeginning);
+    mimecoder := TStringFormat_MIME64.Create;
+    FQuery.SQL.Text := 'UPDATE rawmap SET data=MimeToBin("' + MimeCoder.StrTo(
+      mem.Memory, mem.Size) + '") WHERE (src_id=' + IntToStr(fileid) +
+      ') AND (src_link_offset=' + IntToStr(DatOffset) + ');';
+    FQuery.ExecSQL;
+    mem.Free;
+    mimecoder.Free;
+  end;
+end;
+
+
+
+
+end.
Index: oup/releases/0.34a/DataAccess/Access_OniArchive.pas
===================================================================
--- oup/releases/0.34a/DataAccess/Access_OniArchive.pas	(revision 200)
+++ oup/releases/0.34a/DataAccess/Access_OniArchive.pas	(revision 200)
@@ -0,0 +1,695 @@
+unit Access_OniArchive;
+interface
+
+uses DataAccess, Classes, TypeDefs;
+
+type
+  TAccess_OniArchive = class(TDataAccess)
+  private
+    Fdat_file:           TFileStream;
+    Fraw_file:           TFileStream;
+    Fsep_file:           TFileStream;
+    Fdat_files:          TFiles;
+    Fdat_extensionsmap:  TExtensionsMap;
+    FUnloadWhenUnused:   Boolean;
+    FDatOpened:          Boolean;
+    FRawOpened:          Boolean;
+    FSepOpened:          Boolean;
+  protected
+  public
+    property UnloadWhenUnused: Boolean Read FUnloadWhenUnused Write FUnloadWhenUnused;
+
+    constructor Create(DatFilename: String; ConnectionID: Integer; var Msg: TStatusMessages); override;
+    procedure Close; override;
+
+    function GetFileInfo(FileID: Integer): TFileInfo; override;
+    function GetFilesList(Ext: String; Pattern: String;
+      NoEmptyFiles: Boolean; SortType: TSortType): TStrings; override;
+    function GetFileCount: Integer; override;
+    function GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings; override;
+
+    procedure LoadDatFile(FileID: Integer; var Target: TStream); overload; override;
+    procedure UpdateDatFile(FileID: Integer; Src: TStream); overload; override;
+    procedure LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream); overload; override;
+    procedure UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream); overload; override;
+
+    function GetDatLinks(FileID: Integer): TDatLinkList; override;
+    function GetDatLink(FileID, DatOffset: Integer): TDatLink; override;
+    function GetRawList(FileID: Integer): TRawDataList; override;
+    function GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo; override;
+
+    procedure LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; var target: TStream); overload;
+    procedure LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; target: Pointer); overload;
+    procedure LoadRawFile(FileID, DatOffset: Integer; var Target: TStream); overload; override;
+    procedure UpdateRawFile(FileID, DatOffset: Integer; Src: TStream); overload; override;
+    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream); overload; override;
+    procedure UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream); overload; override;
+
+    function AppendRawFile(LocSep: Boolean; Src: TStream): Integer; overload; override;
+  published
+  end;
+
+implementation
+
+uses
+  SysUtils, StrUtils, Data, Functions, RawList, DatLinks, Math;
+
+
+(*
+================================================================================
+                      Implementation of  TOniDataDat
+*)
+
+
+constructor TAccess_OniArchive.Create(DatFilename: String; ConnectionID: Integer; var Msg: TStatusMessages);
+var
+  i: Integer;
+  header_pc, header_mac, header_macbeta: Boolean;
+  Fdat_header:   THeader;
+  Fdat_filesmap: TFilesMap;
+  Fdat_namedfilesmap: TNamedFilesMap;
+begin
+  FUnloadWhenUnused := True;
+  FDatOpened := False;
+  FRawOpened := False;
+  Msg := SM_UnknownError;
+  if not FileExists(DatFilename) then
+  begin
+    Msg := SM_FileNotFound;
+    Exit;
+  end;
+  FFileName := DatFilename;
+  Fdat_file := TFileStream.Create(FFileName, fmOpenRead);
+  Fdat_file.Read(Fdat_header, SizeOf(Fdat_header));
+  header_pc  := True;
+  header_mac := True;
+  header_macbeta := True;
+  for i := 0 to High(Fdat_header.GlobalIdent) do
+    if Fdat_header.GlobalIdent[i] <> HeaderGlobalIdent[i] then
+    begin
+      Msg := SM_IncompatibleFile;
+      Exit;
+    end;
+
+  for i := 0 to High(Fdat_header.OSIdent) do
+  begin
+    if Fdat_header.OSIdent[i] <> HeaderOSIdentWin[i] then
+      header_pc := False;
+    if Fdat_header.OSIdent[i] <> HeaderOSIdentMac[i] then
+      header_mac := False;
+    if Fdat_header.OSIdent[i] <> HeaderOSIdentMacBeta[i] then
+      header_macbeta := False;
+  end;
+  if not (header_pc xor header_mac xor header_macbeta) then
+  begin
+    Msg := SM_IncompatibleFile;
+    Exit;
+  end
+  else
+  begin
+    if (header_pc and not header_mac and not header_macbeta) then
+      FDataOS := DOS_WIN
+    else if (not header_pc and header_mac and not header_macbeta) then
+      FDataOS := DOS_MAC
+    else if (not header_pc and not header_mac and header_macbeta) then
+      FDataOS := DOS_MACBETA;
+  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].ID := i;
+    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;
+  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(FLevelNumber, 1);
+  FLevelNumber := FLevelNumber div 2;
+
+  Fdat_file.Free;
+
+  Msg := SM_OK;
+  FBackend := DB_ONI;
+  FConnectionID := ConnectionID;
+  FChangeRights := [CR_EditDat, CR_EditRaw, CR_AppendRaw];
+end;
+
+
+
+
+procedure TAccess_OniArchive.Close;
+begin
+  if FDatOpened then
+    Fdat_file.Free;
+  if FRawOpened then
+    Fraw_file.Free;
+  if FSepOpened then
+    Fsep_file.Free;
+  Self.Free;
+end;
+
+
+
+
+function TAccess_OniArchive.GetFileInfo(fileid: Integer): TFileInfo;
+begin
+  if fileid = -1 then
+  begin
+    Result := inherited GetFileInfo(fileid);
+    Exit;
+  end;
+  if fileid < Self.GetFileCount then
+    Result    := Fdat_files[fileid]
+  else
+    Result.ID := -1;
+end;
+
+
+
+
+function TAccess_OniArchive.GetFilesList(ext: String; pattern: String;
+  NoEmptyFiles: Boolean; SortType: TSortType): TStrings;
+var
+  i:      Integer;
+  list:   TStringList;
+  id, name, extension: String;
+  fields: TStrings;
+
+  procedure getfields;
+  begin
+    fields.CommaText := StringReplace(AnsiQuotedStr(list.Strings[i], '"'), ';', '","', [rfReplaceAll]);
+    if SortType in [ST_IDAsc, ST_IDDesc] then
+    begin
+      id := fields.Strings[0];
+      name := fields.Strings[1];
+      extension := fields.Strings[2];
+    end;
+    if SortType in [ST_NameAsc, ST_NameDesc] then
+    begin
+      id := fields.Strings[1];
+      name := fields.Strings[0];
+      extension := fields.Strings[2];
+    end;
+    if SortType in [ST_ExtAsc, ST_ExtDesc] then
+    begin
+      id := fields.Strings[1];
+      name := fields.Strings[2];
+      extension := fields.Strings[0];
+    end;
+    if SortType in [ST_ExtNameAsc, ST_ExtNameDesc] then
+    begin
+      id := fields.Strings[2];
+      name := fields.Strings[1];
+      extension := fields.Strings[0];
+    end;
+  end;
+
+begin
+  list := TStringList.Create;
+  list.Sorted := True;
+  for i := 0 to GetFileCount - 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
+        id := FormatNumber(Fdat_files[i].ID, 5, '0');
+        name := Fdat_files[i].Name;
+        extension := Fdat_files[i].Extension;
+
+        case SortType of
+          ST_IDAsc, ST_IDDesc:     list.Add(id + ';' + name + ';' + extension);
+          ST_NameAsc, ST_NameDesc: list.Add(name + ';' + id + ';' + extension);
+          ST_ExtAsc, ST_ExtDesc:   list.Add(extension + ';' + id + ';' + name);
+          ST_ExtNameAsc, ST_ExtNameDesc: list.Add(name + ';' + extension + ';' + id);
+        end;
+      end;
+    end;
+  end;
+  if not Assigned(Result) then
+    Result := TStringList.Create;
+  if list.Count > 0 then
+  begin
+    fields := TStringList.Create;
+    if SortType in [ST_IDAsc, ST_NameAsc, ST_ExtAsc, ST_ExtNameAsc] then
+      for i := 0 to list.Count - 1 do
+      begin
+        getfields;
+        Result.Add(id + '-' + name + '.' + extension);
+      end
+    else
+      for i := list.Count - 1 downto 0 do
+      begin
+        getfields;
+        Result.Add(id + '-' + name + '.' + extension);
+      end;
+    fields.Free;
+  end;
+  list.Free;
+end;
+
+
+
+
+function TAccess_OniArchive.GetFileCount: Integer;
+begin
+  Result := Length(Fdat_files);
+end;
+
+
+
+
+function TAccess_OniArchive.GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings;
+var
+  i: Integer;
+begin
+  if not Assigned(Result) then
+    Result := TStringList.Create;
+  if Result is TStringList then
+    TStringList(Result).Sorted := True;
+  for i := 0 to Length(Fdat_extensionsmap) - 1 do
+  begin
+    with Fdat_extensionsmap[i] do
+    begin
+      case ExtListFormat of
+        EF_ExtOnly:
+          Result.Add(Extension[3] + Extension[2] + Extension[1] + Extension[0]);
+        EF_ExtCount:
+          Result.Add(Extension[3] + Extension[2] + Extension[1] + Extension[0] +
+                ' (' + IntToStr(ExtCount) + ')');
+      end;
+    end;
+  end;
+end;
+
+
+
+procedure TAccess_OniArchive.LoadDatFile(FileID: Integer; var Target: TStream);
+var
+  streampos: Integer;
+begin
+  if fileid < GetFileCount then
+  begin
+    if not Assigned(Target) then
+      Target := TMemoryStream.Create;
+    if not FDatOpened then
+      Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
+    Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning);
+    streampos := Target.Position;
+    Target.CopyFrom(Fdat_file, Fdat_files[fileid].Size);
+    Target.Seek(streampos, soFromBeginning);
+    if UnloadWhenUnused then
+    begin
+      Fdat_file.Free;
+      FDatOpened := False;
+    end
+    else
+      FDatOpened := True;
+  end;
+end;
+
+procedure TAccess_OniArchive.UpdateDatFile(FileID: Integer; Src: TStream);
+begin
+  if fileid < GetFileCount then
+  begin
+    if not FDatOpened then
+      Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
+    Fdat_file.Seek(Fdat_files[fileid].DatAddr, soFromBeginning);
+    Fdat_file.CopyFrom(Src, Fdat_files[fileid].Size);
+    if UnloadWhenUnused then
+    begin
+      Fdat_file.Free;
+      FDatOpened := False;
+    end
+    else
+      FDatOpened := True;
+  end;
+end;
+
+procedure TAccess_OniArchive.LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream);
+var
+  streampos: Integer;
+begin
+  if fileid < GetFileCount then
+  begin
+    if not Assigned(Target) then
+      Target := TMemoryStream.Create;
+    if not FDatOpened then
+      Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
+    Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning);
+    streampos := Target.Position;
+    Target.CopyFrom(Fdat_file, size);
+    Target.Seek(streampos, soFromBeginning);
+    if UnloadWhenUnused then
+    begin
+      FDatOpened := False;
+      Fdat_file.Free;
+    end
+    else
+      FDatOpened := True;
+  end;
+end;
+
+procedure TAccess_OniArchive.UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream);
+begin
+  if fileid < GetFileCount then
+  begin
+    if not FDatOpened then
+      Fdat_file := TFileStream.Create(FFileName, fmOpenReadWrite);
+    Fdat_file.Seek(Fdat_files[fileid].DatAddr + offset, soFromBeginning);
+    Fdat_file.CopyFrom(Src, Size);
+    if UnloadWhenUnused then
+    begin
+      Fdat_file.Free;
+      FDatOpened := False;
+    end
+    else
+      FDatOpened := True;
+  end;
+end;
+
+
+
+function TAccess_OniArchive.GetDatLink(FileID, DatOffset: Integer): TDatLink;
+var
+  link: Integer;
+begin
+  Result := DatLinksManager.GetDatLink(FConnectionID, FileID, DatOffset);
+  LoadDatFilePart(fileid, Result.SrcOffset, 4, @link);
+  if link > 0 then
+    Result.DestID := link div 256
+  else
+    Result.DestID := -1;
+end;
+
+
+function TAccess_OniArchive.GetDatLinks(FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+  link: Integer;
+begin
+  Result := DatLinksManager.GetDatLinks(FConnectionID, FileID);
+  if Length(Result) > 0 then
+  begin
+    for i := 0 to High(Result) do
+    begin
+      LoadDatFilePart(fileid, Result[i].SrcOffset, 4, @link);
+      if link > 0 then
+        Result[i].DestID := link div 256
+      else
+        Result[i].DestID := -1;
+    end;
+  end;
+end;
+
+
+function TAccess_OniArchive.GetRawList(FileID: Integer): TRawDataList;
+begin
+  Result := RawLists.GetRawList(FConnectionID, FileID);
+end;
+
+
+function TAccess_OniArchive.GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo;
+begin
+  Result := RawLists.GetRawInfo(FConnectionID, FileID, DatOffset);
+end;
+
+
+
+procedure TAccess_OniArchive.LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; var target: TStream);
+begin
+  if not Assigned(Target) then
+    Target := TMemoryStream.Create;
+  if not LocSep then
+  begin
+    if not FRawOpened then
+      Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
+        fmOpenReadWrite);
+    if RawAddr <= Fraw_file.Size then
+    begin
+      Fraw_file.Seek(RawAddr, soFromBeginning);
+      Target.CopyFrom(Fraw_file, size);
+      Target.Seek(0, soFromBeginning);
+    end;
+    if UnloadWhenUnused then
+    begin
+      FRawOpened := False;
+      Fraw_file.Free;
+    end
+    else
+      FRawOpened := True;
+  end
+  else
+  begin
+    if not FSepOpened then
+      Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
+        fmOpenReadWrite);
+    if RawAddr <= Fsep_file.Size then
+    begin
+      Fsep_file.Seek(RawAddr, soFromBeginning);
+      Target.CopyFrom(Fsep_file, size);
+      Target.Seek(0, soFromBeginning);
+    end;
+    if UnloadWhenUnused then
+    begin
+      FSepOpened := False;
+      Fsep_file.Free;
+    end
+    else
+      FSepOpened := True;
+  end;
+end;
+
+procedure TAccess_OniArchive.LoadRawOffset(LocSep: Boolean; RawAddr, Size: Integer; target: Pointer);
+var
+  data: TStream;
+begin
+  data := nil;
+  LoadRawOffset(LocSep, RawAddr, Size, data);
+  data.Read(Target^, Size);
+  data.Free;
+end;
+
+procedure TAccess_OniArchive.LoadRawFile(FileID, DatOffset: Integer; var Target: TStream);
+var
+  raw_info: TRawDataInfo;
+  streampos: Integer;
+begin
+  if not Assigned(Target) then
+    Target := TMemoryStream.Create;
+  if fileid < GetFileCount then
+  begin
+    raw_info := Self.GetRawInfo(FileID, DatOffset);
+    if not raw_info.LocSep then
+    begin
+      if not FRawOpened then
+        Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
+          fmOpenReadWrite);
+      Fraw_file.Seek(raw_info.RawAddr, soFromBeginning);
+      streampos := Target.Position;
+      Target.CopyFrom(Fraw_file, raw_info.RawSize);
+      Target.Seek(streampos, soFromBeginning);
+      if UnloadWhenUnused then
+      begin
+        FRawOpened := False;
+        Fraw_file.Free;
+      end
+      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.RawAddr, soFromBeginning);
+      streampos := Target.Position;
+      Target.CopyFrom(Fsep_file, raw_info.RawSize);
+      Target.Seek(streampos, soFromBeginning);
+      if UnloadWhenUnused then
+      begin
+        FSepOpened := False;
+        Fsep_file.Free;
+      end
+      else
+        FSepOpened := True;
+    end;
+  end;
+end;
+
+procedure TAccess_OniArchive.UpdateRawFile(FileID, DatOffset: Integer; Src: TStream);
+var
+  raw_info: TRawDataInfo;
+begin
+  if fileid < GetFileCount then
+  begin
+    raw_info := GetRawInfo(FileID, DatOffset);
+    if not raw_info.LocSep then
+    begin
+      if not FRawOpened then
+        Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
+          fmOpenReadWrite);
+      Fraw_file.Seek(raw_info.RawAddr, soFromBeginning);
+      Fraw_file.CopyFrom(Src, Min(raw_info.RawSize, Src.Size));
+      if UnloadWhenUnused then
+      begin
+        FRawOpened := False;
+        Fraw_file.Free;
+      end
+      else
+        FRawOpened := True;
+    end
+    else
+    begin
+      if not FSepOpened then
+        Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
+          fmOpenReadWrite);
+      Fsep_file.Seek(raw_info.RawAddr, soFromBeginning);
+      Fsep_file.CopyFrom(Src, raw_info.RawSize);
+      if UnloadWhenUnused then
+      begin
+        FSepOpened := False;
+        Fsep_file.Free;
+      end
+      else
+        FSepOpened := True;
+    end;
+  end;
+end;
+
+procedure TAccess_OniArchive.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream);
+var
+  Data: TStream;
+  streampos: Integer;
+begin
+  if not Assigned(Target) then
+    Target := TMemoryStream.Create;
+  if fileid < Self.GetFileCount then
+  begin
+    data := nil;
+    LoadRawFile(FileID, DatOffset, Data);
+    Data.Seek(Offset, soFromBeginning);
+    streampos := Target.Position;
+    Target.CopyFrom(Data, Size);
+    Target.Seek(streampos, soFromBeginning);
+  end;
+end;
+
+
+procedure TAccess_OniArchive.UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream);
+var
+  raw_info: TRawDataInfo;
+begin
+  if fileid < GetFileCount then
+  begin
+    raw_info := GetRawInfo(FileID, DatOffset);
+    if not raw_info.LocSep then
+    begin
+      if not FRawOpened then
+        Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
+          fmOpenReadWrite);
+      Fraw_file.Seek(raw_info.RawAddr + Offset, soFromBeginning);
+      Fraw_file.CopyFrom(Src, Size);
+      if UnloadWhenUnused then
+      begin
+        FRawOpened := False;
+        Fraw_file.Free;
+      end
+      else
+        FRawOpened := True;
+    end
+    else
+    begin
+      if not FSepOpened then
+        Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
+          fmOpenReadWrite);
+      Fsep_file.Seek(raw_info.RawAddr + Offset, soFromBeginning);
+      Fsep_file.CopyFrom(Src, Size);
+      if UnloadWhenUnused then
+      begin
+        FSepOpened := False;
+        Fsep_file.Free;
+      end
+      else
+        FSepOpened := True;
+    end;
+  end;
+end;
+
+function TAccess_OniArchive.AppendRawFile(LocSep: Boolean; Src: TStream): Integer;
+const
+  EmptyBytes: Array[0..31] of Byte = (
+      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,0,0,0,0,0,0,0 );
+begin
+  if not LocSep then
+  begin
+    if not FRawOpened then
+      Fraw_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.raw'),
+        fmOpenReadWrite);
+    if (Fraw_file.Size mod 32) > 0 then
+      Fraw_file.Write(EmptyBytes[0], 32 - (Fraw_file.Size mod 32));
+    Result := Fraw_file.Size;
+    Fraw_file.Seek(0, soFromEnd);
+    Fraw_file.CopyFrom(Src, Src.Size);
+    if (Fraw_file.Size mod 32) > 0 then
+      Fraw_file.Write(EmptyBytes[0], 32 - (Fraw_file.Size mod 32));
+    if UnloadWhenUnused then
+    begin
+      FRawOpened := False;
+      Fraw_file.Free;
+    end
+    else
+      FRawOpened := True;
+  end
+  else
+  begin
+    if not FSepOpened then
+      Fsep_file := TFileStream.Create(AnsiReplaceStr(FFileName, '.dat', '.sep'),
+        fmOpenReadWrite);
+    if (Fsep_file.Size mod 32) > 0 then
+      Fsep_file.Write(EmptyBytes[0], 32 - (Fsep_file.Size mod 32));
+    Result := Fsep_file.Size;
+    Fsep_file.Seek(0, soFromEnd);
+    Fsep_file.CopyFrom(Src, Src.Size);
+    if (Fsep_file.Size mod 32) > 0 then
+      Fsep_file.Write(EmptyBytes[0], 32 - (Fsep_file.Size mod 32));
+    if UnloadWhenUnused then
+    begin
+      FSepOpened := False;
+      Fsep_file.Free;
+    end
+    else
+      FSepOpened := True;
+  end;
+end;
+
+end.
Index: oup/releases/0.34a/DataAccess/ConnectionManager.pas
===================================================================
--- oup/releases/0.34a/DataAccess/ConnectionManager.pas	(revision 200)
+++ oup/releases/0.34a/DataAccess/ConnectionManager.pas	(revision 200)
@@ -0,0 +1,283 @@
+unit ConnectionManager;
+interface
+
+uses TypeDefs, DataAccess, Access_OniArchive, Access_OUP_ADB;
+
+type
+  TConnections = array of TDataAccess;
+
+  TConnectionListChangedEvent = procedure of object;
+
+  
+  TConnectionManager = class
+  private
+    FConnections: TConnections;
+    FLastID:      Integer;
+    FConnectionListChanged: TConnectionListChangedEvent;
+    function GetConnectionCount: Integer;
+    function GetConnection(ConnectionID: Integer): TDataAccess;
+    function GetConnectionByIndex(Index: Integer): TDataAccess;
+    function GetConnectionIndex(ConnectionID: Integer): Integer;
+    procedure RemoveConnection(ArrayIndex: Integer);
+  protected
+  public
+    property Count: Integer read GetConnectionCount;
+    property Connection[ConnectionID: Integer]: TDataAccess read GetConnection;
+    property ConnectionByIndex[Index: Integer]: TDataAccess read GetConnectionByIndex;
+    property ConnectionIndexByID[ConnectionID: Integer]: Integer read GetConnectionIndex;
+    property OnCoonnectionListChanged: TConnectionListChangedEvent read FConnectionListChanged write FConnectionListChanged;
+
+    constructor Create;
+    function Close: Boolean;
+
+    function OpenConnection(FileName: String; var Msg: TStatusMessages): Integer;
+    function CloseConnectionByIndex(Index: Integer; var Msg: TStatusMessages): Boolean; overload;
+    function CloseConnection(ID: Integer; var Msg: TStatusMessages): Boolean; overload;
+    function CloseConnection(FileName: String; var Msg: TStatusMessages): Boolean; overload;
+    function FileOpened(FileName: String): Integer;
+  published
+  end;
+
+
+var
+  ConManager: TConnectionManager;
+
+
+implementation
+uses
+  SysUtils, Dialogs;
+
+(*
+ Implementation of TConnectionManager
+*)
+
+
+function TConnectionManager.GetConnectionCount: Integer;
+begin
+  Result := Length(FConnections);
+end;
+
+function TConnectionManager.GetConnectionIndex(ConnectionID: Integer): Integer;
+var
+  i: Integer;
+begin
+  Result := -1;
+  if Count > 0 then
+    for i := 0 to Count - 1 do
+      if ConnectionByIndex[i].ConnectionID = ConnectionID then
+      begin
+        Result := i;
+        Break;
+      end;
+end;
+
+function TConnectionManager.GetConnection(ConnectionID: Integer): TDataAccess;
+var
+  i: Integer;
+begin
+  Result := nil;
+  if Length(FConnections) > 0 then
+  begin
+    for i := 0 to High(FConnections) do
+    begin
+      if FConnections[i].ConnectionID = ConnectionID then
+      begin
+        Result := FConnections[i];
+        Break;
+      end;
+    end;
+    if i = Length(FConnections) then
+      ShowMessage('Couldn''t find specified ConnectionID (' +
+          IntToStr(ConnectionID) + '). Please contact developer!!!');
+  end;
+end;
+
+
+function TConnectionManager.GetConnectionByIndex(Index: Integer): TDataAccess;
+begin
+  Result := nil;
+  if index < Length(FConnections) then
+  begin
+    Result := FConnections[index];
+  end;
+end;
+
+constructor TConnectionManager.Create;
+begin
+  inherited;
+  FLastID := 0;
+end;
+
+function TConnectionManager.Close: Boolean;
+begin
+  Result := False;
+  if Length(FConnections) > 0 then
+    Exit;
+
+  inherited;
+end;
+
+
+
+function TConnectionManager.OpenConnection(FileName: String; var Msg: TStatusMessages): Integer;
+var
+  i: Integer;
+  ext: String;
+  backend: TDataBackend;
+  CreateMsg: TStatusMessages;
+begin
+  Msg := SM_UnknownError;
+  Result := -1;
+
+  if Length(FConnections) > 0 then
+  begin
+    for i := 0 to High(FConnections) do
+    begin
+      if FConnections[i].FileName = FileName then
+      begin
+        Result := FConnections[i].ConnectionID;
+        Msg := SM_AlreadyOpened;
+        Exit;
+      end;
+    end;
+  end;
+
+  if not FileExists(FileName) then
+  begin
+    Msg := SM_FileNotFound;
+    Exit;
+  end;
+
+  ext := UpperCase(ExtractFileExt(FileName));
+
+  if ext = '.OLDB' then
+    backend := DB_ADB
+  else if ext = '.DAT' then
+    backend := DB_ONI
+  else
+  begin
+    Msg := SM_UnknownExtension;
+    Exit;
+  end;
+
+  SetLength(FConnections, Length(FConnections) + 1);
+  i := High(FConnections);
+  case backend of
+    DB_ONI:
+      FConnections[i] := TAccess_OniArchive.Create(FileName, FLastID + 1, CreateMsg);
+    DB_ADB:
+      FConnections[i] := TAccess_OUP_ADB.Create(FileName, FLastID + 1, CreateMsg);
+  end;
+
+  if CreateMsg = SM_OK then
+  begin
+    FLastID := FConnections[i].ConnectionID;
+    Result := FLastID;
+    Msg := SM_OK;
+  end
+  else
+  begin
+    FConnections[i].Close;
+    FConnections[i].Free;
+    FConnections[i] := nil;
+    SetLength(FConnections, Length(FConnections) - 1);
+    Msg := CreateMsg;
+  end;
+end;
+
+
+procedure TConnectionManager.RemoveConnection(ArrayIndex: Integer);
+var
+  i: Integer;
+begin
+  if Length(FConnections) > 1 then
+  begin
+    for i := ArrayIndex to High(FConnections) - 1 do
+    begin
+      FConnections[i] := FConnections[i + 1];
+    end;
+  end;
+  SetLength(FConnections, Length(FConnections) - 1);
+end;
+
+function TConnectionManager.CloseConnectionByIndex(Index: Integer; var Msg: TStatusMessages): Boolean;
+begin
+  Msg := SM_UnknownError;
+  Result := False;
+
+  if Index < Length(FConnections) then
+  begin
+    FConnections[Index].Close;
+    RemoveConnection(Index);
+    Msg := SM_OK;
+    Result := True;
+  end;
+end;
+
+function TConnectionManager.CloseConnection(ID: Integer; var Msg: TStatusMessages): Boolean;
+var
+  i: Integer;
+begin
+  Msg := SM_UnknownError;
+  Result := False;
+
+  if Length(FConnections) > 0 then
+  begin
+    for i := 0 to High(FConnections) do
+    begin
+      if FConnections[i].ConnectionID = ID then
+      begin
+        FConnections[i].Close;
+        RemoveConnection(i);
+        Msg := SM_OK;
+        Result := True;
+        Exit;
+      end;
+    end;
+  end;
+end;
+
+function TConnectionManager.CloseConnection(FileName: String; var Msg: TStatusMessages): Boolean;
+var
+  i: Integer;
+begin
+  Msg := SM_UnknownError;
+  Result := False;
+
+  if Length(FConnections) > 0 then
+  begin
+    for i := 0 to High(FConnections) do
+    begin
+      if FConnections[i].FileName = FileName then
+      begin
+        FConnections[i].Close;
+        RemoveConnection(i);
+        Msg := SM_OK;
+        Result := True;
+        Exit;
+      end;
+    end;
+  end;
+end;
+
+
+function TConnectionManager.FileOpened(FileName: String): Integer;
+var
+  i: Integer;
+begin
+  Result := -1;
+  if Length(FConnections) > 0 then
+    for i := 0 to High(FConnections) do
+      if FConnections[i].FileName = FileName then
+      begin
+        Result := FConnections[i].ConnectionID;
+        Exit;
+      end;
+end;
+
+
+initialization
+  ConManager := TConnectionManager.Create;
+finalization
+  ConManager.Free;
+end.
Index: oup/releases/0.34a/DataAccess/DataAccess.pas
===================================================================
--- oup/releases/0.34a/DataAccess/DataAccess.pas	(revision 200)
+++ oup/releases/0.34a/DataAccess/DataAccess.pas	(revision 200)
@@ -0,0 +1,298 @@
+unit DataAccess;
+interface
+
+uses TypeDefs, Classes, StrUtils, SysUtils;
+
+type
+  TDataAccess = class
+  private
+  protected
+    FConnectionID:  Integer;
+    FFileName:      String;
+    FBackend:       TDataBackend;
+    FDataOS:        TDataOS;
+    FLevelNumber:   Integer;
+    FChangeRights:  TChangeRights;
+    procedure SetDataOS(DataOS: TDataOS);
+  public
+    property ConnectionID: Integer      read FConnectionID;
+    property FileName:     String       read FFileName;
+    property Backend:      TDataBackend read FBackend;
+    property DataOS:       TDataOS      read FDataOS write SetDataOS;
+    property LevelNumber:  Integer      read FLevelNumber;
+    property ChangeRights: TChangeRights read FChangeRights;
+
+    constructor Create(FileName: String; ConnectionID: Integer; var Msg: TStatusMessages); virtual; abstract;
+    procedure Close; virtual; abstract;
+
+    function ExtractFileIDOfName(Name: String): Integer; virtual;
+    function GetFileInfo(FileID: Integer): TFileInfo; virtual;
+    function GetFileInfoByName(Name: String): TFileInfo; virtual;
+    function GetFilesList(Ext: String; Pattern: String;
+      NoEmptyFiles: Boolean; SortType: TSortType): TStrings; virtual; abstract;
+    function GetFileCount: Integer; virtual; abstract;
+    function GetExtensionsList(ExtListFormat: TExtensionFormat): TStrings; virtual; abstract;
+
+    procedure LoadDatFile(FileID: Integer; var Target: TStream); overload; virtual; abstract;
+    procedure LoadDatFile(FileID: Integer; var Target: TByteData); overload;
+    procedure UpdateDatFile(FileID: Integer; Src: TStream); overload; virtual; abstract;
+    procedure UpdateDatFile(FileID: Integer; Src: TByteData); overload;
+    procedure LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TStream); overload; virtual; abstract;
+    procedure LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TByteData); overload;
+    procedure LoadDatFilePart(FileID, Offset, Size: Integer; Target: Pointer); overload;
+    procedure UpdateDatFilePart(FileID, Offset, Size: Integer; Src: TStream); overload; virtual; abstract;
+    procedure UpdateDatFilePart(FileID, Offset, Size: Integer; Src: Pointer); overload;
+
+    function GetDatLinks(FileID: Integer): TDatLinkList; virtual; abstract;
+    function GetDatLink(FileID, DatOffset: Integer): TDatLink; virtual; abstract;
+    function GetRawList(FileID: Integer): TRawDataList; virtual; abstract;
+    function GetRawInfo(FileID, DatOffset: Integer): TRawDataInfo; virtual; abstract;
+
+    procedure LoadRawFile(FileID, DatOffset: Integer; var Target: TStream); overload; virtual; abstract;
+    procedure LoadRawFile(FileID, DatOffset: Integer; var Target: TByteData); overload;
+    procedure UpdateRawFile(FileID, DatOffset: Integer; Src: TStream); overload; virtual; abstract;
+    procedure UpdateRawFile(FileID, DatOffset: Integer; Src: TByteData); overload;
+    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TStream); overload; virtual; abstract;
+    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TByteData); overload;
+    procedure LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; Target: Pointer); overload;
+    procedure UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: TStream); overload; virtual; abstract;
+    procedure UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: Pointer); overload;
+
+    function AppendRawFile(LocSep: Boolean; Src: TStream): Integer; overload; virtual;
+    function AppendRawFile(LocSep: Boolean; Src: TByteData): Integer; overload;
+//    function AppendRawFile(LocSep: Boolean; Size: Integer; Src: Pointer): Integer; overload;
+  published
+  end;
+
+
+
+implementation
+
+
+(*
+ Implementation of TDataAccess
+*)
+
+function TDataAccess.ExtractFileIDOfName(Name: String): Integer;
+begin
+  if Name[5] = '-' then
+    Result := StrToInt(MidStr(Name, 1, 4))
+  else
+    Result := StrToInt(MidStr(Name, 1, 5));
+end;
+
+
+function TDataAccess.GetFileInfo(FileID: Integer): TFileInfo;
+begin
+  Result.ID := -1;
+  Result.Name := '';
+  Result.Extension := '';
+  Result.Size := -1;
+  Result.FileType := 0;
+  Result.DatAddr := -1;
+end;
+
+
+function TDataAccess.GetFileInfoByName(Name: String): TFileInfo;
+var
+  i:     Integer;
+  files: TStrings;
+begin
+  Result := GetFileInfo(-1);
+  files  := GetFilesList('', Name, False, ST_IDAsc);
+  if files.Count = 0 then
+  else
+  begin
+    for i := 0 to files.Count - 1 do
+    begin
+      if MidStr(files.Strings[i], Pos('-', files.Strings[i]) + 1,
+            Length(files.Strings[i]) - Pos('-', files.Strings[i]) - 5) = name then
+      begin
+        Result := GetFileInfo(ExtractFileIDOfName(files.Strings[i]));
+        Break;
+      end;
+    end;
+  end;
+  files.Free;
+end;
+
+
+procedure TDataAccess.LoadDatFile(FileID: Integer; var Target: TByteData);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := nil;
+    LoadDatFile(FileID, data);
+    SetLength(Target, data.Size);
+    data.Read(Target[0], data.Size);
+    data.Free;
+  end;
+end;
+
+procedure TDataAccess.UpdateDatFile(FileID: Integer; Src: TByteData);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := TMemoryStream.Create;
+    data.Write(Src[0], Length(Src));
+    data.Seek(0, soFromBeginning);
+    UpdateDatFile(FileID, data);
+    data.Free;
+  end;
+end;
+
+procedure TDataAccess.LoadDatFilePart(FileID, Offset, Size: Integer; var Target: TByteData);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := nil;
+    LoadDatFilePart(FileID, offset, size, data);
+    SetLength(Target, data.Size);
+    data.Read(Target[0], data.Size);
+    data.Free;
+  end;
+end;
+
+procedure TDataAccess.LoadDatFilePart(FileID, Offset, Size: Integer; Target: Pointer);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := nil;
+    LoadDatFilePart(FileID, offset, size, data);
+    data.Read(Target^, data.Size);
+    data.Free;
+  end;
+end;
+
+procedure TDataAccess.UpdateDatFilePart(FileID, Offset, Size: Integer; Src: Pointer);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := TMemoryStream.Create;
+    data.Write(Src^, Size);
+    data.Seek(0, soFromBeginning);
+    UpdateDatFilePart(FileID, offset, size, data);
+    data.Free;
+  end;
+end;
+
+
+
+procedure TDataAccess.LoadRawFile(FileID, DatOffset: Integer; var Target: TByteData);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := nil;
+    LoadRawFile(FileID, DatOffset, data);
+    SetLength(Target, data.Size);
+    data.Read(Target[0], data.Size);
+    data.Free;
+  end;
+end;
+
+procedure TDataAccess.UpdateRawFile(FileID, DatOffset: Integer; Src: TByteData);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := TMemoryStream.Create;
+    data.Write(Src[0], Length(Src));
+    data.Seek(0, soFromBeginning);
+    UpdateRawFile(FileID, DatOffset, data);
+    data.Free;
+  end;
+end;
+
+procedure TDataAccess.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; var Target: TByteData);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := nil;
+    SetLength(Target, Size);
+    LoadRawFile(FileID, DatOffset, Data);
+    Data.Seek(Offset, soFromBeginning);
+    Data.Read(Target[0], Size);
+    Data.Free;
+  end;
+end;
+
+procedure TDataAccess.LoadRawFilePart(FileID, DatOffset, Offset, Size: Integer; Target: Pointer);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := nil;
+    LoadRawFile(FileID, DatOffset, Data);
+    Data.Seek(Offset, soFromBeginning);
+    Data.Read(Target^, Size);
+    Data.Free;
+  end;
+end;
+
+procedure TDataAccess.UpdateRawFilePart(FileID, DatOffset, Offset, Size: Integer; Src: Pointer);
+var
+  data: TStream;
+begin
+  if fileid < GetFileCount then
+  begin
+    data := TMemoryStream.Create;
+    data.Write(Src^, Size);
+    data.Seek(0, soFromBeginning);
+    UpdateRawFilePart(FileID, DatOffset, Offset, Size, data);
+    data.Free;
+  end;
+end;
+
+
+function TDataAccess.AppendRawFile(LocSep: Boolean; Src: TStream): Integer;
+begin
+  raise ENotImplemented.Create('ERROR: AppendRawFile not implemented here!!!');
+end;
+
+
+function TDataAccess.AppendRawFile(LocSep: Boolean; Src: TByteData): Integer;
+var
+  data: TStream;
+begin
+  data := TMemoryStream.Create;
+  data.Write(Src[0], Length(Src));
+  data.Seek(0, soFromBeginning);
+  Result := AppendRawFile(LocSep, data);
+  data.Free;
+end;
+{
+function TDataAccess.AppendRawFile(LocSep: Boolean; Size: Integer; Src: Pointer): Integer;
+var
+  data: TStream;
+begin
+  data := TMemoryStream.Create;
+  data.Write(Src^, Size);
+  data.Seek(0, soFromBeginning);
+  Result := AppendRawFile(LocSep, data);
+  data.Free;
+end;
+}
+
+
+procedure TDataAccess.SetDataOS(DataOS: TDataOS);
+begin
+  raise ENotImplemented.Create('TDataAccess.SetDataOS: TBD!');
+end;
+
+end.
Index: oup/releases/0.34a/FileClasses/_DataTypes.pas
===================================================================
--- oup/releases/0.34a/FileClasses/_DataTypes.pas	(revision 200)
+++ oup/releases/0.34a/FileClasses/_DataTypes.pas	(revision 200)
@@ -0,0 +1,136 @@
+unit _DataTypes;
+
+interface
+
+type
+  TDataField = class
+    private
+      FOffset: Integer;
+      FName:   String;
+      FDescription: String;
+      FDataLength: Integer;
+      function GetValueAsString: String; virtual; abstract;
+    public
+      constructor Create(Offset: Integer; Name, Description: String);
+
+      property Offset: Integer read FOffset;
+      property Name: String read FName;
+      property Description: String read FDescription;
+      property DataLength: Integer read FDataLength;
+      property ValueAsString: String read GetValueAsString;
+  end;
+
+  TDataFields = array of TDataField;
+
+
+  TInt32 = class(TDataField)
+    private
+      FInt: LongWord;
+      function GetValueAsString: String; override;
+    public
+      constructor Create(Offset: Integer; Name, Description: String);
+  end;
+
+
+  TString = class(TDataField)
+    private
+      FString: String;
+      function GetValueAsString: String; override;
+    public
+      constructor Create(Offset: Integer; Name, Description: String; Length: Integer);
+  end;
+
+
+  
+  TArray = class(TDataField)
+    private
+      FDataFields: TDataFields;
+      function GetFieldByOffset(Offset: Integer): TDataField;
+      function GetFieldByIndex(ID: Integer): TDataField;
+    public
+      constructor Create(Offset: Integer; Name, Description: String; Length, Count: Integer);
+      property FieldByOffset[Offset: Integer]: TDataField read GetFieldByOffset;
+      property FieldByIndex[ID: Integer]: TDataField read GetFieldByIndex;
+  end;
+
+implementation
+
+uses
+  SysUtils;
+
+
+{ TDataType }
+
+constructor TDataField.Create(Offset: Integer; Name, Description: String);
+begin
+  FOffset := Offset;
+  FName := Name;
+  FDescription := Description; 
+end;
+
+
+
+{ TInt32 }
+
+constructor TInt32.Create(Offset: Integer; Name, Description: String);
+begin
+  inherited Create(Offset, Name, Description);
+end;
+
+function TInt32.GetValueAsString: String;
+begin
+  Result := IntToStr(FInt);
+end;
+
+
+
+{ TString }
+
+constructor TString.Create(Offset: Integer; Name, Description: String;
+  Length: Integer);
+begin
+  inherited Create(Offset, Name, Description);
+
+end;
+
+function TString.GetValueAsString: String;
+begin
+  Result := FString;
+end;
+
+
+
+{ TArray }
+
+constructor TArray.Create(Offset: Integer; Name, Description: String;
+  Length, Count: Integer);
+begin
+  Exit;
+end;
+
+function TArray.GetFieldByIndex(ID: Integer): TDataField;
+begin
+  if ID < Length(FDataFields) then
+    Result := FDataFields[ID]
+  else
+    Result := nil;
+end;
+
+function TArray.GetFieldByOffset(Offset: Integer): TDataField;
+var
+  i: Integer;
+begin
+  Result := nil;
+
+  if Length(FDataFields) > 0 then
+  begin
+    for i := 0 to High(FDataFields) do
+      if FDataFields[i].Offset = Offset then
+        break;
+    if i < Length(FDataFields) then
+      Result := FDataFields[i];
+  end;
+end;
+
+
+end.
Index: oup/releases/0.34a/FileClasses/_FileTypes.pas
===================================================================
--- oup/releases/0.34a/FileClasses/_FileTypes.pas	(revision 200)
+++ oup/releases/0.34a/FileClasses/_FileTypes.pas	(revision 200)
@@ -0,0 +1,149 @@
+unit _FileTypes;
+
+interface
+
+uses
+  TypeDefs, _DataTypes;
+
+
+type
+  TFile = class
+    private
+      FConnectionID: Integer;
+      FFileID: Integer;
+
+      FDatLinks: TDatLinkList;
+      FDataFields: TDataFields;
+      FRawParts: TRawDataList;
+
+      function GetDatLinkByOffset(Offset: Integer): TDatLink;
+      function GetDatLinkByIndex(ID: Integer): TDatLink;
+      function GetFieldByOffset(Offset: Integer): TDataField;
+      function GetFieldByIndex(ID: Integer): TDataField;
+      function GetRawPartByOffset(Offset: Integer): TRawDataInfo;
+      function GetRawPartByIndex(ID: Integer): TRawDataInfo;
+    public
+      constructor Create(ConnectionID, FileID: Integer);
+      
+      property LinkByOffset[Offset: Integer]: TDatLink read GetDatLinkByOffset;
+      property LinkByIndex[ID: Integer]: TDatLink read GetDatLinkByIndex;
+
+      property FieldByOffset[Offset: Integer]: TDataField read GetFieldByOffset;
+      property FieldByIndex[ID: Integer]: TDataField read GetFieldByIndex;
+
+      property RawPartByOffset[Offset: Integer]: TRawDataInfo read GetRawPartByOffset;
+      property RawPartByIndex[ID: Integer]: TRawDataInfo read GetRawPartByIndex;
+  end;
+
+
+implementation
+
+uses
+  DatLinks, RawList;
+
+{ TFileType }
+
+constructor TFile.Create(ConnectionID, FileID: Integer);
+begin
+  FConnectionID := ConnectionID;
+  FFileID := FileID;
+
+  FDatLinks := DatLinksManager.GetDatLinks(ConnectionID, FileID);
+  FRawParts := RawLists.GetRawList(ConnectionID, FileID);
+end;
+
+
+function TFile.GetDatLinkByIndex(ID: Integer): TDatLink;
+begin
+  if ID < Length(FDatLinks) then
+    Result := FDatLinks[ID]
+  else
+    with Result do
+    begin
+      SrcOffset := -1;
+      DestID := -1;
+      PosDestExts := '';
+    end;
+end;
+
+function TFile.GetDatLinkByOffset(Offset: Integer): TDatLink;
+var
+  i: Integer;
+begin
+  Result.SrcOffset := -1;
+  Result.DestID := -1;
+  Result.PosDestExts := '';
+  
+  if Length(FDatLinks) > 0 then
+  begin
+    for i := 0 to High(FDatLinks) do
+      if FDatLinks[i].SrcOffset = Offset then
+        break;
+    if i < Length(FDatLinks) then
+      Result := FDatLinks[i];
+  end;
+end;
+
+
+function TFile.GetFieldByIndex(ID: Integer): TDataField;
+begin
+  if ID < Length(FDataFields) then
+    Result := FDataFields[ID]
+  else
+    Result := nil;
+end;
+
+function TFile.GetFieldByOffset(Offset: Integer): TDataField;
+var
+  i: Integer;
+begin
+  Result := nil;
+
+  if Length(FDataFields) > 0 then
+  begin
+    for i := 0 to High(FDataFields) do
+      if FDataFields[i].Offset = Offset then
+        break;
+    if i < Length(FDataFields) then
+      Result := FDataFields[i];
+  end;
+end;
+
+
+function TFile.GetRawPartByIndex(ID: Integer): TRawDataInfo;
+begin
+  if ID < Length(FRawParts) then
+    Result := FRawParts[ID]
+  else
+    with Result do
+    begin
+      SrcID := -1;
+      SrcOffset := -1;
+      RawAddr := -1;
+      RawSize := -1;
+    end;
+end;
+
+function TFile.GetRawPartByOffset(Offset: Integer): TRawDataInfo;
+var
+  i: Integer;
+begin
+  with Result do
+  begin
+    SrcID := -1;
+    SrcOffset := -1;
+    RawAddr := -1;
+    RawSize := -1;
+  end;
+
+  if Length(FRawParts) > 0 then
+  begin
+    for i := 0 to High(FRawParts) do
+      if FRawParts[i].SrcOffset = Offset then
+        break;
+    if i < Length(FRawParts) then
+      Result := FRawParts[i];
+  end;
+end;
+
+end.
Index: oup/releases/0.34a/Global/DatLinks.pas
===================================================================
--- oup/releases/0.34a/Global/DatLinks.pas	(revision 200)
+++ oup/releases/0.34a/Global/DatLinks.pas	(revision 200)
@@ -0,0 +1,1313 @@
+unit DatLinks;
+interface
+uses TypeDefs, DataAccess;
+
+type
+  THandler = function(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+  TDatLinkHandler = record
+    Ext:     String[4];
+    Handler: THandler;
+  end;
+  TDatLinkHandlers = array of TDatLinkHandler;
+
+  TDatLinks = class
+    private
+      FDatLinkHandlers: TDatLinkHandlers;
+    public
+      property RawListHandlers: TDatLinkHandlers read FDatLinkHandlers;
+      procedure InsertDatLinkHandler(ext: String; handler: THandler);
+      function GetDatLinks(ConnectionID, FileID: Integer): TDatLinkList;
+      function GetDatLink(ConnectionID, FileID, DatOffset: Integer): TDatLink;
+  end;
+
+
+var
+  DatLinksManager: TDatLinks;
+
+
+implementation
+uses
+  ConnectionManager, Classes, SysUtils;
+
+
+
+function AISA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages * 2);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i*2 + 0].SrcOffset := $20 + i * 352 + $28;
+      Result[i*2 + 0].DestID := -1;
+      Result[i*2 + 0].PosDestExts := 'ONCC';
+
+      Result[i*2 + 1].SrcOffset := $20 + i * 352 + $150;
+      Result[i*2 + 1].DestID := -1;
+      Result[i*2 + 1].PosDestExts := 'ONWC';
+    end;
+  end;
+end;
+
+
+function AKEV(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..16] of String[4] =
+      ('PNTA', 'PLEA', 'TXCA', 'AGQG', 'AGQR', 'AGQC', 'AGDB', 'TXMA', 'AKVA',
+      'AKBA', 'IDXA', 'IDXA', 'AKBP', 'ABNA', 'AKOT', 'AKAA', 'AKDA');
+var
+  i: Integer;
+begin
+  SetLength(Result, 17);
+  for i := 0 to 16 do
+  begin
+    Result[i].SrcOffset := $8 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function AKOT(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..4] of String[4] =
+      ('OTIT', 'OTLF', 'QTNA', 'IDXA', 'IDXA');
+var
+  i: Integer;
+begin
+  SetLength(Result, 5);
+  for i := 0 to 4 do
+  begin
+    Result[i].SrcOffset := $8 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function CBPI(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 57);
+  for i := 0 to 56 do
+  begin
+    Result[i].SrcOffset := $8 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'Impt';
+  end;
+end;
+
+
+function CBPM(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 19);
+  for i := 0 to 18 do
+  begin
+    Result[i].SrcOffset := $8 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'Mtrl';
+  end;
+end;
+
+
+function CONS(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..1] of String[4] =
+      ('OFGA', 'M3GM');
+var
+  i: Integer;
+begin
+  SetLength(Result, 2);
+  for i := 0 to 1 do
+  begin
+    Result[i].SrcOffset := $24 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function CRSA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*1100 + $A0;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'ONCC';
+    end;
+  end;
+end;
+
+
+function DOOR(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..2] of String[4] =
+      ('OFGA', 'OFGA', 'OBAN');
+var
+  i: Integer;
+begin
+  SetLength(Result, 3);
+  for i := 0 to 2 do
+  begin
+    Result[i].SrcOffset := $8 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function DPge(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..0] of String[4] =
+      ('IGPG');
+var
+  i: Integer;
+begin
+  SetLength(Result, 1);
+  for i := 0 to 0 do
+  begin
+    Result[i].SrcOffset := $40 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function FILM(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..1] of String[4] =
+      ('TRAM', 'TRAM');
+var
+  i: Integer;
+begin
+  SetLength(Result, 2);
+  for i := 0 to 1 do
+  begin
+    Result[i].SrcOffset := $28 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function FXLR(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..1] of String[4] =
+      ('TXMP', 'M3GM');
+var
+  i: Integer;
+begin
+  SetLength(Result, 2);
+  for i := 0 to 1 do
+  begin
+    Result[i].SrcOffset := $0C + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function GMAN(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'M3GM';
+    end;
+  end;
+end;
+
+
+function HPge(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..0] of String[4] =
+      ('IGPG');
+var
+  i: Integer;
+begin
+  SetLength(Result, 1);
+  for i := 0 to 0 do
+  begin
+    Result[i].SrcOffset := $0C + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function IGHH(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..1] of String[4] =
+      ('TXMP', 'TXMP');
+var
+  i: Integer;
+begin
+  SetLength(Result, 2);
+  for i := 0 to 1 do
+  begin
+    Result[i].SrcOffset := $24 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function IGPA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'IGPG';
+    end;
+  end;
+end;
+
+
+function IGPG(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..3] of String[4] =
+      ('TSFF', '*', 'IGSA', 'IGSA');
+var
+  i: Integer;
+begin
+  SetLength(Result, 4);
+  Result[0].SrcOffset := $8;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := types[0];
+
+  for i := 1 to 3 do
+  begin
+    Result[i].SrcOffset := $14 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function IGSA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'IGSt';
+    end;
+  end;
+end;
+
+
+function IGSt(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..0] of String[4] =
+      ('TSFF');
+var
+  i: Integer;
+begin
+  SetLength(Result, 1);
+  for i := 0 to 0 do
+  begin
+    Result[i].SrcOffset := $8 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function Impt(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..0] of String[4] =
+      ('*');
+var
+  i: Integer;
+begin
+  SetLength(Result, 1);
+  for i := 0 to 0 do
+  begin
+    Result[i].SrcOffset := $10 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function IPge(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..0] of String[4] =
+      ('IGPG');
+var
+  i: Integer;
+begin
+  SetLength(Result, 1);
+  for i := 0 to 0 do
+  begin
+    Result[i].SrcOffset := $0C + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function KeyI(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 10);
+  for i := 0 to 9 do
+  begin
+    Result[i].SrcOffset := $08 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'TXMP';
+  end;
+end;
+
+
+function M3GA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'M3GM';
+    end;
+  end;
+end;
+
+
+function M3GM(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..7] of String[4] =
+      ('PNTA', 'VCRA', 'VCRA', 'TXCA', 'IDXA', 'IDXA', 'TXMP', '*');
+var
+  i: Integer;
+begin
+  SetLength(Result, 8);
+  for i := 0 to 7 do
+  begin
+    Result[i].SrcOffset := $0C + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function Mtrl(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..0] of String[4] =
+      ('*');
+var
+  i: Integer;
+begin
+  SetLength(Result, 1);
+  for i := 0 to 0 do
+  begin
+    Result[i].SrcOffset := $10 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function OBDC(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*$18 + 4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'OBAN';
+    end;
+  end;
+end;
+
+
+function OBOA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages * 3);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i*3 + 0].SrcOffset := $20 + i*240 + 0;
+      Result[i*3 + 0].DestID := -1;
+      Result[i*3 + 0].PosDestExts := 'M3GA';
+
+      Result[i*3 + 0].SrcOffset := $20 + i*240 + 4;
+      Result[i*3 + 0].DestID := -1;
+      Result[i*3 + 1].PosDestExts := 'OBAN';
+
+      Result[i*3 + 0].SrcOffset := $20 + i*240 + 8;
+      Result[i*3 + 0].DestID := -1;
+      Result[i*3 + 2].PosDestExts := 'ENVP';
+    end;
+  end;
+end;
+
+
+function OFGA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages * 2 + 1);
+
+  Result[0].SrcOffset := $18;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'ENVP';
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[1 + i*2 + 0].SrcOffset := $20 + i*12 + 4;
+      Result[1 + i*2 + 0].DestID := -1;
+      Result[1 + i*2 + 0].PosDestExts := 'M3GM';
+
+      Result[1 + i*2 + 1].SrcOffset := $20 + i*12 + 8;
+      Result[1 + i*2 + 1].DestID := -1;
+      Result[1 + i*2 + 1].PosDestExts := 'OBLS';
+    end;
+  end;
+end;
+
+
+function ONCC(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 10);
+  i := 0;
+  Result[i].SrcOffset := $28;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $434;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'ONCV';
+  Inc(i);
+  Result[i].SrcOffset := $438;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'ONCP';
+  Inc(i);
+  Result[i].SrcOffset := $43C;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'ONIA';
+  Inc(i);
+  Result[i].SrcOffset := $C3C;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TRBS';
+  Inc(i);
+  Result[i].SrcOffset := $C40;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TRMA';
+  Inc(i);
+  Result[i].SrcOffset := $C44;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'CBPM';
+  Inc(i);
+  Result[i].SrcOffset := $C48;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'CBPI';
+  Inc(i);
+  Result[i].SrcOffset := $C88;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TRAC';
+  Inc(i);
+  Result[i].SrcOffset := $C8C;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TRSC';
+end;
+
+
+function ONCV(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $8;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := '*';
+end;
+
+
+function ONLV(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..12] of String[4] =
+      ('AKEV', 'OBOA', 'ONMA', 'ONFA', 'ONTA', 'ONSK', 'AISA', 'AITR',
+       'ONSA', 'OBDC', 'ONOA', 'ENVP', 'CRSA');
+var
+  i: Integer;
+begin
+  SetLength(Result, 13);
+  for i := 0 to 5 do
+  begin
+    Result[i].SrcOffset := $48 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+  for i := 0 to 5 do
+  begin
+    Result[i+6].SrcOffset := $64 + i*4;
+    Result[i+6].DestID := -1;
+    Result[i+6].PosDestExts := types[i+6];
+  end;
+  Result[12].SrcOffset := $300;
+  Result[12].DestID := -1;
+  Result[12].PosDestExts := types[12];
+end;
+
+
+function ONOA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*8 + 4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'IDXA';
+    end;
+  end;
+end;
+
+
+function ONSK(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 20);
+  for i := 0 to 19 do
+  begin
+    Result[i].SrcOffset := $08 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'TXMP';
+  end;
+end;
+
+
+function ONVL(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'ONCV';
+    end;
+  end;
+end;
+
+
+function ONWC(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 9);
+  i := 0;
+  Result[i].SrcOffset := $28;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $34;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $40;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $54;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $58;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $5C;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $60;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'M3GM';
+  Inc(i);
+  Result[i].SrcOffset := $6FC;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+  Inc(i);
+  Result[i].SrcOffset := $700;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'TXMP';
+end;
+
+
+function OPge(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $0C;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'IGPA';
+end;
+
+
+function PSpc(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $50;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := '*';
+end;
+
+
+function PSpL(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*8 + 4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := '*';
+    end;
+  end;
+end;
+
+
+function PSUI(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 44);
+  for i := 0 to 43 do
+  begin
+    Result[i].SrcOffset := $08 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'PSpc';
+  end;
+end;
+
+
+function StNA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TStr';
+    end;
+  end;
+end;
+
+
+function TMRA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := '*';
+    end;
+  end;
+end;
+
+
+function TRAC(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages + 1);
+  Result[0].SrcOffset := $18;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'TRAC';
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i+1].SrcOffset := $20 + i*12 + 8;
+      Result[i+1].DestID := -1;
+      Result[i+1].PosDestExts := 'TRAM';
+    end;
+  end;
+end;
+
+
+function TRAM(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 2);
+  for i := 0 to 1 do
+  begin
+    Result[i].SrcOffset := $40 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'TRAM';
+  end;
+end;
+
+
+function TRAS(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $08;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'TRAM';
+end;
+
+
+function TRBS(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 5);
+  for i := 0 to 4 do
+  begin
+    Result[i].SrcOffset := $08 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'TRCM';
+  end;
+end;
+
+
+function TRCM(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..2] of String[4] =
+      ('TRGA', 'TRTA', 'TRIA');
+var
+  i: Integer;
+begin
+  SetLength(Result, 3);
+  for i := 0 to 2 do
+  begin
+    Result[i].SrcOffset := $5C + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+end;
+
+
+function TRGA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'M3GM';
+    end;
+  end;
+end;
+
+
+function TRGE(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $20;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'M3GM';
+end;
+
+
+function TRIG(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+const
+  types: array[0..3] of String[4] =
+      ('M3GM', 'OBLS', 'TRGE', 'OBAN');
+var
+  i: Integer;
+begin
+  SetLength(Result, 4);
+  for i := 0 to 1 do
+  begin
+    Result[i].SrcOffset := $18 + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := types[i];
+  end;
+  for i := 0 to 1 do
+  begin
+    Result[i+2].SrcOffset := $24 + i*4;
+    Result[i+2].DestID := -1;
+    Result[i+2].PosDestExts := types[i+2];
+  end;
+end;
+
+
+function TRMA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TXMP';
+    end;
+  end;
+end;
+
+
+function TRSC(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1E, 2, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TRAS';
+    end;
+  end;
+end;
+
+
+function TSFF(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages + 1);
+
+  Result[0].SrcOffset := $18;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'TSFL';
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i+1].SrcOffset := $20 + i*4;
+      Result[i+1].DestID := -1;
+      Result[i+1].PosDestExts := 'TSFT';
+    end;
+  end;
+end;
+
+
+function TSFT(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 256);
+  for i := 0 to 255 do
+  begin
+    Result[i].SrcOffset := $1C + i*4;
+    Result[i].DestID := -1;
+    Result[i].PosDestExts := 'TSGA';
+  end;
+end;
+
+
+function TURR(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+begin
+  SetLength(Result, 4);
+  i := 0;
+  Result[i].SrcOffset := $60;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'M3GM';
+  Inc(i);
+  Result[i].SrcOffset := $64;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'OBLS';
+  Inc(i);
+  Result[i].SrcOffset := $6C;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'M3GM';
+  Inc(i);
+  Result[i].SrcOffset := $74;
+  Result[i].DestID := -1;
+  Result[i].PosDestExts := 'M3GM';
+end;
+
+
+function TXAN(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TXMP';
+    end;
+  end;
+end;
+
+
+function TXMA(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TXMP';
+    end;
+  end;
+end;
+
+
+function TXMB(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TXMP';
+    end;
+  end;
+end;
+
+
+function TXMP(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 2);
+  Result[0].SrcOffset := $94;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := '*';
+  Result[1].SrcOffset := $98;
+  Result[1].DestID := -1;
+  Result[1].PosDestExts := 'TXMP';
+end;
+
+
+function TxtC(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $08;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'IGPA';
+end;
+
+
+function WMCL(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*8 + 4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := '*';
+    end;
+  end;
+end;
+
+
+function WMDD(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $11C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $120 + i*292 + $114;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'TSFF';
+    end;
+  end;
+end;
+
+
+function WMMB(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+var
+  packages: Integer;
+  i: Integer;
+begin
+  packages := 0;
+  Connection.LoadDatFilePart(fileid, $1C, 4, @packages);
+  SetLength(Result, packages);
+  if packages > 0 then
+  begin
+    for i := 0 to packages - 1 do
+    begin
+      Result[i].SrcOffset := $20 + i*4;
+      Result[i].DestID := -1;
+      Result[i].PosDestExts := 'WMM_';
+    end;
+  end;
+end;
+
+
+function WPge(Connection: TDataAccess; FileID: Integer): TDatLinkList;
+begin
+  SetLength(Result, 2);
+  Result[0].SrcOffset := $08;
+  Result[0].DestID := -1;
+  Result[0].PosDestExts := 'ONWC';
+  Result[1].SrcOffset := $0C;
+  Result[1].DestID := -1;
+  Result[1].PosDestExts := 'IGPG';
+end;
+
+
+
+
+
+
+
+function TDatLinks.GetDatLink(ConnectionID, FileID, DatOffset: Integer): TDatLink;
+var
+  i: Integer;
+  DatLinks: TDatLinkList;
+begin
+  DatLinks           := GetDatLinks(ConnectionID, FileID);
+  Result.SrcOffset   := -1;
+  Result.DestID      := -1;
+  Result.PosDestExts := '';
+  if Length(DatLinks) > 0 then
+  begin
+    for i := 0 to High(DatLinks) do
+    begin
+      if DatLinks[i].SrcOffset = DatOffset then
+      begin
+        Result.SrcOffset := DatOffset;
+        Result.DestID := DatLinks[i].DestID;
+        Result.PosDestExts := DatLinks[i].PosDestExts;
+        Break;
+      end;
+    end;
+  end;
+end;
+
+
+function TDatLinks.GetDatLinks(ConnectionID, FileID: Integer): TDatLinkList;
+var
+  i: Integer;
+  fileinfo: TFileInfo;
+begin
+  SetLength(Result, 0);
+  fileinfo := ConManager.Connection[ConnectionID].GetFileInfo(FileID);
+  for i := 0 to High(FDatLinkHandlers) do
+    if UpperCase(FDatLinkHandlers[i].Ext) = UpperCase(fileinfo.extension) then
+    begin
+      Result := FDatLinkHandlers[i].Handler(ConManager.Connection[ConnectionID], FileID);
+      Break;
+    end;
+end;
+
+procedure TDatLinks.InsertDatLinkHandler(ext: String; handler: THandler);
+begin
+  SetLength(FDatLinkHandlers, Length(FDatLinkHandlers) + 1);
+  FDatLinkHandlers[High(FDatLinkHandlers)].Ext := ext;
+  FDatLinkHandlers[High(FDatLinkHandlers)].handler := handler;
+end;
+
+
+
+
+initialization
+  DatLinksManager := TDatLinks.Create;
+  DatLinksManager.InsertDatLinkHandler('AISA', AISA);
+  DatLinksManager.InsertDatLinkHandler('AKEV', AKEV);
+  DatLinksManager.InsertDatLinkHandler('AKOT', AKOT);
+  DatLinksManager.InsertDatLinkHandler('CBPI', CBPI);
+  DatLinksManager.InsertDatLinkHandler('CBPM', CBPM);
+  DatLinksManager.InsertDatLinkHandler('CONS', CONS);
+  DatLinksManager.InsertDatLinkHandler('CRSA', CRSA);
+  DatLinksManager.InsertDatLinkHandler('DOOR', DOOR);
+  DatLinksManager.InsertDatLinkHandler('DPge', DPge);
+  DatLinksManager.InsertDatLinkHandler('FILM', FILM);
+  DatLinksManager.InsertDatLinkHandler('FXLR', FXLR);
+  DatLinksManager.InsertDatLinkHandler('GMAN', GMAN);
+  DatLinksManager.InsertDatLinkHandler('HPge', HPge);
+  DatLinksManager.InsertDatLinkHandler('IGHH', IGHH);
+  DatLinksManager.InsertDatLinkHandler('IGPA', IGPA);
+  DatLinksManager.InsertDatLinkHandler('IGPG', IGPG);
+  DatLinksManager.InsertDatLinkHandler('IGSA', IGSA);
+  DatLinksManager.InsertDatLinkHandler('IGSt', IGSt);
+  DatLinksManager.InsertDatLinkHandler('Impt', Impt);
+  DatLinksManager.InsertDatLinkHandler('IPge', IPge);
+  DatLinksManager.InsertDatLinkHandler('KeyI', KeyI);
+  DatLinksManager.InsertDatLinkHandler('M3GA', M3GA);
+  DatLinksManager.InsertDatLinkHandler('M3GM', M3GM);
+  DatLinksManager.InsertDatLinkHandler('Mtrl', Mtrl);
+  DatLinksManager.InsertDatLinkHandler('OBDC', OBDC);
+  DatLinksManager.InsertDatLinkHandler('OBOA', OBOA);
+  DatLinksManager.InsertDatLinkHandler('OFGA', OFGA);
+  DatLinksManager.InsertDatLinkHandler('ONCC', ONCC);
+  DatLinksManager.InsertDatLinkHandler('ONCV', ONCV);
+  DatLinksManager.InsertDatLinkHandler('ONLV', ONLV);
+  DatLinksManager.InsertDatLinkHandler('ONOA', ONOA);
+  DatLinksManager.InsertDatLinkHandler('ONSK', ONSK);
+  DatLinksManager.InsertDatLinkHandler('ONVL', ONVL);
+  DatLinksManager.InsertDatLinkHandler('ONWC', ONWC);
+  DatLinksManager.InsertDatLinkHandler('OPge', OPge);
+  DatLinksManager.InsertDatLinkHandler('PSpc', PSpc);
+  DatLinksManager.InsertDatLinkHandler('PSpL', PSpL);
+  DatLinksManager.InsertDatLinkHandler('PSUI', PSUI);
+  DatLinksManager.InsertDatLinkHandler('StNA', StNA);
+  DatLinksManager.InsertDatLinkHandler('TMRA', TMRA);
+  DatLinksManager.InsertDatLinkHandler('TRAC', TRAC);
+  DatLinksManager.InsertDatLinkHandler('TRAM', TRAM);
+  DatLinksManager.InsertDatLinkHandler('TRAS', TRAS);
+  DatLinksManager.InsertDatLinkHandler('TRBS', TRBS);
+  DatLinksManager.InsertDatLinkHandler('TRCM', TRCM);
+  DatLinksManager.InsertDatLinkHandler('TRGA', TRGA);
+  DatLinksManager.InsertDatLinkHandler('TRGE', TRGE);
+  DatLinksManager.InsertDatLinkHandler('TRIG', TRIG);
+  DatLinksManager.InsertDatLinkHandler('TRMA', TRMA);
+  DatLinksManager.InsertDatLinkHandler('TRSC', TRSC);
+  DatLinksManager.InsertDatLinkHandler('TSFF', TSFF);
+  DatLinksManager.InsertDatLinkHandler('TSFT', TSFT);
+  DatLinksManager.InsertDatLinkHandler('TURR', TURR);
+  DatLinksManager.InsertDatLinkHandler('TXAN', TXAN);
+  DatLinksManager.InsertDatLinkHandler('TXMA', TXMA);
+  DatLinksManager.InsertDatLinkHandler('TXMB', TXMB);
+  DatLinksManager.InsertDatLinkHandler('TXMP', TXMP);
+  DatLinksManager.InsertDatLinkHandler('TxtC', TxtC);
+  DatLinksManager.InsertDatLinkHandler('WMCL', WMCL);
+  DatLinksManager.InsertDatLinkHandler('WMDD', WMDD);
+  DatLinksManager.InsertDatLinkHandler('WMMB', WMMB);
+  DatLinksManager.InsertDatLinkHandler('WPge', WPge);
+end.
Index: oup/releases/0.34a/Global/DatStructureLoader.pas
===================================================================
--- oup/releases/0.34a/Global/DatStructureLoader.pas	(revision 200)
+++ oup/releases/0.34a/Global/DatStructureLoader.pas	(revision 200)
@@ -0,0 +1,279 @@
+unit DatStructureLoader;
+
+interface
+
+type
+  TStructureEntry = record
+    Name:     String;
+    offset:   Integer;
+    datatype: Word;
+      // 1..4  : Integer[1..4] dec
+      // 5..8  : Integer[1..4] hex
+      // 9     : float
+      // 10    : bitset
+      // 11    : raw-addr
+      // 12    : untyped-dat-file-ID-link
+      // 13..16: Signed Integer[1..4]
+      // 17    : level-ID
+      // 100..300: dat-file-name[0..200]
+      // 501..614: typed-dat-file-ID-link
+      // 1000..9999: Unused data[0-8999]
+      // 10000+: string[0+]
+    description: String;
+  end;
+
+  TStructDefSub = record
+    SubName: String;
+    SubDesc: String;
+    Entries: array of TStructureEntry;
+  end;
+
+  TStructDef = record
+    Data:   Boolean;
+    Global: array of TStructureEntry;
+    Subs:   array of TStructDefSub;
+  end;
+
+
+function LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef;
+function GetDataType(TypeID: Word): String;
+function GetDataTypeLength(DataType: Word): Word;
+
+implementation
+
+uses
+  SysUtils, Classes, Functions, ConnectionManager, TypeDefs, Forms, StrUtils, Data;
+
+type
+  TStringArray = array of String;
+
+function GetDataTypeLength(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;
+    500..614:
+      Result := 4;
+    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 Explode(_string: String; delimiter: Char): TStringArray;
+var
+  start, len: Word;
+begin
+  SetLength(Result, 0);
+  start := 1;
+  while PosEx(delimiter, _string, start) > 0 do
+  begin
+    SetLength(Result, Length(Result) + 1);
+    len := PosEx(delimiter, _string, start) - start;
+    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 LoadStructureDefinition(ConnectionID, FileID: Integer): TStructDef;
+var
+  current_type: Byte; //0: Global, 1: Undynamic, 2: Dynamic
+  current_base, current_package, current_package_size: Integer;
+  packages: Integer;
+  deffile: Text;
+  structentry: TStructureEntry;
+  fields: TStringArray;
+  filename: String;
+  ext:    String[4];
+  temps:  String;
+  Data:   TByteData;
+begin
+  SetLength(Result.Global, 0);
+  SetLength(Result.Subs, 0);
+  Result.Data := False;
+  ext      := ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension;
+  filename := ExtractFilePath(Application.ExeName) + '\StructDefs\' + ext + '.txt';
+  if FileExists(filename) then
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFile(FileID, Data);
+    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 := StrToInt(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    := StrToInt(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[StrToInt(fields[3])];
+                    2:
+                      packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] * 256;
+                    4:
+                      packages := Data[StrToInt(fields[3])] + Data[StrToInt(fields[3]) + 1] *
+                        256 + Data[StrToInt(fields[3]) + 2] * 256 * 256 + Data[StrToInt(fields[3]) + 3] * 256 * 256 * 256;
+                  end;
+                end
+                else
+                begin
+                  packages := StrToInt(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 := StrToInt(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 + StrToInt(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;
+
+
+end.
Index: oup/releases/0.34a/Global/Data.pas
===================================================================
--- oup/releases/0.34a/Global/Data.pas	(revision 200)
+++ oup/releases/0.34a/Global/Data.pas	(revision 200)
@@ -0,0 +1,142 @@
+unit Data;
+interface
+uses Classes, Graphics, TypeDefs;
+
+const
+  Version:   String    = 'v0.34a';
+  DBVersion: String    = '0.4';
+  CrLf:      String[2] = #13 + #10;
+
+var
+  AppSettings:     TAppSettings;
+  AppSettingsFile: file of TAppSettings;
+
+
+const
+  HeaderOSIdentWin:     TDatOSIdent = ($1F, $27, $DC, $33);
+  HeaderOSIdentMac:     TDatOSIdent = ($61, $30, $C1, $23);
+  HeaderOSIdentMacBeta: TDatOSIdent = ($81, $11, $8D, $23);
+  HeaderGlobalIdent: TDatGlobalIdent = ($DF, $BC, $03, $00, $31, $33, $52, $56,
+                                        $40, $00, $14, $00, $10, $00, $08, $00);
+
+	FileTypes: array[0..113] of TFileType = (
+		(Extension: 'AISA';  StructID: 501; Name: 'AI Character Setup Array';  IdentWin:($E9,$6B,$4C,$22,$2A,$00,$00,$00);  IdentMac:($E9,$6B,$4C,$22,$2A,$00,$00,$00)),
+		(Extension: 'AITR';  StructID: 502; Name: 'AI script trigger array';  IdentWin:($55,$EA,$1A,$00,$00,$00,$00,$00);  IdentMac:($55,$EA,$1A,$00,$00,$00,$00,$00)),
+		(Extension: 'AIWA';  StructID: 503; Name: 'AI Imported Waypoint Array';  IdentWin:($03,$7F,$10,$00,$00,$00,$00,$00);  IdentMac:($03,$7F,$10,$00,$00,$00,$00,$00)),
+		(Extension: 'AKAA';  StructID: 504; Name: 'Adjacency Array';  IdentWin:($77,$DE,$11,$00,$00,$00,$00,$00);  IdentMac:($77,$DE,$11,$00,$00,$00,$00,$00)),
+		(Extension: 'ABNA';  StructID: 505; Name: 'BSP tree node Array';  IdentWin:($A0,$6D,$12,$00,$00,$00,$00,$00);  IdentMac:($A0,$6D,$12,$00,$00,$00,$00,$00)),
+		(Extension: 'AKVA';  StructID: 506; Name: 'BNV Node Array';  IdentWin:($E0,$05,$DF,$00,$00,$00,$00,$00);  IdentMac:($E0,$05,$DF,$00,$00,$00,$00,$00)),
+		(Extension: 'AKBA';  StructID: 507; Name: 'Side Array';  IdentWin:($84,$28,$3A,$00,$00,$00,$00,$00);  IdentMac:($84,$28,$3A,$00,$00,$00,$00,$00)),
+		(Extension: 'AKBP';  StructID: 508; Name: 'BSP node Array';  IdentWin:($49,$F4,$0C,$00,$00,$00,$00,$00);  IdentMac:($49,$F4,$0C,$00,$00,$00,$00,$00)),
+		(Extension: 'AKDA';  StructID: 509; Name: 'Door Frame Array';  IdentWin:($64,$54,$2E,$00,$00,$00,$00,$00);  IdentMac:($64,$54,$2E,$00,$00,$00,$00,$00)),
+		(Extension: 'AKEV';  StructID: 510; Name: 'Akira Environment';  IdentWin:($75,$DE,$14,$30,$88,$00,$00,$00);  IdentMac:($75,$DE,$14,$30,$88,$00,$00,$00)),
+		(Extension: 'AGQC';  StructID: 511; Name: 'Gunk Quad Collision Array';  IdentWin:($91,$CB,$1C,$00,$00,$00,$00,$00);  IdentMac:($91,$CB,$1C,$00,$00,$00,$00,$00)),
+		(Extension: 'AGDB';  StructID: 512; Name: 'Gunk Quad Debug Array';  IdentWin:($17,$2E,$07,$00,$00,$00,$00,$00);  IdentMac:($17,$2E,$07,$00,$00,$00,$00,$00)),
+		(Extension: 'AGQG';  StructID: 513; Name: 'Gunk Quad General Array';  IdentWin:($D2,$03,$1C,$00,$00,$00,$00,$00);  IdentMac:($D2,$03,$1C,$00,$00,$00,$00,$00)),
+		(Extension: 'AGQM';  StructID: 514; Name: 'Gunk Quad Material';  IdentWin:($A6,$4A,$04,$00,$00,$00,$00,$00);  IdentMac:($A6,$4A,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'AGQR';  StructID: 515; Name: 'Gunk Quad Render Array';  IdentWin:($3B,$3A,$08,$00,$00,$00,$00,$00);  IdentMac:($3B,$3A,$08,$00,$00,$00,$00,$00)),
+		(Extension: 'AKOT';  StructID: 516; Name: 'Oct tree';  IdentWin:($08,$DA,$B8,$E7,$11,$00,$00,$00);  IdentMac:($08,$DA,$B8,$E7,$11,$00,$00,$00)),
+		(Extension: 'OTIT';  StructID: 517; Name: 'Oct tree interior node Array';  IdentWin:($D2,$51,$0A,$00,$00,$00,$00,$00);  IdentMac:($D2,$51,$0A,$00,$00,$00,$00,$00)),
+		(Extension: 'OTLF';  StructID: 518; Name: 'Oct tree leaf node Array';  IdentWin:($0B,$AC,$1E,$00,$00,$00,$00,$00);  IdentMac:($0B,$AC,$1E,$00,$00,$00,$00,$00)),
+		(Extension: 'QTNA';  StructID: 519; Name: 'Quad tree node Array';  IdentWin:($CC,$6E,$06,$00,$00,$00,$00,$00);  IdentMac:($CC,$6E,$06,$00,$00,$00,$00,$00)),
+		(Extension: 'BINA';  StructID: 520; Name: 'Binary Data';  IdentWin:($41,$DB,$00,$00,$00,$00,$00,$00);  IdentMac:($11,$5E,$01,$00,$00,$00,$00,$00)),
+		(Extension: 'ENVP';  StructID: 521; Name: 'Env Particle Array';  IdentWin:($C3,$C1,$67,$00,$00,$00,$00,$00);  IdentMac:($C3,$C1,$67,$00,$00,$00,$00,$00)),
+		(Extension: 'FXLR';  StructID: 522; Name: 'FX Laser effect';  IdentWin:($A9,$F8,$83,$95,$06,$00,$00,$00);  IdentMac:($A9,$F8,$83,$95,$06,$00,$00,$00)),
+		(Extension: '3CLA';  StructID: 523; Name: 'RGB Color Array';  IdentWin:($BE,$E6,$04,$00,$00,$00,$00,$00);  IdentMac:($BE,$E6,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'EDIA';  StructID: 524; Name: 'Edge Index Array';  IdentWin:($F7,$B6,$07,$00,$00,$00,$00,$00);  IdentMac:($F7,$B6,$07,$00,$00,$00,$00,$00)),
+		(Extension: 'M3GM';  StructID: 525; Name: 'Geometry';  IdentWin:($36,$E4,$78,$A0,$27,$00,$00,$00);  IdentMac:($36,$E4,$78,$A0,$27,$00,$00,$00)),
+		(Extension: 'GMAN';  StructID: 526; Name: 'Geometry Animation';  IdentWin:($A5,$F5,$72,$A6,$09,$00,$00,$00);  IdentMac:($A5,$F5,$72,$A6,$09,$00,$00,$00)),
+		(Extension: 'M3GA';  StructID: 527; Name: 'GeometryArray';  IdentWin:($B2,$20,$6B,$20,$05,$00,$00,$00);  IdentMac:($B2,$20,$6B,$20,$05,$00,$00,$00)),
+		(Extension: 'PLEA';  StructID: 528; Name: 'Plane Equation Array';  IdentWin:($38,$BC,$07,$00,$00,$00,$00,$00);  IdentMac:($38,$BC,$07,$00,$00,$00,$00,$00)),
+		(Extension: 'PNTA';  StructID: 529; Name: '3D Point Array';  IdentWin:($6C,$67,$37,$00,$00,$00,$00,$00);  IdentMac:($6C,$67,$37,$00,$00,$00,$00,$00)),
+		(Extension: 'QUDA';  StructID: 530; Name: 'Quad array';  IdentWin:($6A,$5E,$03,$00,$00,$00,$00,$00);  IdentMac:($6A,$5E,$03,$00,$00,$00,$00,$00)),
+		(Extension: 'TXCA';  StructID: 531; Name: 'Texture Coordinate Array';  IdentWin:($1A,$14,$09,$00,$00,$00,$00,$00);  IdentMac:($1A,$14,$09,$00,$00,$00,$00,$00)),
+		(Extension: 'TXMP';  StructID: 532; Name: 'Texture Map';  IdentWin:($81,$75,$18,$91,$08,$00,$00,$00);  IdentMac:($5F,$EB,$1E,$91,$08,$00,$00,$00)),
+		(Extension: 'TXAN';  StructID: 533; Name: 'Texture Map Animation';  IdentWin:($87,$43,$13,$8B,$0A,$00,$00,$00);  IdentMac:($87,$43,$13,$8B,$0A,$00,$00,$00)),
+		(Extension: 'TXMA';  StructID: 534; Name: 'Texture map array';  IdentWin:($90,$7F,$DE,$99,$05,$00,$00,$00);  IdentMac:($90,$7F,$DE,$99,$05,$00,$00,$00)),
+		(Extension: 'TXMB';  StructID: 535; Name: 'Texture Map Big';  IdentWin:($52,$6A,$16,$8B,$0A,$00,$00,$00);  IdentMac:($52,$6A,$16,$8B,$0A,$00,$00,$00)),
+		(Extension: 'TXPC';  StructID: 536; Name: 'Texture Procedure Data';  IdentWin:($7E,$A7,$0B,$00,$00,$00,$00,$00);  IdentMac:($7E,$A7,$0B,$00,$00,$00,$00,$00)),
+		(Extension: 'M3TA';  StructID: 537; Name: 'Triangle array';  IdentWin:($C1,$F7,$02,$00,$00,$00,$00,$00);  IdentMac:($C1,$F7,$02,$00,$00,$00,$00,$00)),
+		(Extension: 'VCRA';  StructID: 538; Name: '3D Vector Array';  IdentWin:($39,$47,$05,$00,$00,$00,$00,$00);  IdentMac:($39,$47,$05,$00,$00,$00,$00,$00)),
+		(Extension: 'Impt';  StructID: 539; Name: 'Impact';  IdentWin:($16,$4F,$04,$00,$00,$00,$00,$00);  IdentMac:($16,$4F,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'Mtrl';  StructID: 540; Name: 'Material';  IdentWin:($0D,$8E,$02,$00,$00,$00,$00,$00);  IdentMac:($0D,$8E,$02,$00,$00,$00,$00,$00)),
+		(Extension: 'NMSA';  StructID: 541; Name: 'Network Spawn Point Array';  IdentWin:($9C,$09,$0C,$00,$00,$00,$00,$00);  IdentMac:($9C,$09,$0C,$00,$00,$00,$00,$00)),
+		(Extension: 'CONS';  StructID: 542; Name: 'Console';  IdentWin:($DD,$0B,$8B,$DA,$13,$00,$00,$00);  IdentMac:($DD,$0B,$8B,$DA,$13,$00,$00,$00)),
+		(Extension: 'DOOR';  StructID: 543; Name: 'Door';  IdentWin:($67,$FD,$72,$31,$06,$00,$00,$00);  IdentMac:($67,$FD,$72,$31,$06,$00,$00,$00)),
+		(Extension: 'OFGA';  StructID: 544; Name: 'Object Furn Geom Array';  IdentWin:($62,$C3,$FA,$74,$13,$00,$00,$00);  IdentMac:($62,$C3,$FA,$74,$13,$00,$00,$00)),
+		(Extension: 'OBLS';  StructID: 545; Name: 'Object LS Data';  IdentWin:($3D,$70,$0B,$00,$00,$00,$00,$00);  IdentMac:($3D,$70,$0B,$00,$00,$00,$00,$00)),
+		(Extension: 'TRIG';  StructID: 546; Name: 'Trigger';  IdentWin:($2C,$CD,$D0,$DC,$21,$00,$00,$00);  IdentMac:($2C,$CD,$D0,$DC,$21,$00,$00,$00)),
+		(Extension: 'TRGE';  StructID: 547; Name: 'Trigger Emitter';  IdentWin:($3C,$B9,$A6,$71,$08,$00,$00,$00);  IdentMac:($3C,$B9,$A6,$71,$08,$00,$00,$00)),
+		(Extension: 'TURR';  StructID: 548; Name: 'Turret';  IdentWin:($BE,$05,$58,$C8,$49,$00,$00,$00);  IdentMac:($BE,$05,$58,$C8,$49,$00,$00,$00)),
+		(Extension: 'OBAN';  StructID: 549; Name: 'Object animation';  IdentWin:($24,$0C,$4E,$00,$00,$00,$00,$00);  IdentMac:($24,$0C,$4E,$00,$00,$00,$00,$00)),
+		(Extension: 'OBDC';  StructID: 550; Name: 'Door class array';  IdentWin:($0B,$CA,$9E,$BD,$07,$00,$00,$00);  IdentMac:($0B,$CA,$9E,$BD,$07,$00,$00,$00)),
+		(Extension: 'OBOA';  StructID: 551; Name: 'Starting Object Array';  IdentWin:($E1,$86,$89,$4F,$13,$00,$00,$00);  IdentMac:($E1,$86,$89,$4F,$13,$00,$00,$00)),
+		(Extension: 'CBPI';  StructID: 552; Name: 'Character Body Part Impacts';  IdentWin:($C2,$D6,$F9,$0B,$0C,$00,$00,$00);  IdentMac:($C2,$D6,$F9,$0B,$0C,$00,$00,$00)),
+		(Extension: 'CBPM';  StructID: 553; Name: 'Character Body Part Material';  IdentWin:($1F,$35,$A4,$6B,$02,$00,$00,$00);  IdentMac:($1F,$35,$A4,$6B,$02,$00,$00,$00)),
+		(Extension: 'ONCC';  StructID: 554; Name: 'Oni Character Class';  IdentWin:($EF,$59,$C7,$AA,$A5,$04,$00,$00);  IdentMac:($EF,$59,$C7,$AA,$A5,$04,$00,$00)),
+		(Extension: 'ONIA';  StructID: 555; Name: 'Oni Character Impact Array';  IdentWin:($9A,$2F,$2B,$00,$00,$00,$00,$00);  IdentMac:($9A,$2F,$2B,$00,$00,$00,$00,$00)),
+		(Extension: 'ONCP';  StructID: 556; Name: 'Oni Character Particle Array';  IdentWin:($21,$73,$2F,$00,$00,$00,$00,$00);  IdentMac:($21,$73,$2F,$00,$00,$00,$00,$00)),
+		(Extension: 'ONCV';  StructID: 557; Name: 'Oni Character Variant';  IdentWin:($F5,$99,$02,$00,$00,$00,$00,$00);  IdentMac:($F5,$99,$02,$00,$00,$00,$00,$00)),
+		(Extension: 'CRSA';  StructID: 558; Name: 'Corpse Array';  IdentWin:($CC,$D4,$43,$15,$0C,$00,$00,$00);  IdentMac:($CC,$D4,$43,$15,$0C,$00,$00,$00)),
+		(Extension: 'DPge';  StructID: 559; Name: 'Diary Page';  IdentWin:($6B,$68,$8A,$BA,$07,$00,$00,$00);  IdentMac:($6B,$68,$8A,$BA,$07,$00,$00,$00)),
+		(Extension: 'FILM';  StructID: 560; Name: 'Film';  IdentWin:($AD,$62,$1B,$33,$0B,$00,$00,$00);  IdentMac:($AD,$62,$1B,$33,$0B,$00,$00,$00)),
+		(Extension: 'ONFA';  StructID: 561; Name: 'Imported Flag Node Array';  IdentWin:($E7,$0C,$1B,$00,$00,$00,$00,$00);  IdentMac:($E7,$0C,$1B,$00,$00,$00,$00,$00)),
+		(Extension: 'ONGS';  StructID: 562; Name: 'Oni Game Settings';  IdentWin:($B6,$EB,$26,$02,$00,$00,$00,$00);  IdentMac:($B6,$EB,$26,$02,$00,$00,$00,$00)),
+		(Extension: 'HPge';  StructID: 563; Name: 'Help Page';  IdentWin:($3B,$71,$2F,$4B,$04,$00,$00,$00);  IdentMac:($3B,$71,$2F,$4B,$04,$00,$00,$00)),
+		(Extension: 'IGHH';  StructID: 564; Name: 'IGUI HUD Help';  IdentWin:($DE,$58,$8E,$E5,$08,$00,$00,$00);  IdentMac:($DE,$58,$8E,$E5,$08,$00,$00,$00)),
+		(Extension: 'IGPG';  StructID: 565; Name: 'IGUI Page';  IdentWin:($7D,$88,$67,$CE,$11,$00,$00,$00);  IdentMac:($7D,$88,$67,$CE,$11,$00,$00,$00)),
+		(Extension: 'IGPA';  StructID: 566; Name: 'IGUI Page Array';  IdentWin:($05,$09,$BE,$DD,$04,$00,$00,$00);  IdentMac:($05,$09,$BE,$DD,$04,$00,$00,$00)),
+		(Extension: 'IGSt';  StructID: 567; Name: 'IGUI String';  IdentWin:($25,$77,$A4,$A2,$02,$00,$00,$00);  IdentMac:($25,$77,$A4,$A2,$02,$00,$00,$00)),
+		(Extension: 'IGSA';  StructID: 568; Name: 'IGUI String Array';  IdentWin:($08,$A4,$BE,$DD,$04,$00,$00,$00);  IdentMac:($08,$A4,$BE,$DD,$04,$00,$00,$00)),
+		(Extension: 'IPge';  StructID: 569; Name: 'Item Page';  IdentWin:($BA,$69,$83,$93,$02,$00,$00,$00);  IdentMac:($BA,$69,$83,$93,$02,$00,$00,$00)),
+		(Extension: 'KeyI';  StructID: 570; Name: 'Key Icons';  IdentWin:($AD,$57,$47,$3F,$40,$00,$00,$00);  IdentMac:($AD,$57,$47,$3F,$40,$00,$00,$00)),
+		(Extension: 'ONLV';  StructID: 571; Name: 'Oni Game Level';  IdentWin:($A3,$2E,$9A,$B7,$7D,$00,$00,$00);  IdentMac:($A3,$2E,$9A,$B7,$7D,$00,$00,$00)),
+		(Extension: 'ONLD';  StructID: 572; Name: 'Oni Game Level Descriptor';  IdentWin:($A1,$12,$04,$00,$00,$00,$00,$00);  IdentMac:($A1,$12,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'ONMA';  StructID: 573; Name: 'Imported Marker Node Array';  IdentWin:($79,$47,$12,$00,$00,$00,$00,$00);  IdentMac:($79,$47,$12,$00,$00,$00,$00,$00)),
+		(Extension: 'ONOA';  StructID: 574; Name: 'Object Gunk Array';  IdentWin:($7C,$5C,$E7,$4B,$06,$00,$00,$00);  IdentMac:($7C,$5C,$E7,$4B,$06,$00,$00,$00)),
+		(Extension: 'OPge';  StructID: 575; Name: 'Objective Page';  IdentWin:($FB,$BB,$30,$4B,$04,$00,$00,$00);  IdentMac:($FB,$BB,$30,$4B,$04,$00,$00,$00)),
+		(Extension: 'ONSK';  StructID: 576; Name: 'Oni Sky class';  IdentWin:($67,$10,$26,$C2,$14,$00,$00,$00);  IdentMac:($67,$10,$26,$C2,$14,$00,$00,$00)),
+		(Extension: 'ONSA';  StructID: 577; Name: 'Imported Spawn Array';  IdentWin:($34,$46,$04,$00,$00,$00,$00,$00);  IdentMac:($34,$46,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'TxtC';  StructID: 578; Name: 'Text Console';  IdentWin:($27,$8B,$AC,$B7,$01,$00,$00,$00);  IdentMac:($27,$8B,$AC,$B7,$01,$00,$00,$00)),
+		(Extension: 'ONTA';  StructID: 579; Name: 'Trigger Array';  IdentWin:($C0,$FC,$A0,$00,$00,$00,$00,$00);  IdentMac:($C0,$FC,$A0,$00,$00,$00,$00,$00)),
+		(Extension: 'ONVL';  StructID: 580; Name: 'Oni Variant List';  IdentWin:($8A,$C5,$34,$44,$05,$00,$00,$00);  IdentMac:($8A,$C5,$34,$44,$05,$00,$00,$00)),
+		(Extension: 'WPge';  StructID: 581; Name: 'Weapon Page';  IdentWin:($B5,$89,$58,$6F,$04,$00,$00,$00);  IdentMac:($B5,$89,$58,$6F,$04,$00,$00,$00)),
+		(Extension: 'OSBD';  StructID: 582; Name: 'Oni Sound Binary Data';  IdentWin:($6C,$DB,$00,$00,$00,$00,$00,$00);  IdentMac:($3C,$5E,$01,$00,$00,$00,$00,$00)),
+		(Extension: 'PSpc';  StructID: 583; Name: 'Part Specification';  IdentWin:($48,$26,$08,$00,$00,$00,$00,$00);  IdentMac:($48,$26,$08,$00,$00,$00,$00,$00)),
+		(Extension: 'PSpL';  StructID: 584; Name: 'Part Specification List';  IdentWin:($05,$CC,$0C,$00,$00,$00,$00,$00);  IdentMac:($05,$CC,$0C,$00,$00,$00,$00,$00)),
+		(Extension: 'PSUI';  StructID: 585; Name: 'Part Specifications UI';  IdentWin:($FB,$96,$4E,$54,$CD,$03,$00,$00);  IdentMac:($FB,$96,$4E,$54,$CD,$03,$00,$00)),
+		(Extension: 'SNDD';  StructID: 586; Name: 'Sound Data';  IdentWin:($78,$05,$37,$00,$00,$00,$00,$00);  IdentMac:($EB,$11,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'SUBT';  StructID: 587; Name: 'Subtitle Array';  IdentWin:($68,$6C,$04,$00,$00,$00,$00,$00);  IdentMac:($68,$6C,$04,$00,$00,$00,$00,$00)),
+		(Extension: 'UUEA';  StructID: 588; Name: 'Error Binding Array';  IdentWin:($BC,$EE,$0A,$00,$00,$00,$00,$00);  IdentMac:($BC,$EE,$0A,$00,$00,$00,$00,$00)),
+		(Extension: 'TMFA';  StructID: 589; Name: 'Float Array';  IdentWin:($24,$53,$02,$00,$00,$00,$00,$00);  IdentMac:($24,$53,$02,$00,$00,$00,$00,$00)),
+		(Extension: 'IDXA';  StructID: 590; Name: 'Index Array';  IdentWin:($8F,$70,$02,$00,$00,$00,$00,$00);  IdentMac:($8F,$70,$02,$00,$00,$00,$00,$00)),
+		(Extension: 'TStr';  StructID: 591; Name: 'String';  IdentWin:($A0,$64,$00,$00,$00,$00,$00,$00);  IdentMac:($A0,$64,$00,$00,$00,$00,$00,$00)),
+		(Extension: 'StNA';  StructID: 592; Name: 'String Array';  IdentWin:($20,$B5,$8C,$99,$05,$00,$00,$00);  IdentMac:($20,$B5,$8C,$99,$05,$00,$00,$00)),
+		(Extension: 'TMRA';  StructID: 593; Name: 'Template Reference Array';  IdentWin:($21,$35,$07,$00,$00,$00,$00,$00);  IdentMac:($21,$35,$07,$00,$00,$00,$00,$00)),
+		(Extension: 'TRAS';  StructID: 594; Name: 'Totoro Aiming Screen';  IdentWin:($30,$A9,$21,$FA,$01,$00,$00,$00);  IdentMac:($30,$A9,$21,$FA,$01,$00,$00,$00)),
+		(Extension: 'TRAM';  StructID: 595; Name: 'Totoro Animation Sequence';  IdentWin:($18,$C9,$3C,$7E,$10,$00,$00,$00);  IdentMac:($18,$C9,$3C,$7E,$10,$00,$00,$00)),
+		(Extension: 'TRAC';  StructID: 596; Name: 'Animation Collection';  IdentWin:($2F,$FB,$E9,$26,$0F,$00,$00,$00);  IdentMac:($2F,$FB,$E9,$26,$0F,$00,$00,$00)),
+		(Extension: 'TRCM';  StructID: 597; Name: 'Totoro Quaternion Body';  IdentWin:($4E,$05,$DE,$92,$23,$00,$00,$00);  IdentMac:($4E,$05,$DE,$92,$23,$00,$00,$00)),
+		(Extension: 'TRBS';  StructID: 598; Name: 'Totoro Body Set';  IdentWin:($39,$42,$92,$A2,$02,$00,$00,$00);  IdentMac:($39,$42,$92,$A2,$02,$00,$00,$00)),
+		(Extension: 'TRMA';  StructID: 599; Name: 'Texture Map Array';  IdentWin:($57,$6D,$DE,$99,$05,$00,$00,$00);  IdentMac:($57,$6D,$DE,$99,$05,$00,$00,$00)),
+		(Extension: 'TRFT';  StructID: 600; Name: 'Totoro Facing Table';  IdentWin:($AF,$21,$02,$00,$00,$00,$00,$00);  IdentMac:($AF,$21,$02,$00,$00,$00,$00,$00)),
+		(Extension: 'TRGA';  StructID: 601; Name: 'Totoro Quaternion Body Geometry Array';  IdentWin:($F8,$20,$6B,$20,$05,$00,$00,$00);  IdentMac:($F8,$20,$6B,$20,$05,$00,$00,$00)),
+		(Extension: 'TRIA';  StructID: 602; Name: 'Totoro Quaternion Body Index Array';  IdentWin:($82,$C4,$0A,$00,$00,$00,$00,$00);  IdentMac:($82,$C4,$0A,$00,$00,$00,$00,$00)),
+		(Extension: 'TRSC';  StructID: 603; Name: 'Screen (aiming) Collection';  IdentWin:($17,$6B,$78,$99,$05,$00,$00,$00);  IdentMac:($17,$6B,$78,$99,$05,$00,$00,$00)),
+		(Extension: 'TRTA';  StructID: 604; Name: 'Totoro Quaternion Body Translation Array';  IdentWin:($E8,$59,$07,$00,$00,$00,$00,$00);  IdentMac:($E8,$59,$07,$00,$00,$00,$00,$00)),
+		(Extension: 'TSFT';  StructID: 605; Name: 'Font';  IdentWin:($EA,$DE,$91,$BA,$16,$00,$00,$00);  IdentMac:($EA,$DE,$91,$BA,$16,$00,$00,$00)),
+		(Extension: 'TSFF';  StructID: 606; Name: 'Font Family';  IdentWin:($8A,$48,$6C,$8A,$0A,$00,$00,$00);  IdentMac:($8A,$48,$6C,$8A,$0A,$00,$00,$00)),
+		(Extension: 'TSFL';  StructID: 607; Name: 'Font Language';  IdentWin:($29,$DE,$08,$00,$00,$00,$00,$00);  IdentMac:($29,$DE,$08,$00,$00,$00,$00,$00)),
+		(Extension: 'TSGA';  StructID: 608; Name: 'Glyph Array';  IdentWin:($98,$4E,$2A,$00,$00,$00,$00,$00);  IdentMac:($98,$4E,$2A,$00,$00,$00,$00,$00)),
+		(Extension: 'UVDL';  StructID: 609; Name: 'UV Data List';  IdentWin:($E5,$16,$0A,$00,$00,$00,$00,$00);  IdentMac:($E5,$16,$0A,$00,$00,$00,$00,$00)),
+		(Extension: 'WMCL';  StructID: 610; Name: 'WM Cursor List';  IdentWin:($76,$D0,$09,$00,$00,$00,$00,$00);  IdentMac:($76,$D0,$09,$00,$00,$00,$00,$00)),
+		(Extension: 'WMDD';  StructID: 611; Name: 'WM Dialog Data';  IdentWin:($C4,$F3,$1D,$00,$1C,$00,$00,$00);  IdentMac:($C4,$F3,$1D,$00,$1C,$00,$00,$00)),
+		(Extension: 'WMMB';  StructID: 612; Name: 'WM Menu Bar';  IdentWin:($37,$67,$0C,$D2,$06,$00,$00,$00);  IdentMac:($37,$67,$0C,$D2,$06,$00,$00,$00)),
+		(Extension: 'WMM_';  StructID: 613; Name: 'WM Menu';  IdentWin:($38,$1A,$0C,$00,$00,$00,$00,$00);  IdentMac:($38,$1A,$0C,$00,$00,$00,$00,$00)),
+		(Extension: 'ONWC';  StructID: 614; Name: 'Oni Weapon Class';  IdentWin:($B5,$EE,$E0,$A3,$93,$01,$00,$00);  IdentMac:($B5,$EE,$E0,$A3,$93,$01,$00,$00))
+	);
+
+
+implementation
+
+end.
Index: oup/releases/0.34a/Global/Exporters.pas
===================================================================
--- oup/releases/0.34a/Global/Exporters.pas	(revision 200)
+++ oup/releases/0.34a/Global/Exporters.pas	(revision 200)
@@ -0,0 +1,260 @@
+unit Exporters;
+
+interface
+
+procedure ExportDatFile(ConnectionID, FileID: Integer; filename: String);
+procedure ExportRawFiles(ConnectionID, FileID: Integer; filename: String);
+procedure ExportRawFile(ConnectionID, FileID, DatOffset: Integer; filename: String);
+function ExportConverted(ConnectionID, FileID: Integer; filename: String): Integer;
+
+
+implementation
+
+uses
+  Classes, SysUtils, TypeDefs, ConnectionManager, OniImgClass;
+
+type
+  TExportHandler = function(ConnectionID, FileID: Integer; filename: String): Integer;
+  TExportHandlers = record
+    Ext:     String[4];
+    needed:  Boolean;
+    Handler: TExportHandler;
+  end;
+
+var
+  ExportHandlers: array of TExportHandlers;
+
+
+procedure ExportDatFile(ConnectionID, FileID: Integer; filename: String);
+var
+  filestream: TFileStream;
+begin
+  if FileExists(filename) then
+  begin
+    // Overwrite???
+  end;
+  filestream := TFileStream.Create(filename, fmCreate);
+  ConManager.Connection[ConnectionID].LoadDatFile(FileID, TStream(filestream));
+  filestream.Free;
+end;
+
+
+procedure ExportRawFiles(ConnectionID, FileID: Integer; filename: String);
+var
+  i: Integer;
+  rawlist: TRawDataList;
+begin
+  rawlist := ConManager.Connection[ConnectionID].GetRawList(fileid);
+  if Length(rawlist) > 0 then
+    for i := 0 to High(rawlist) do
+      ExportRawFile(ConnectionID, FileID, rawlist[i].SrcOffset, filename);
+end;
+
+
+procedure ExportRawFile(ConnectionID, FileID, DatOffset: Integer; filename: String);
+var
+  filestream: TFileStream;
+begin
+  if FileExists(filename + '.raw0x' + IntToHex(DatOffset, 8)) then
+  begin
+    // Overwrite???
+  end;
+  filestream := TFileStream.Create(filename + '.raw0x' + IntToHex(DatOffset, 8), fmCreate);
+  ConManager.Connection[ConnectionID].LoadRawFile(FileID, DatOffset, TStream(filestream));
+  filestream.Free;
+end;
+
+function ExportConverted(ConnectionID, FileID: Integer; filename: String): Integer;
+var
+  i: Integer;
+  fileinfo: TFileInfo;
+begin
+  fileinfo := ConManager.Connection[ConnectionID].GetFileInfo(FileID);
+  if Length(ExportHandlers) > 0 then
+    for i := 0 to High(ExportHandlers) do
+      if ExportHandlers[i].Ext = fileinfo.Extension then
+        Result := ExportHandlers[i].Handler(ConnectionID, FileID, filename);
+end;
+
+
+
+
+function ExportSNDD(ConnectionID, FileID: Integer; filename: String): Integer;
+type
+  TDatData = packed record
+    {0x00}
+    _fileid:         Integer;
+    level:           Integer;
+    FormatSize:      Integer;
+    AudioFormat:     Word;
+    NumChannels:     Word;
+    {0x10}
+    SampleRate:      Integer;
+    ByteRate:        Integer;
+    BlockAlign:      Word;
+    BitsPerSample:   Word;
+    {0x1C}
+    SizeExtHeader:   Word;
+    SamplesPerBlock: Word;
+    NumCoefficients: Word;
+    Coefficients:    array[0..6] of Integer;
+    {0x3E}
+    Duration:        Word;
+    {0x40}
+    RawSize:         Integer;
+    RawPos:          Integer;
+  end;
+var
+  filestream: TFileStream;
+  DatData:     TDatData;
+  i: Integer;
+
+  //Wave Header Stuff
+  ASCII_RIFF:   LongWord; //"RIFF"
+  WAVE_Len:     Integer;
+  ASCII_WAVE:   LongWord; //"WAVE"
+  ASCII_FMT:    LongWord; //"fmt "
+  WAVE_FMT_Len: Integer;
+  ASCII_DATA:   LongWord; //"data"
+  WAVE_DataLen:  Integer;
+begin
+  Result := 0;
+  ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, 0, SizeOf(DatData), @DatData);
+  with DatData do
+  begin
+    //Initializing Header vars
+    ASCII_RIFF   := 1179011410; // 'RIFF'
+    WAVE_Len     := RAWSize + 70;
+    ASCII_WAVE   := 1163280727;  // 'WAVE'
+    ASCII_FMT    := 544501094;   // 'fmt '
+    WAVE_FMT_Len := 50;          // 50 bytes
+    ASCII_DATA   := 1635017060;  // 'data'
+    WAVE_DataLen := RAWSize;
+
+    if FileExists(filename+'.wav') then
+    begin
+      // Overwrite???
+    end;
+
+    //Now start packing this into a neat wave...
+    filestream := TFileStream.Create(filename + '.wav', fmCreate);
+    filestream.Write(ASCII_RIFF, SizeOf(ASCII_RIFF));
+    filestream.Write(WAVE_Len, SizeOf(WAVE_Len));
+    filestream.Write(ASCII_WAVE, SizeOf(ASCII_WAVE));
+    filestream.Write(ASCII_FMT, SizeOf(ASCII_FMT));
+    filestream.Write(WAVE_FMT_Len, SizeOf(WAVE_FMT_Len));
+    filestream.Write(AudioFormat, SizeOf(AudioFormat));
+    filestream.Write(NumChannels, SizeOf(NumChannels));
+    filestream.Write(Samplerate, SizeOf(Samplerate));
+    filestream.Write(ByteRate, SizeOf(ByteRate));
+    filestream.Write(BlockAlign, SizeOf(BlockAlign));
+    filestream.Write(BitsPerSample, SizeOf(BitsPerSample));
+    filestream.Write(SizeExtHeader, SizeOf(SizeExtHeader));
+    filestream.Write(SamplesPerBlock, SizeOf(SamplesPerBlock));
+    filestream.Write(NumCoefficients, SizeOf(NumCoefficients));
+    for i := 0 to High(Coefficients) do
+      filestream.Write(Coefficients[i], SizeOf(Coefficients[i]));
+    filestream.Write(ASCII_DATA, SizeOf(ASCII_DATA));
+    filestream.Write(WAVE_DataLen, SizeOf(WAVE_DataLen));
+    ConManager.Connection[ConnectionID].LoadRawFile(FileID, $44, TStream(filestream));
+    filestream.Free;
+  end;
+end;
+
+
+
+
+function ExportTRAC(ConnectionID, FileID: Integer; filename: String): Integer;
+var
+  link: Integer;
+  linkcount: Word;
+  i: Integer;
+begin
+  Result := 0;
+
+  ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $18, SizeOf(link), @link);
+  link := link div 256;
+
+  ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $1E, SizeOf(linkcount), @linkcount);
+  for i := 1 to linkcount do
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $20 + (i - 1) * 12 + 8, SizeOf(link), @link);
+    link := link div 256;
+  end;
+end;
+
+
+
+
+function ExportTXAN(ConnectionID, FileID: Integer; filename: String): Integer;
+var
+  loop_speed, unknown: Word;
+  linkcount: Integer;
+  link: Integer;
+  i: Byte;
+begin
+  Result := 0;
+
+  ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $14, SizeOf(loop_speed), @loop_speed);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $16, SizeOf(unknown), @unknown);
+
+  ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $1C, SizeOf(linkcount), @linkcount);
+  for i := 0 to linkcount - 1 do
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(FileID, $20 + i * 4, SizeOf(link), @link);
+    link := link div 256;
+    if link = 0 then
+      link := fileid - 1;
+  end;
+end;
+
+
+
+
+function ExportImage(ConnectionID, FileID: Integer; filename: String): Integer;
+var
+  img: TOniImage;
+begin
+  Result := 0;
+
+  if FileExists(filename+'.bmp') then
+  begin
+    // Overwrite???
+  end;
+
+  img := TOniImage.Create;
+  img.Load(ConnectionID, FileID);
+  img.WriteToFile(filename+'.dds');
+  img.WriteToFile(filename+'.bmp');
+  img.Free;
+end;
+
+
+
+procedure InsertExportHandler(ext: String; needed: Boolean; handler: TExportHandler);
+begin
+  SetLength(ExportHandlers, Length(ExportHandlers) + 1);
+  ExportHandlers[High(ExportHandlers)].Ext := ext;
+  ExportHandlers[High(ExportHandlers)].needed := needed;
+  ExportHandlers[High(ExportHandlers)].handler := handler;
+end;
+
+{
+  ExportHandlers: array[1..3] 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:ExportImage),
+    (Ext:'TXMP'; needed:True; Handler:ExportImage)
+);
+}
+
+initialization
+//  InsertExportHandler('ABNA', False, ABNA);
+//  InsertExportHandler('AGDB', False, AGDB);
+  InsertExportHandler('SNDD', True, ExportSNDD);
+  InsertExportHandler('TXMB', True, ExportImage);
+  InsertExportHandler('TXMP', True, ExportImage);
+end.
Index: oup/releases/0.34a/Global/Functions.pas
===================================================================
--- oup/releases/0.34a/Global/Functions.pas	(revision 200)
+++ oup/releases/0.34a/Global/Functions.pas	(revision 200)
@@ -0,0 +1,279 @@
+unit Functions;
+
+interface
+
+uses TypeDefs, Classes;
+
+function BoolToStr(bool: Boolean): String;
+function Decode_Int(buffer: TByteData): LongWord;
+function Encode_Int(input: LongWord): TByteData;
+function Decode_Float(buffer: TByteData): Single;
+function Encode_Float(input: Single): TByteData;
+function IntToBin(Value: Byte): String;
+function DataToBin(Data: TByteData): String;
+function BinToInt(bin: String): Byte;
+function MakeDatLink(FileID: Integer): Integer;
+
+function StringSmaller(string1, string2: String): Boolean;
+
+function FormatNumber(Value: LongWord; Width: Byte; leadingzeros: Char): String;
+function FormatFileSize(size: LongWord): String;
+function CreateHexString(Data: TByteData; HexOnly: Boolean): String;
+function DecodeHexString(hex: String): TByteData;
+function GetWinFileName(Name: String): String;
+//function GetExtractPath: String;
+
+function Explode(_string: String; delimiter: Char): TStrings;
+
+
+implementation
+
+uses SysUtils, Math, StrUtils;
+
+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 Decode_Int(buffer: TByteData): LongWord;
+begin
+  Result := buffer[0] + buffer[1] * 256 + buffer[2] * 256 * 256 + buffer[3] * 256 * 256 * 256;
+end;
+
+
+function Encode_Int(input: LongWord): TByteData;
+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: TByteData): 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): TByteData;
+var
+  _valueswitcher: TValueSwitcher;
+begin
+  _valueswitcher.ValueFloat := input;
+  Result := Encode_Int(_valueswitcher.ValueInt);
+end;
+
+
+function IntToBin(Value: Byte): String;
+var
+  i: Byte;
+begin
+  Result := '';
+  for i := 7 downto 0 do
+    Result := Result + IntToStr((Value shr i) and $01);
+end;
+
+
+function DataToBin(Data: TByteData): 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 MakeDatLink(FileID: Integer): Integer;
+begin
+  Result := FileID * 256 + 1;
+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;
+var
+  floatformat: TFormatSettings;
+begin
+  floatformat.DecimalSeparator := '.';
+  if size >= 1000 * 1024 * 1024 then
+    Result := FloatToStrF(size / 1024 / 1024 / 1024, ffFixed, 5, 1, floatformat) + ' GB'
+  else
+    if size >= 1000 * 1024 then
+      Result := FloatToStrF(size / 1024 / 1024, ffFixed, 5, 1, floatformat) + ' MB'
+    else
+      if size >= 1000 then
+        Result := FloatToStrF(size / 1024, ffFixed, 5, 1, floatformat) + ' KB'
+      else
+        Result := IntToStr(size) + ' B';
+end;
+
+
+
+
+function CreateHexString(Data: TByteData; HexOnly: Boolean): String;
+var
+  string_build, ascii_version: String;
+  i: Integer;
+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): TByteData;
+var
+  i: Integer;
+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 Explode(_string: String; delimiter: Char): TStrings;
+var
+  start, len: Word;
+begin
+  Result := TStringList.Create;
+  start := 1;
+  while PosEx(delimiter, _string, start) > 0 do
+  begin
+    len := PosEx(delimiter, _string, start) - start;
+    Result.Add(MidStr(_string, start, len));
+    start := start + len + 1;
+  end;
+  Result.Add(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;
+
+
+end.
Index: oup/releases/0.34a/Global/Img_DDSTypes.pas
===================================================================
--- oup/releases/0.34a/Global/Img_DDSTypes.pas	(revision 200)
+++ oup/releases/0.34a/Global/Img_DDSTypes.pas	(revision 200)
@@ -0,0 +1,69 @@
+unit Img_DDSTypes;
+interface
+
+type
+  TPIXELFORMAT = packed record
+    Size         : Integer;
+    Flags        : Integer;
+    FOURCC       : array[1..4] of Char;
+    RGBBitCount  : Integer;
+    RBitMask     : LongWord;
+    GBitMask     : LongWord;
+    BBitMask     : LongWord;
+    AlphaBitMask : LongWord;
+  end;
+
+  TDDSCAPS2 = packed record
+    Caps1       : Integer;
+    Caps2       : Integer;
+    Reserved    : array[1..2] of Integer;
+  end;
+
+  TSURFACEDESC2 = packed record
+    Size        : Integer;
+    Flags       : Integer;
+    Height      : Integer;
+    Width       : Integer;
+    PitchOrLinearSize : Integer;
+    Depth       : Integer;
+    MipMapCount : Integer;
+    Reserved    : array[1..11] of Integer;
+    PIXELFORMAT : TPIXELFORMAT;
+    DDSCAPS2    : TDDSCAPS2;
+    Reserved2   : Integer;
+  end;
+
+  TDDSDXTHeader = packed record
+    FOURCC       : array[1..4] of Char;
+    SURFACEDESC2 : TSURFACEDESC2;
+  end;
+
+const
+  DDSD_CAPS : Integer = $00000001;
+  DDSD_HEIGHT : Integer = $00000002;
+  DDSD_WIDTH : Integer = $00000004;
+  DDSD_PITCH : Integer = $00000008;
+  DDSD_PIXELFORMAT : Integer = $00001000;
+  DDSD_MIPMAPCOUNT : Integer = $00020000;
+  DDSD_LINEARSIZE : Integer = $00080000;
+  DDSD_DEPTH : Integer = $00800000;
+
+  DDPF_ALPHAPIXELS : Integer = $00000001;
+  DDPF_FOURCC : Integer = $00000004;
+  DDPF_RGB : Integer = $00000040;
+
+  DDSCAPS_COMPLEX : Integer = $00000008;
+  DDSCAPS_TEXTURE : Integer = $00001000;
+  DDSCAPS_MIPMAP : Integer = $00400000;
+
+  DDSCAPS2_CUBEMAP : Integer = $00000200;
+  DDSCAPS2_CUBEMAP_POSITIVEX : Integer = $00000400;
+  DDSCAPS2_CUBEMAP_NEGATIVEX : Integer = $00000800;
+  DDSCAPS2_CUBEMAP_POSITIVEY : Integer = $00001000;
+  DDSCAPS2_CUBEMAP_NEGATIVEY : Integer = $00002000;
+  DDSCAPS2_CUBEMAP_POSITIVEZ : Integer = $00004000;
+  DDSCAPS2_CUBEMAP_NEGATIVEZ : Integer = $00008000;
+  DDSCAPS2_VOLUME : Integer = $00200000;
+
+implementation
+end.
Index: oup/releases/0.34a/Global/OniImgClass.pas
===================================================================
--- oup/releases/0.34a/Global/OniImgClass.pas	(revision 200)
+++ oup/releases/0.34a/Global/OniImgClass.pas	(revision 200)
@@ -0,0 +1,608 @@
+unit OniImgClass;
+
+interface
+
+uses Math, Dialogs, Types, SysUtils, Classes, Data, ConnectionManager, TypeDefs,
+  Imaging, ImagingTypes, Graphics;
+
+
+type
+  TOniImage = class
+  private
+    FImages: TDynImageDataArray;
+    function GetImage(MipGen: Integer): TImageData;
+    function GetWidth(MipGen: Integer): Integer;
+    function GetHeight(MipGen: Integer): Integer;
+    function GetImageFormat: TImageFormat;
+    procedure SetImageFormat(Format: TImageFormat);
+    function pGetImageFormatInfo: TImageFormatInfo;
+    function GetHasMipMaps: Boolean;
+  protected
+  public
+    property Images: TDynImageDataArray         read FImages;
+    property Image[MipGen: Integer]: TImageData read GetImage;
+    property Width[MipGen: Integer]: Integer    read GetWidth;
+    property Height[MipGen: Integer]: Integer   read GetHeight;
+    property Format: TImageFormat read GetImageFormat write SetImageFormat;
+    property FormatInfo: TImageFormatInfo read pGetImageFormatInfo;
+    property HasMipMaps: Boolean read GetHasMipMaps;
+
+    constructor Create;
+    procedure Free;
+    function Load(ConnectionID, FileID: Integer): Boolean;
+    function LoadFromPSpc(ConnectionID, FileID: Integer): Boolean;
+    function LoadFromTXMP(ConnectionID, FileID: Integer): Boolean;
+    function LoadFromTXMB(ConnectionID, FileID: Integer): Boolean;
+
+    procedure SaveDataToStream(MipMaps: Boolean; var Target: TStream);
+
+    function LoadFromFile(filename: String): Boolean;
+    function WriteToFile(filename: String): Boolean;
+
+    procedure DrawOnCanvas(Canvas: TCanvas; Index: Integer);
+    function GetImageSize(MipMaps: Boolean): Integer;
+  published
+  end;
+
+
+implementation
+
+uses Img_DDSTypes, ImagingComponents;
+
+
+procedure TOniImage.DrawOnCanvas(Canvas: TCanvas; Index: Integer);
+var
+  singleimg: TImageData;
+  rect: TRect;
+begin
+  InitImage(singleimg);
+  CloneImage(FImages[Index-1], singleimg);
+  ConvertImage(singleimg, ifX8R8G8B8);
+  rect.Left := 0;
+  rect.Top := 0;
+  rect.Right := singleimg.Width - 1;
+  rect.Bottom := singleimg.Height - 1;
+  Canvas.Brush.Color := $C8D0D4;
+  Canvas.FillRect(Canvas.ClipRect);
+  DisplayImageData(Canvas, rect, singleimg, rect);
+  FreeImage(singleimg);
+end;
+
+
+
+constructor TOniImage.Create;
+begin
+end;
+
+
+
+procedure TOniImage.Free;
+begin
+  FreeImagesInArray(FImages);
+end;
+
+
+
+
+function TOniImage.GetImage(MipGen: Integer): TImageData;
+begin
+  if MipGen <= Length(FImages) then
+  begin
+    InitImage(Result);
+    CloneImage(FImages[MipGen-1], Result);
+  end;
+end;
+
+
+
+function TOniImage.GetWidth(MipGen: Integer): Integer;
+begin
+  if MipGen <= Length(FImages) then
+    Result := FImages[MipGen-1].Width
+  else
+    Result := -1;
+end;
+
+
+function TOniImage.GetHeight(MipGen: Integer): Integer;
+begin
+  if MipGen <= Length(FImages) then
+    Result := FImages[MipGen-1].Height
+  else
+    Result := -1;
+end;
+
+
+function TOniImage.GetImageFormat: TImageFormat;
+begin
+  if Length(FImages) > 0 then
+    Result := FImages[0].Format
+  else
+    Result := ifUnknown;
+end;
+
+procedure TOniImage.SetImageFormat(Format: TImageFormat);
+var
+  i: Integer;
+begin
+  if Length(FImages) > 0 then
+    for i := 0 to High(FImages) do
+      ConvertImage(FImages[i], Format);
+end;
+
+
+function TOniImage.pGetImageFormatInfo: TImageFormatInfo;
+begin
+  if Length(FImages) > 0 then
+    GetImageFormatInfo(FImages[0].Format, Result);
+end;
+
+
+function TOniImage.GetHasMipMaps: Boolean;
+begin
+  Result := Length(FImages) > 1;
+end;
+
+
+function TOniImage.Load(ConnectionID, FileID: Integer): Boolean;
+var
+  FileInfo: TFileInfo;
+begin
+  FileInfo := ConManager.Connection[ConnectionID].GetFileInfo(fileid);
+  if FileInfo.Extension = 'PSpc' then
+    Result := LoadFromPSpc(ConnectionID, fileid)
+  else if FileInfo.Extension = 'TXMB' then
+    Result := LoadFromTXMB(ConnectionID, fileid)
+  else if FileInfo.Extension = 'TXMP' then
+    Result := LoadFromTXMP(ConnectionID, fileid)
+  else
+    Result := False;
+end;
+
+
+
+
+function TOniImage.LoadFromPSpc(ConnectionID, FileID: Integer): Boolean;
+type
+  TPoint = packed record
+    X, Y: Word;
+  end;
+
+  TPSpc = packed record
+    p1:   array[0..8] of TPoint;
+    p2:   array[0..8] of TPoint;
+    TXMP: Integer;
+  end;
+
+  TPart = packed record
+    x_txmp, y_txmp: Word;
+    x_pspc, y_pspc: Word;
+    w, h:    Word;
+    imgdata: TImageData;
+    used:    Boolean;
+  end;
+const
+  PartMatch: array[0..8] of Byte = (0, 3, 6, 1, 4, 7, 2, 5, 8);
+  stretch_x: Integer = 1;
+  stretch_y: Integer = 1;
+var
+  x, y: Word;
+  i: Integer;
+
+  PSpc:     TPSpc;
+  txmpimg:  TOniImage;
+//  txmpdata: TByteData;
+
+  parts:    array[0..8] of TPart;
+  part:     Byte;
+  cols:     array[0..2] of Word;
+  rows:     array[0..2] of Word;
+  col, row: Byte;
+
+  pspcimage: TImageData;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, SizeOf(PSpc), @PSpc);
+  PSpc.TXMP := PSpc.TXMP div 256;
+  if PSpc.TXMP = 0 then
+  begin
+    Result := False;
+    Exit;
+  end;
+  txmpimg := TOniImage.Create;
+  txmpimg.Load(ConnectionID, PSpc.TXMP);
+  CloneImage(txmpimg.Image[1], pspcimage);
+  txmpimg.Free;
+
+  with pspc do
+  begin
+    for i := 0 to 2 do
+    begin
+      cols[i] := 0;
+      rows[i] := 0;
+    end;
+    for i := 0 to 8 do
+    begin
+      part := PartMatch[i];
+      col  := i div 3;
+      row  := i mod 3;
+      if (p2[i].X > 0) or (p2[i].Y > 0) then
+      begin
+        parts[part].x_txmp := p1[i].X;// - 1;
+        parts[part].y_txmp := p1[i].Y;// - 1;
+        parts[part].x_pspc := 0;
+        if col > 0 then
+          for x := 0 to col - 1 do
+            Inc(parts[part].x_pspc, cols[x]);
+        parts[part].y_pspc := 0;
+        if row > 0 then
+          for y := 0 to row - 1 do
+            Inc(parts[part].y_pspc, rows[y]);
+        parts[part].w := Max(p2[i].X - p1[i].X, 1);// + 1;
+        parts[part].h := Max(p2[i].Y - p1[i].Y, 1);// + 1;
+        parts[part].used := True;
+        cols[col] := parts[part].w;
+        rows[row] := parts[part].h;
+
+        NewImage(parts[part].w, parts[part].h, pspcimage.Format, parts[part].imgdata);
+
+        CopyRect(pspcimage,
+            parts[part].x_txmp, parts[part].y_txmp, parts[part].w, parts[part].h,
+            parts[part].imgdata, 0, 0);
+      end
+      else
+      begin
+        parts[part].used := False;
+      end;
+    end;
+
+  end;
+
+  for i := 0 to 8 do
+  begin
+    if parts[i].used then
+    begin
+//      SaveImageToFile('M:\' + IntToStr(i) + '.bmp', parts[i].imgdata);
+    end;
+  end;
+
+  SetLength(FImages, 1);
+  x := cols[0] + cols[1] * stretch_x + cols[2];
+  y := rows[0] + rows[1] * stretch_y + rows[2];
+
+  NewImage(x, y, pspcimage.Format, FImages[0]);
+
+  x := 0;
+  for col := 0 to 2 do
+  begin
+    y := 0;
+    for row := 0 to 2 do
+    begin
+      part := row*3 + col;
+      if parts[part].used then
+      begin
+        if (row = 1) and (col = 1) then
+          StretchRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h,
+              FImages[0], x, y, parts[part].w * stretch_x, parts[part].h * stretch_y, rfNearest)
+        else
+        if (row = 1) then
+          StretchRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h,
+              FImages[0], x, y, parts[part].w, parts[part].h * stretch_y, rfNearest)
+        else
+        if (col = 1) then
+          StretchRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h,
+              FImages[0], x, y, parts[part].w * stretch_x, parts[part].h, rfNearest)
+        else
+          CopyRect(parts[part].imgdata, 0, 0, parts[part].w, parts[part].h,
+              FImages[0], x, y );
+        if row = 1 then
+          y := y + parts[part].h * stretch_y
+        else
+          y := y + parts[part].h;
+      end;
+    end;
+    if cols[col] > 0 then
+    begin
+      if (col = 1) then
+        x := x + parts[part].w * stretch_x
+      else
+        x := x + parts[part].w;
+    end;
+  end;
+
+  FreeImage(pspcimage);
+  for i := 0 to 8 do
+    if parts[i].used then
+      FreeImage(parts[i].imgdata);
+end;
+
+
+
+
+function TOniImage.LoadFromTXMP(ConnectionID, FileID: Integer): Boolean;
+var
+  img_addr: Integer;
+  data: TMemoryStream;
+  hdr: TDDSDXTHeader;
+  imginfo: Integer;
+  x,y, i: Integer;
+
+  _width, _height: Word;
+  _storetype: Byte;
+  _depth: Byte;
+begin
+  Result := True;
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(_width), @_width);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(_height), @_height);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(_storetype), @_storetype);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, SizeOf(imginfo), @imginfo);
+  if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, SizeOf(img_addr), @img_addr)
+  else
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, SizeOf(img_addr), @img_addr);
+
+  case _storetype of
+    0, 1, 2:
+      _depth := 16;
+    7, 8:
+      _depth := 32;
+    9:
+      _depth := 16;
+    else
+      Result := False;
+      Exit;
+  end;
+
+  with hdr do
+  begin
+    FOURCC := 'DDS ';
+    with SURFACEDESC2 do
+    begin
+      Size := 124;
+      Flags := DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or DDSD_HEIGHT;
+      if _storetype = 9 then
+        Flags := Flags or DDSD_LINEARSIZE
+      else
+        Flags := Flags or DDSD_PITCH;
+      if (imginfo and $01) > 0 then
+        Flags := Flags or DDSD_MIPMAPCOUNT;
+      Height := _height;
+      Width := _width;
+      if _storetype = 9 then
+        PitchOrLinearSize := width * height div 2
+      else
+        PitchOrLinearSize := width * _depth div 8;
+      Depth := 0;
+      MipMapCount := 1;
+      if (imginfo and $01) > 0 then
+      begin
+        x := width;
+        y := height;
+        while (x > 1) and (y > 1) do
+        begin
+          x := x div 2;
+          y := y div 2;
+          Inc(MipMapCount);
+        end;
+      end;
+      for i := 1 to 11 do
+        Reserved[i] := 0;
+      with PIXELFORMAT do
+      begin
+        Size := 32;
+        if _storetype = 9 then
+          Flags := DDPF_FOURCC
+        else
+          Flags := DDPF_RGB;
+        if _storetype in [0, 2] then
+          Flags := Flags or DDPF_ALPHAPIXELS;
+        if _storetype = 9 then
+          FOURCC := 'DXT1'
+        else
+        begin
+          RGBBitCount := _depth;
+          case _storetype of
+            0: begin
+              RBitMask := $0F00;
+              GBitMask := $00F0;
+              BBitMask := $000F;
+              AlphaBitMask := $F000;
+            end;
+            1, 2: begin
+              RBitMask := $7C00;
+              GBitMask := $03E0;
+              BBitMask := $001F;
+              if _storetype = 2 then
+                AlphaBitMask := $8000
+              else
+                AlphaBitMask := $0000;
+            end;
+            8: begin
+              RBitMask := $00FF0000;
+              GBitMask := $0000FF00;
+              BBitMask := $000000FF;
+              AlphaBitMask := $00000000;
+            end;
+          end;
+        end;
+      end;
+      with DDSCAPS2 do
+      begin
+        Caps1 := DDSCAPS_TEXTURE;
+        if (imginfo and $01) > 0 then
+          Caps1 := Caps1 or DDSCAPS_COMPLEX or DDSCAPS_MIPMAP;
+        Caps2 := 0;
+        Reserved[1] := 0;
+        Reserved[2] := 0;
+      end;
+    end;
+  end;
+
+  data := TMemoryStream.Create;
+  data.Write(hdr, SizeOf(hdr));
+  if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
+    ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, TStream(data))
+  else
+    ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, TStream(data));
+
+//  data.Seek(0, soFromBeginning);
+//  data.SaveToFile('m:\test.txmp');
+
+  data.Seek(0, soFromBeginning);
+  result := LoadMultiImageFromStream(data, FImages);
+  data.Free;
+{
+  if result then
+  begin
+    for i := 0 to High(FImages) do
+    begin
+      data := TMemoryStream.Create;
+      data.Write(FImages[i].Bits^, FImages[i].Size);
+      data.Seek(0, soFromBeginning);
+      data.SaveToFile('m:\test.txmp.'+IntToStr(i));
+      data.Free;
+    end;
+  end;
+}
+  if not result then
+  begin
+    ShowMessage('Error while loading file' + #13#10 + DetermineStreamFormat(data));
+//    data.SaveToFile('m:\prob.dds');
+  end;
+end;
+
+
+
+
+function TOniImage.LoadFromTXMB(ConnectionID, FileID: Integer): Boolean;
+var
+  i, x, y, imgid: Integer;
+  rows, cols: Word;
+  linkcount: Integer;
+  link: Integer;
+  images: array of TOniImage;
+  x_start, y_start: Integer;
+
+  width, height: Word;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, SizeOf(width), @width);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $12, SizeOf(height), @height);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, SizeOf(cols), @cols);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1A, SizeOf(rows), @rows);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, SizeOf(linkcount), @linkcount);
+  SetLength(images, linkcount);
+  for i := 0 to linkcount - 1 do
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * 4, SizeOf(link), @link);
+    link := link div 256;
+    images[i] := TOniImage.Create;
+    images[i].LoadFromTXMP(ConnectionID, link);
+    SetLength(FImages, 1);
+    NewImage(width, height, ifA1R5G5B5, FImages[0]);
+  end;
+  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[i].Image[0].Width;
+      for i := 0 to y do
+        if i < y then
+          y_start := y_start + images[i].Image[0].Height;
+      CopyRect(images[imgid].Image[0], 0, 0, images[imgid].Image[0].Width,
+          images[imgid].Image[0].Height, FImages[0], x_start, y_start);
+    end;
+  end;
+  for i := 0 to linkcount - 1 do
+    images[i].Free;
+end;
+
+
+
+procedure TOniImage.SaveDataToStream(MipMaps: Boolean; var Target: TStream);
+var
+  images: TDynImageDataArray;
+  mem: TMemoryStream;
+  i: Integer;
+begin
+  if Length(FImages) = 0 then
+    Exit;
+  if MipMaps then
+  begin
+    if Length(FImages) = 1 then
+    begin
+      if not GenerateMipMaps(FImages[0], 0, images) then
+      begin
+        ShowMessage('Could not generate MipMaps');
+        Exit;
+      end;
+    end
+    else
+    begin
+      SetLength(images, Length(FImages));
+      for i := 0 to High(FImages) do
+        CloneImage(FImages[i], images[i]);
+    end;
+    mem := TMemoryStream.Create;
+    if not SaveMultiImageToStream('dds', mem, images) then
+    begin
+      ShowMessage('Could not save images to stream');
+      Exit;
+    end;
+    FreeImagesInArray(images);
+  end
+  else
+  begin
+    mem := TMemoryStream.Create;
+    if not SaveImageToStream('dds', mem, FImages[0]) then
+    begin
+      ShowMessage('Could not save image to stream');
+      Exit;
+    end;
+  end;
+  if not Assigned(Target) then
+    Target := TMemoryStream.Create;
+
+//  mem.Seek(0, soFromBeginning);
+//  mem.SaveToFile('m:\dds.dds');
+
+  mem.Seek(128, soFromBeginning);
+  Target.CopyFrom(mem, mem.Size - 128);
+  mem.Free;
+  Target.Seek(0, soFromBeginning);
+end;
+
+
+function TOniImage.LoadFromFile(filename: String): Boolean;
+begin
+  if not LoadMultiImageFromFile(filename, FImages) then
+    ShowMessage('Couldn''t load image file');
+end;
+
+
+function TOniImage.WriteToFile(filename: String): Boolean;
+begin
+  SaveMultiImageToFile(filename, FImages);
+end;
+
+
+
+function TOniImage.GetImageSize(MipMaps: Boolean): Integer;
+var
+  i: Integer;
+begin
+  if Length(FImages) > 0 then
+  begin
+    Result := FImages[0].Size;
+    if mipmaps then
+      for i := 1 to High(FImages) do
+        Result := Result + FImages[i].Size;
+  end
+  else
+    Result := -1;
+end;
+
+end.
Index: oup/releases/0.34a/Global/RawList.pas
===================================================================
--- oup/releases/0.34a/Global/RawList.pas	(revision 200)
+++ oup/releases/0.34a/Global/RawList.pas	(revision 200)
@@ -0,0 +1,437 @@
+unit RawList;
+interface
+uses TypeDefs;
+
+type
+  THandler = function(ConnectionID, FileID: Integer): TRawDataList;
+  TRawListHandler = record
+    Ext:     String[4];
+    needed:  Boolean;
+    Handler: THandler;
+  end;
+  TRawListHandlers = array of TRawListHandler;
+
+  TRawLists = class
+    private
+      FRawListHandlers: TRawListHandlers;
+    public
+      property RawListHandlers: TRawListHandlers read FRawListHandlers;
+      procedure InsertRawListHandler(ext: String; needed: Boolean; handler: THandler);
+      function GetRawList(ConnectionID, FileID: Integer): TRawDataList;
+      function GetRawInfo(ConnectionID, FileID, DatOffset: Integer): TRawDataInfo;
+  end;
+
+
+var
+  RawLists: TRawLists;
+
+
+implementation
+
+uses
+  Template, ConnectionManager, Access_OniArchive, Classes, SysUtils, Math;
+
+
+function AGDB(ConnectionID, FileID: Integer): TRawDataList;
+var
+  link:  Integer;
+  links: Integer;
+  i:     Integer;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, 4, @links);
+  links := links * 2;
+  SetLength(Result, links);
+  for i := 0 to links - 1 do
+  begin
+    Result[i].SrcOffset := $20 + i * 4;
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * 4, 4, @link);
+    Result[i].RawAddr := link;
+    Result[i].RawSize := 32;
+    Result[i].LocSep  := False;
+  end;
+end;
+
+
+
+
+function AKVA(ConnectionID, FileID: Integer): TRawDataList;
+var
+  link:  Integer;
+  links: Integer;
+  i:     Integer;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, 4, @links);
+  SetLength(Result, links);
+  for i := 0 to links - 1 do
+  begin
+    Result[i].SrcOffset := $20 + i * $74 + $24;
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * $74 + $24, 4, @link);
+    Result[i].RawAddr := link;
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * $74 + $28, 4, @link);
+    Result[i].RawSize := link;
+    Result[i].LocSep  := False;
+  end;
+end;
+
+
+
+
+function BINA(ConnectionID, FileID: Integer): TRawDataList;
+var
+  link:     Integer;
+  datasize: Integer;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $0C, 4, @link);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, 4, @datasize);
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $0C;
+  Result[0].RawAddr   := link;
+  Result[0].RawSize   := datasize;
+  Result[0].LocSep    := not (ConManager.Connection[ConnectionID].DataOS = DOS_WIN);
+end;
+
+
+
+
+function OSBD(ConnectionID, FileID: Integer): TRawDataList;
+var
+  link:     Integer;
+  datasize: Integer;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, 4, @datasize);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $0C, 4, @link);
+  SetLength(Result, 1);
+  Result[0].SrcOffset := $0C;
+  Result[0].RawAddr   := link;
+  Result[0].RawSize   := datasize;
+  Result[0].LocSep     := not (ConManager.Connection[ConnectionID].DataOS = DOS_WIN);
+end;
+
+
+
+
+function SNDD(ConnectionID, FileID: Integer): TRawDataList;
+var
+  link:     Integer;
+  datasize: Integer;
+begin
+  SetLength(Result, 1);
+  if ConManager.Connection[ConnectionID].DataOS in [DOS_MACBETA, DOS_MAC] then
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, 4, @datasize);
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $14, 4, @link);
+    Result[0].SrcOffset := $14;
+  end
+  else
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $40, 4, @datasize);
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $44, 4, @link);
+    Result[0].SrcOffset := $44;
+  end;
+  Result[0].RawAddr := link;
+  Result[0].RawSize := datasize;
+  Result[0].LocSep  := False;
+end;
+
+
+
+
+function SUBT(ConnectionID, FileID: Integer): TRawDataList;
+var
+  baselink, lastlink: Integer;
+  links: Integer;
+  Data:  TStream;
+  read:  Integer;
+  char:  Byte;
+  foundzeros: Byte;
+begin
+  SetLength(Result, 0);
+
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, 4, @baselink);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, 4, @links);
+  if links > 0 then
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + (links - 1) * 4, 4, @lastlink);
+    Data := nil;
+    TAccess_OniArchive(ConManager.Connection[ConnectionID]).LoadRawOffset(
+          False, baselink, lastlink + 1024, Data);
+    Data.Seek(lastlink, soFromBeginning);
+
+    foundzeros := 0;
+    repeat
+      read := Data.Read(char, 1);
+      if (read > 0) and (char = 0) then
+      begin
+        Inc(foundzeros);
+      end;
+    until (read = 0) or (foundzeros = 2);
+
+    if foundzeros = 2 then
+    begin
+      SetLength(Result, 1);
+      Result[0].SrcID     := FileID;
+      Result[0].SrcOffset := $18;
+      Result[0].RawAddr   := baselink;
+      Result[0].RawSize   := Data.Position;
+      Result[0].LocSep    := False;
+    end;
+  end;
+end;
+
+
+
+
+function TRAM(ConnectionID, FileID: Integer): TRawDataList;
+var
+  i:      Integer;
+  link:   Integer;
+  frames: Word;
+  tempb:  Byte;
+  tempw:  Word;
+  templ:  Integer;
+  Data:   TByteData;
+  offset: Word;
+  frame_count: Integer;
+begin
+  SetLength(Result, 13);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $16C, 2, @frames);
+  {x-z-pos}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $0C, 4, @link);
+  Result[0].SrcOffset := $0C;
+  Result[0].RawAddr   := link;
+  if link > 0 then
+    Result[0].RawSize := frames * 4
+  else
+    Result[0].RawSize := 0;
+  {y-pos}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, 4, @link);
+  Result[1].SrcOffset := $10;
+  Result[1].RawAddr   := link;
+  if link > 0 then
+    Result[1].RawSize := frames * 8
+  else
+    Result[1].RawSize := 0;
+  {attacks}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $182, 1, @tempb);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $14, 4, @link);
+  Result[2].SrcOffset := $14;
+  Result[2].RawAddr   := link;
+  Result[2].RawSize   := tempb * 32;
+  {damage}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $183, 1, @tempb);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, 4, @link);
+  Result[3].SrcOffset := $18;
+  Result[3].RawAddr   := link;
+  Result[3].RawSize   := tempb * 8;
+  {motionblur}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $184, 1, @tempb);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, 4, @link);
+  Result[4].SrcOffset := $1C;
+  Result[4].RawAddr   := link;
+  Result[4].RawSize   := tempb * 12;
+  {shortcut}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $185, 1, @tempb);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20, 4, @link);
+  Result[5].SrcOffset := $20;
+  Result[5].RawAddr   := link;
+  Result[5].RawSize   := tempb * 8;
+  {throw}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $24, 4, @link);
+  Result[6].SrcOffset := $24;
+  Result[6].RawAddr   := link;
+  if link > 0 then
+    Result[6].RawSize := 24
+  else
+    Result[6].RawSize := 0;
+  {footstep}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $186, 1, @tempb);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $28, 4, @link);
+  Result[7].SrcOffset := $28;
+  Result[7].RawAddr   := link;
+  Result[7].RawSize   := tempb * 4;
+  {particle}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $187, 1, @tempb);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $2C, 4, @link);
+  Result[8].SrcOffset := $2C;
+  Result[8].RawAddr   := link;
+  Result[8].RawSize   := tempb * 24;
+  {position}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $30, 4, @link);
+  Result[9].SrcOffset := $30;
+  Result[9].RawAddr   := link;
+  Result[9].RawSize   := frames * 8;
+  {particle}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $154, 2, @tempw);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $38, 4, @link);
+  Result[11].SrcOffset := $38;
+  Result[11].RawAddr   := link;
+  Result[11].RawSize   := tempw * 34;
+  {extent}
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $138, 4, @templ);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $13C, 4, @link);
+  Result[12].SrcOffset := $13C;
+  Result[12].RawAddr   := link;
+  Result[12].RawSize   := templ * 12;
+
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $34, 4, @link);
+  if link > 0 then
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $160, 2, @tempw);
+    frame_count := 0;
+    i := 0;
+    SetLength(Data, $FFFF);
+    TAccess_OniArchive(ConManager.Connection[ConnectionID]).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].RawSize := offset + i;
+    end
+    else
+    begin
+      Result[10].RawSize := 0;
+    end;
+  end;
+  Result[10].SrcOffset := $34;
+  Result[10].RawAddr   := link;
+end;
+
+
+
+
+function TXMP(ConnectionID, FileID: Integer): TRawDataList;
+var
+  link_pc:   Integer;
+  link_mac:  Integer;
+  x, y:      Word;
+  storetype: Byte;
+  datasize:  Integer;
+  mipmap:    Byte;
+
+  function GetImgSize(w,h, storetype: Integer): Integer;
+  begin
+    case storetype of
+      0, 1, 2:
+        Result := w*h*2;
+      8:
+        Result := w*h*4;
+      9:
+        Result :=  Max(1, w div 4) * Max(1, h div 4) * 8;
+    else
+      Result := -1;
+    end;
+  end;
+
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, SizeOf(mipmap), @mipmap);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(x), @x);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(y), @y);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(storetype), @storetype);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, 4, @link_pc);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, 4, @link_mac);
+
+
+  datasize := GetImgSize(x, y, storetype);
+  if (mipmap and $01) > 0 then
+  begin
+    repeat
+      x    := Max(x div 2, 1);
+      y    := Max(y div 2, 1);
+      datasize := datasize + GetImgSize(x, y, storetype);
+    until (x = 1) and (y = 1);
+  end;
+
+  SetLength(Result, 1);
+  if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
+  begin
+    Result[0].SrcOffset := $9C;
+    Result[0].RawAddr   := link_pc;
+  end
+  else
+  begin
+    Result[0].SrcOffset := $A0;
+    Result[0].RawAddr   := link_mac;
+  end;
+  Result[0].RawSize := datasize;
+  Result[0].LocSep  := not (ConManager.Connection[ConnectionID].DataOS = DOS_WIN);
+end;
+
+
+
+
+function TRawLists.GetRawInfo(ConnectionID, FileID,
+  DatOffset: Integer): TRawDataInfo;
+var
+  i: Integer;
+  RawList: TRawDataList;
+begin
+  RawList          := GetRawList(ConnectionID, FileID);
+  Result.SrcID     := -1;
+  Result.SrcOffset := -1;
+  Result.RawAddr   := -1;
+  Result.RawSize   := -1;
+  if Length(RawList) > 0 then
+  begin
+    for i := 0 to High(RawList) do
+    begin
+      if RawList[i].SrcOffset = DatOffset then
+      begin
+        Result.SrcID     := FileID;
+        Result.SrcOffset := RawList[i].SrcOffset;
+        Result.RawAddr   := RawList[i].RawAddr;
+        Result.RawSize   := RawList[i].RawSize;
+        Result.LocSep    := RawList[i].LocSep;
+        Break;
+      end;
+    end;
+  end;
+end;
+
+
+function TRawLists.GetRawList(ConnectionID, FileID: Integer): TRawDataList;
+var
+  i: Integer;
+  fileinfo: TFileInfo;
+begin
+  SetLength(Result, 0);
+  fileinfo := ConManager.Connection[ConnectionID].GetFileInfo(FileID);
+  for i := 0 to High(FRawListHandlers) do
+    if UpperCase(FRawListHandlers[i].Ext) = UpperCase(fileinfo.extension) then
+    begin
+      if FRawListHandlers[i].needed then
+        Result := FRawListHandlers[i].Handler(ConnectionID, FileID);
+      Break;
+    end;
+end;
+
+procedure TRawLists.InsertRawListHandler(ext: String; needed: Boolean; handler: THandler);
+begin
+  SetLength(FRawListHandlers, Length(FRawListHandlers) + 1);
+  FRawListHandlers[High(FRawListHandlers)].Ext := ext;
+  FRawListHandlers[High(FRawListHandlers)].needed := needed;
+  FRawListHandlers[High(FRawListHandlers)].handler := handler;
+//  Raws := Raws + ext;
+  AddToolListEntry('rawedit', '', ext);
+end;
+
+
+
+
+initialization
+  RawLists := TRawLists.Create;
+  RawLists.InsertRawListHandler('AGDB', False, AGDB);
+  RawLists.InsertRawListHandler('AKVA', True, AKVA);
+  RawLists.InsertRawListHandler('BINA', True, BINA);
+  RawLists.InsertRawListHandler('OSBD', True, OSBD);
+  RawLists.InsertRawListHandler('SNDD', True, SNDD);
+  RawLists.InsertRawListHandler('SUBT', True, SUBT);
+  RawLists.InsertRawListHandler('TRAM', True, TRAM);
+  RawLists.InsertRawListHandler('TXMP', True, TXMP);
+end.
Index: oup/releases/0.34a/Global/TypeDefs.pas
===================================================================
--- oup/releases/0.34a/Global/TypeDefs.pas	(revision 200)
+++ oup/releases/0.34a/Global/TypeDefs.pas	(revision 200)
@@ -0,0 +1,155 @@
+unit TypeDefs;
+interface
+
+uses
+  Graphics, SysUtils;
+
+type
+  ENotImplemented = class(Exception);
+
+  TDataBackend = (DB_ONI, DB_ADB);
+  TDataOS = (DOS_WIN, DOS_WINDEMO, DOS_MAC, DOS_MACBETA);
+
+  TChangeRights = set of (CR_EditDat, CR_EditRaw, CR_ResizeDat, CR_ResizeRaw, CR_AppendRaw);
+
+  TStatusMessages = (
+      SM_OK,
+      SM_AlreadyOpened,
+      SM_FileNotFound,
+      SM_UnknownExtension,
+      SM_IncompatibleFile,
+      SM_IncompatibleDBVersion,
+      SM_UnknownError
+  );
+
+  TDatOSIdent = array[0..3] of Byte;
+  TDatGlobalIdent = array[0..15] of Byte;
+
+  THeader = packed record
+    OSIdent:    TDatOSIdent;
+    GlobalIdent:TDatGlobalIdent;
+    Files:      Integer;
+    NamedFiles: Integer;
+    Extensions: Integer;
+    DataAddr:   Integer;
+    DataSize:   Integer;
+    NamesAddr:  Integer;
+    NamesSize:  Integer;
+    Ident2:     array[0..$F] of Byte;
+  end;
+  TFilesMap = array of packed record
+    Extension: array[0..$3] of Char;
+    DataAddr:  Integer;
+    NameAddr:  Integer;
+    FileSize:  Integer;
+    FileType:  LongWord;
+  end;
+  TNamedFilesMap = array of packed record
+    FileNumber: Integer;
+    blubb:      Integer;
+  end;
+
+	TTypeIdent = array[0..7] of Byte;
+	TFileType = record
+		Extension: String[4];
+		StructID:  Integer;
+    Name:      String;
+		IdentWin:  TTypeIdent;
+    IdentMac:  TTypeIdent;
+	end;
+
+  TExtensionsMap = array of packed record
+      Ident:       TTypeIdent;
+      Extension:   array[0..$3] of Char;
+      ExtCount:    Integer;
+  end;
+
+  TFileInfo = packed record
+      ID:          Integer;
+      Name:        String;
+      Extension:   String[4];
+      Size:        Integer;
+      FileType:    LongWord;
+      DatAddr:     Integer;
+  end;
+  TFiles = array of TFileInfo;
+
+  TRawDataInfo = record
+      SrcID:         Integer;
+      SrcOffset:     Integer;
+      RawAddr:       Integer;
+      RawSize:       Integer;
+      LocSep:        Boolean;
+  end;
+  TRawDataList = array of TRawDataInfo;
+
+  TSortType = (
+      ST_IDAsc,
+      ST_IDDesc,
+      ST_NameAsc,
+      ST_NameDesc,
+      ST_ExtAsc,
+      ST_ExtDesc,
+      ST_ExtNameAsc,
+      ST_ExtNameDesc
+  );
+
+  TExtensionFormat = (
+      EF_ExtOnly,
+      EF_ExtCount
+  );
+
+  TByteData = array of Byte; 
+
+  TAppSettings = record
+      DatPath:        String[250];
+      ExtractPath:    String[250];
+      CharSet:        TFontCharSet;
+      HideUnusedData: Boolean;
+  end;
+
+  TToolList = array of record
+      context: String;
+      name: String;
+      exts: String;
+  end;
+
+
+  TLinkByName = record
+      SrcOffset: Integer;
+      Destination: String;
+  end;
+  TLinkByID = record
+      SrcOffset: Integer;
+      Destination: Integer;
+  end;
+  TLinks = record
+      ByName: array of TLinkByName;
+      ByID: array of TLinkByID;
+  end;
+
+  TDatLink = record
+      SrcOffset: Integer;
+      DestID:    Integer;
+      PosDestExts:   String;
+  end;
+  TDatLinkList = array of TDatLink;
+ 
+{
+  TLevelInfo = record
+    Ident: array[0..$13] of Byte;
+    LevelNumber: Byte;
+  end;
+
+ TDatLinks = array of record
+    Src_Offset: Integer;
+    Target:     Integer;
+  end;
+}
+
+const
+  CrLf: String[2] = #13#10;
+
+implementation
+
+end.
Index: oup/releases/0.34a/Helper/LevelDB.dfm
===================================================================
--- oup/releases/0.34a/Helper/LevelDB.dfm	(revision 200)
+++ oup/releases/0.34a/Helper/LevelDB.dfm	(revision 200)
@@ -0,0 +1,61 @@
+object Form_LevelDB: TForm_LevelDB
+  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.34a/Helper/LevelDB.pas
===================================================================
--- oup/releases/0.34a/Helper/LevelDB.pas	(revision 200)
+++ oup/releases/0.34a/Helper/LevelDB.pas	(revision 200)
@@ -0,0 +1,766 @@
+unit LevelDB;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ComCtrls, StdCtrls, StrUtils;
+
+type
+  TForm_LevelDB = class(TForm)
+    group_progress: TGroupBox;
+    progress:     TProgressBar;
+    lbl_progress: TLabel;
+    btn_abortok:  TButton;
+    lbl_estimation: TLabel;
+    procedure btn_abortokClick(Sender: TObject);
+  public
+    procedure CreateDatabase(Source, Target: String);
+    procedure CreateLevel(Source, Target: String);
+  end;
+
+
+var
+  Form_LevelDB: TForm_LevelDB;
+
+implementation
+{$R *.dfm}
+uses ABSMain, ABSDecUtil, Main,
+    ConnectionManager, TypeDefs, DataAccess, OniImgClass, Data, RawList, 
+  Access_OniArchive;
+
+var
+  Converting:  Boolean = False;
+  Abort:       Boolean = False;
+
+
+function GetOpenMsg(msg: TStatusMessages): String;
+begin
+  case msg of
+    SM_AlreadyOpened:    Result := 'File already opened.';
+    SM_FileNotFound:     Result := 'File not found.';
+    SM_UnknownExtension: Result := 'Unknown extension.';
+    SM_IncompatibleFile: Result := 'Incompatible file format.';
+    SM_UnknownError:     Result := 'Unknown error.';
+  end;
+end;
+
+
+procedure TForm_LevelDB.CreateLevel(Source, Target: String);
+const
+  EmptyBytes: Array[0..31] of Byte = (
+      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,0,0,0,0,0,0,0 );
+var
+  DatHeader:        THeader;
+  FilesHeader:      TFilesMap;
+  NamedFilesHeader: TNamedFilesMap;
+  ExtensionsHeader: TExtensionsMap;
+
+  Stream_Body, Stream_Names:          TMemoryStream;
+  Stream_Dat, Stream_Raw, Stream_Sep: TFileStream;
+
+  BeginTime, FileTime: Double;
+  Step:     Integer;
+  LevelID:    Integer;
+  TimeFormat: TFormatSettings;
+
+  ConID:      Integer;
+  Connection: TDataAccess;
+  ConRepMsg:  TStatusMessages;
+
+  FileID:     Integer;
+
+  Strings:    TStrings;
+  i, j:       Integer;
+  temps:      String;
+  tempi:      Integer;
+  tempb:      Byte;
+  FileInfo:   TFileInfo;
+  DatLinks:   TDatLinkList;
+  RawLinks:   TRawDataList;
+
+  DatFileStream, RawFileStream: TMemoryStream;
+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;
+
+  procedure StopConvert;
+  begin
+    btn_abortok.Caption := '&Close';
+    btn_abortok.Default := True;
+    converting := False;
+    lbl_estimation.Caption := 'ABORTED';
+    group_progress.Caption := 'Creating Level (ABORTED)';
+
+    Stream_Body.Free;
+    Stream_Names.Free;
+    DatFileStream.Free;
+    RawFileStream.Free;
+    
+    Stream_Dat.Free;
+    Stream_Raw.Free;
+    if Connection.DataOS in [DOS_WINDEMO, DOS_MAC, DOS_MACBETA] then
+      Stream_Sep.Free;
+    
+    if MessageBox(Self.Handle, PChar('Delete the unfinished level-files?'),
+      PChar('Delete files?'), MB_YESNO) = idYes then
+    begin
+      DeleteFile(target);
+      DeleteFile(AnsiReplaceStr(Target, '.dat', '.raw'));
+      if Connection.DataOS in [DOS_WINDEMO, DOS_MAC, DOS_MACBETA] then
+        DeleteFile(AnsiReplaceStr(Target, '.dat', '.sep'));
+    end;
+  end;
+
+begin
+
+  //
+  // FILE EXISTS CHECK FÜR DAT/RAW/SEP!!!
+  //
+
+  TimeFormat.ShortTimeFormat := 'hh:nn:ss';
+  TimeFormat.LongTimeFormat  := 'hh:nn:ss';
+  TimeFormat.TimeSeparator   := ':';
+
+  ConID := ConManager.OpenConnection(Source, ConRepMsg);
+  if not (ConRepMsg in [SM_OK, SM_AlreadyOpened]) then
+  begin
+    ShowMessage('Source-file couldn''t be opened! Aborting' + CrLf + GetOpenMsg(ConRepMsg));
+    Exit;
+  end else
+    Connection := ConManager.Connection[ConID];
+
+  ConID := ConManager.FileOpened(Target);
+  if ConID >= 0 then
+  begin
+    if MessageBox(Self.Handle, PChar('Destination-file is opened, close it in ' +
+          'order to proceed conversion?'), PChar('Destination-file opened'),
+          MB_YESNO + MB_ICONQUESTION) = ID_YES then
+    begin
+      if Form_Main.CheckConnectionCloseable(ConID) then
+        if not ConManager.CloseConnection(ConID, ConRepMsg) then
+        begin
+          ShowMessage('Couldn''t close destination-file. Aborting');
+          Exit;
+        end;
+    end else begin
+      ShowMessage('Aborting');
+      Exit;
+    end;
+  end;
+
+  if FileExists(Target) then
+  begin
+    if MessageBox(Self.Handle, PChar('Destination-file exists. ' +
+          'Overwrite it?'), PChar('Destination-file exists'),
+          MB_YESNO + MB_ICONWARNING) = ID_YES then
+    begin
+      if not DeleteFile(Target) then
+      begin
+        ShowMessage('Couldn''t delete file. Aborting');
+        Exit;
+      end;
+      if FileExists(AnsiReplaceStr(Target, '.dat', '.raw')) then
+        if not DeleteFile(AnsiReplaceStr(Target, '.dat', '.raw')) then
+        begin
+          ShowMessage('Couldn''t delete file. Aborting');
+          Exit;
+        end;
+      if FileExists(AnsiReplaceStr(Target, '.dat', '.sep')) then
+        if Connection.DataOS in [DOS_WINDEMO, DOS_MAC, DOS_MACBETA] then
+          if not DeleteFile(AnsiReplaceStr(Target, '.dat', '.sep')) then
+          begin
+            ShowMessage('Couldn''t delete file. Aborting');
+            Exit;
+          end;
+    end else begin
+      ShowMessage('Aborting');
+      Exit;
+    end;
+  end;
+
+  LevelID  := Connection.LevelNumber;
+  LevelID  := (LevelID * 2) * 256 * 256 * 256 + $01;
+
+  Self.Visible := True;
+  Form_Main.Visible := False;
+  Step := 0;
+  Converting := True;
+  Abort := False;
+  btn_abortok.Caption := '&Abort...';
+  btn_abortok.Default := False;
+  BeginTime := Time;
+
+  Stream_Body  := TMemoryStream.Create;
+  Stream_Names := TMemoryStream.Create;
+  Stream_Dat   := TFileStream.Create(Target, fmCreate);
+  Stream_Raw   := TFileStream.Create(AnsiReplaceStr(Target, '.dat', '.raw'), fmCreate);
+  Stream_Raw.Write(EmptyBytes[0], 32);
+  if Connection.DataOS in [DOS_WINDEMO, DOS_MAC, DOS_MACBETA] then
+  begin
+    Stream_Sep := TFileStream.Create(AnsiReplaceStr(Target, '.dat', '.sep'), fmCreate);
+    Stream_Sep.Write(EmptyBytes[0], 32);
+  end;
+
+
+  DoStep('Creating header');
+  progress.Position      := 0;
+  lbl_progress.Caption   := '';
+  lbl_estimation.Caption := 'Estimated finishing time: unknown';
+  Application.ProcessMessages;
+
+  SetLength(NamedFilesHeader, 0);
+  Strings := TStringList.Create;
+  Strings := Connection.GetFilesList('', '', False, ST_ExtNameAsc);
+  for i := 0 to Strings.Count - 1 do
+  begin
+    if MidStr(Strings.Strings[i],
+          Pos('-', Strings.Strings[i]) + 1,
+          Length(Strings.Strings[i]) -
+            Pos('.', ReverseString(Strings.Strings[i])) -
+            Pos('-', Strings.Strings[i])
+        ) <> '' then
+    begin
+      SetLength(NamedFilesHeader, Length(NamedFilesHeader) + 1);
+      NamedFilesHeader[High(NamedFilesHeader)].FileNumber := StrToInt(MidStr(Strings.Strings[i], 1, 5));
+      NamedFilesHeader[High(NamedFilesHeader)].blubb := 0;
+    end;
+  end;
+
+  for i := 0 to High(DatHeader.OSIdent) do
+    case Connection.DataOS of
+      DOS_WIN: DatHeader.OSIdent[i] := HeaderOSIdentWin[i];
+      DOS_MAC, DOS_WINDEMO: DatHeader.OSIdent[i] := HeaderOSIdentMac[i];
+      DOS_MACBETA: DatHeader.OSIdent[i] := HeaderOSIdentMacBeta[i];
+    end;
+  for i := 0 to High(DatHeader.GlobalIdent) do
+    DatHeader.GlobalIdent[i] := HeaderGlobalIdent[i];
+  DatHeader.Files := Connection.GetFileCount;
+  DatHeader.NamedFiles := Length(NamedFilesHeader);
+
+  Strings := Connection.GetExtensionsList(EF_ExtCount);
+
+  DatHeader.Extensions := Strings.Count;
+  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 := Strings.Count;
+  Application.ProcessMessages;
+  for i := 0 to Strings.Count - 1 do
+  begin
+    temps := Strings.Strings[i];
+    ExtensionsHeader[i].ExtCount := StrToInt( MidStr(
+            temps,
+            Pos('(', temps) + 1,
+            Pos(')', temps) - Pos('(', temps) - 1 ) );
+    temps := MidStr(temps, 1, 4);
+    for j := 0 to 3 do
+      ExtensionsHeader[i].Extension[j] := temps[4-j];
+    for j := 0 to High(FileTypes) do
+      if FileTypes[j].Extension = temps then
+        Break;
+    if j < Length(FileTypes) then
+    begin
+      case Connection.DataOS of
+        DOS_WIN:     ExtensionsHeader[i].Ident := FileTypes[j].IdentWin;
+        DOS_WINDEMO:
+            if FileTypes[j].Extension = 'SNDD' then
+              ExtensionsHeader[i].Ident := FileTypes[j].IdentWin
+            else
+              ExtensionsHeader[i].Ident := FileTypes[j].IdentMac;
+        DOS_MAC:     ExtensionsHeader[i].Ident := FileTypes[j].IdentMac;
+        DOS_MACBETA: ExtensionsHeader[i].Ident := FileTypes[j].IdentMac;
+      end;
+    end else begin
+      ShowMessage('Unknown Extension: ' + Strings.Strings[i]);
+      Exit;
+    end;
+    progress.Position    := i + 1;
+    lbl_progress.Caption := 'Extensions done: ' + IntToStr(i + 1) + '/' +
+      IntToStr(Strings.Count);
+    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;
+
+  FileTime := Time;
+  for FileID := 0 to DatHeader.Files - 1 do
+  begin
+    FileInfo := Connection.GetFileInfo(FileID);
+    for j := 0 to 3 do
+      FilesHeader[FileID].Extension[j] := FileInfo.Extension[4 - j];
+    if FileInfo.Size > 0 then
+    begin
+      FilesHeader[FileID].DataAddr := Stream_Body.Size + 8;
+      DatFileStream := TMemoryStream.Create;
+      Connection.LoadDatFile(FileID, TStream(DatFileStream));
+      DatFileStream.Seek(0, soFromBeginning);
+      tempi := FileID * 256 + 1;
+      DatFileStream.Write(tempi, 4);
+      DatFileStream.Write(LevelID, 4);
+
+      DatLinks := Connection.GetDatLinks(FileID);
+      if Length(DatLinks) > 0 then
+      begin
+        for i := 0 to High(DatLinks) do
+        begin
+          DatFileStream.Seek(DatLinks[i].SrcOffset, soFromBeginning);
+          if DatLinks[i].DestID < 0 then
+            tempi := 0
+          else
+            tempi := DatLinks[i].DestID * 256 + 1;
+          DatFileStream.Write(tempi, 4);
+        end;
+      end;
+
+      RawLinks := Connection.GetRawList(FileID);
+      if Length(RawLinks) > 0 then
+      begin
+        for i := 0 to High(RawLinks) do
+        begin
+          if RawLinks[i].RawSize > 0 then
+          begin
+            RawFileStream := TMemoryStream.Create;
+            Connection.LoadRawFile(FileID, RawLinks[i].SrcOffset, TStream(RawFileStream));
+            RawFileStream.Seek(0, soFromBeginning);
+            if RawLinks[i].LocSep then
+            begin
+              RawLinks[i].RawAddr := Stream_Sep.Size;
+              Stream_sep.CopyFrom(RawFileStream, RawFileStream.Size);
+              if (Stream_Sep.Size mod 32) > 0 then
+                Stream_Sep.Write(EmptyBytes[0], 32 - (Stream_Sep.Size mod 32));
+            end else begin
+              RawLinks[i].RawAddr := Stream_Raw.Size;
+              Stream_Raw.CopyFrom(RawFileStream, RawFileStream.Size);
+              if (Stream_Raw.Size mod 32) > 0 then
+                Stream_Raw.Write(EmptyBytes[0], 32 - (Stream_Raw.Size mod 32));
+            end;
+          end else
+            RawLinks[i].RawAddr := 0;
+          DatFileStream.Seek(RawLinks[i].SrcOffset, soFromBeginning);
+          DatFileStream.Write(RawLinks[i].RawAddr, 4);
+        end;
+      end;
+      DatFileStream.Seek(0, soFromBeginning);
+      Stream_Body.CopyFrom(DatFileStream, DatFileStream.Size);
+      if (Stream_Body.Size mod 32) > 0 then
+      begin
+        ShowMessage(
+            IntToStr(FileID) + '-' + FileInfo.Name + '.' + FileInfo.Extension + #13#10 +
+            IntToStr(FileInfo.Size) + ' - 0x' + IntToHex(FileInfo.Size, 6) + ' - real: ' + IntToStr(DatFileStream.Size) + ' - 0x' + IntToHex(DatFileStream.Size, 6) + #13#10 +
+            IntToStr(Stream_Body.Size) + ' - 0x' + IntToHex(Stream_Body.Size, 6) );
+        Stream_Body.Write(EmptyBytes[0], 32 - (Stream_Body.Size mod 32));
+      end;
+    end
+    else
+      FilesHeader[FileID].DataAddr := 0;
+    if Length(fileinfo.Name) > 0 then
+    begin
+      FilesHeader[FileID].NameAddr := Stream_Names.Size;
+      temps := fileinfo.Extension + fileinfo.Name + Chr(0);
+      Stream_Names.Write(temps[1], Length(temps));
+    end
+    else
+      FilesHeader[FileID].NameAddr := 0;
+    FilesHeader[FileID].FileSize := fileinfo.Size;
+    FilesHeader[FileID].FileType := fileinfo.FileType;
+
+    if ((FileID mod 10) = 0) and (FileID >= 100) then
+      lbl_estimation.Caption := 'Estimated time left: ' + TimeToStr(
+        (Time - FileTime) / FileID * (progress.Max - FileID + 1) * 1.1, TimeFormat );
+    progress.Position := FileID + 1;
+    lbl_progress.Caption := 'Files done: ' + IntToStr(FileID + 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]));
+
+  if (Stream_Dat.Size mod 32) > 0 then
+    Stream_Dat.Write(EmptyBytes[0], 32 - (Stream_Dat.Size mod 32));
+
+  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);
+
+  if (Stream_Dat.Size mod 32) > 0 then
+    Stream_Dat.Write(EmptyBytes[0], 32 - (Stream_Dat.Size mod 32));
+
+  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 Connection.DataOS in [DOS_WINDEMO, DOS_MAC, DOS_MACBETA] 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 - Begintime, TimeFormat) + ')';
+
+  DoStep('FIN');
+  btn_abortok.Caption := '&OK';
+  btn_abortok.Default := True;
+
+  converting := False;
+
+//  CloseDataConnection(DataConnections[conIndex]);
+end;
+
+
+
+
+procedure TForm_LevelDB.CreateDatabase(Source, target: String);
+var
+  DataBase:  TABSDatabase;
+  Query:     TABSQuery;
+  MimeCoder: TStringFormat_MIME64;
+
+  BeginTime, FileTime: Double;
+  Step:       Integer;
+  TimeFormat: TFormatSettings;
+
+  ConID:      Integer;
+  Connection: TDataAccess;
+  ConRepMsg:  TStatusMessages;
+
+  FileID:     Integer;
+
+  i:          Integer;
+  temps:      String;
+  tempdata:   TByteData;
+  FileInfo:   TFileInfo;
+  DatLinks:   TDatLinkList;
+  RawLinks:   TRawDataList;
+const
+  steps: Byte = 2;
+
+  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;
+
+  procedure StopConvert;
+  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(target);
+    end;
+  end;
+
+
+
+begin
+
+  //
+  // FILE EXISTS CHECK FÜR DAT/RAW/SEP!!!
+  //
+
+  TimeFormat.ShortTimeFormat := 'hh:nn:ss';
+  TimeFormat.LongTimeFormat  := 'hh:nn:ss';
+  TimeFormat.TimeSeparator   := ':';
+
+  ConID := ConManager.OpenConnection(Source, ConRepMsg);
+  if not (ConRepMsg in [SM_OK, SM_AlreadyOpened]) then
+  begin
+    ShowMessage('Source-file couldn''t be opened! Aborting' + CrLf + GetOpenMsg(ConRepMsg));
+    Exit;
+  end else
+    Connection := ConManager.Connection[ConID];
+
+  ConID := ConManager.FileOpened(Target);
+  if ConID >= 0 then
+  begin
+    if MessageBox(Self.Handle, PChar('Destination-file is opened, close it in ' +
+          'order to proceed conversion?'), PChar('Destination-file opened'),
+          MB_YESNO + MB_ICONQUESTION) = ID_YES then
+    begin
+      if Form_Main.CheckConnectionCloseable(ConID) then
+        if not ConManager.CloseConnection(ConID, ConRepMsg) then
+        begin
+          ShowMessage('Couldn''t close destination-file. Aborting');
+          Exit;
+        end;
+    end else begin
+      ShowMessage('Aborting');
+      Exit;
+    end;
+  end;
+
+  if FileExists(Target) then
+  begin
+    if MessageBox(Self.Handle, PChar('Destination-file exists. ' +
+          'Overwrite it?'), PChar('Destination-file exists'),
+          MB_YESNO + MB_ICONWARNING) = ID_YES then
+    begin
+      if not DeleteFile(Target) then
+      begin
+        ShowMessage('Couldn''t delete file. Aborting');
+        Exit;
+      end;
+    end else begin
+      ShowMessage('Aborting');
+      Exit;
+    end;
+  end;
+
+  Self.Visible := True;
+  Form_Main.Visible := False;
+  step  := 0;
+  converting := True;
+  abort := False;
+  btn_abortok.Caption := '&Abort...';
+  btn_abortok.Default := False;
+
+  BeginTime := Time;
+
+  DataBase := TABSDatabase.Create(Self);
+  DataBase.MaxConnections := 1;
+  DataBase.PageSize := 8112;
+  DataBase.PageCountInExtent := 8;
+
+  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 INDEX idsrcid ON linkmap (src_id);';
+  Query.ExecSQL;
+  Query.SQL.Text := 'CREATE INDEX idtargetid ON linkmap (target_id);';
+  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 INDEX idsrcid ON rawmap (src_id);';
+  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;
+
+  Query.SQL.Text := 'INSERT INTO globals (name,value) VALUES ("lvl","' +
+    IntToStr(Connection.LevelNumber) + '");';
+  Query.ExecSQL;
+  case Connection.DataOS of
+    DOS_WIN: temps := 'WIN';
+    DOS_WINDEMO: temps := 'WINDEMO';
+    DOS_MAC: temps := 'MAC';
+    DOS_MACBETA: temps := 'MACBETA';
+  end;
+  Query.SQL.Text := 'INSERT INTO globals (name,value) VALUES ("os","' + temps + '");';
+  Query.ExecSQL;
+
+  progress.Position      := 0;
+  lbl_progress.Caption   := 'Files done: ' + IntToStr(0) + '/' + IntToStr(
+    Connection.GetFileCount);
+  lbl_estimation.Caption := 'Estimated finishing time: unknown';
+
+  progress.Max := Connection.GetFileCount;
+  begintime    := Time;
+  DoStep('Writing .dat-fileslist');
+  Application.ProcessMessages;
+
+  TAccess_OniArchive(Connection).UnloadWhenUnused := False;
+
+  FileTime := Time;
+  Database.StartTransaction;
+  for FileID := 0 to Connection.GetFileCount - 1 do
+  begin
+    fileinfo := Connection.GetFileInfo(FileID);
+    if (fileinfo.FileType and $02) = 0 then
+    begin
+      mimecoder := TStringFormat_MIME64.Create;
+      Connection.LoadDatFile(FileID, tempdata);
+      Query.SQL.Text :=
+        'INSERT INTO datfiles (id,extension,name,contenttype,size,data) VALUES (' +
+        IntToStr(FileID) + ',"' + fileinfo.Extension + '","' + fileinfo.Name + '","' + IntToHex(
+        fileinfo.FileType, 8) + '",' + IntToStr(fileinfo.Size) + ',MimeToBin("' +
+        MimeCoder.StrTo(@tempdata[0], Length(tempdata)) + '") );';
+      Query.ExecSQL;
+      mimecoder.Free;
+
+      RawLinks := Connection.GetRawList(FileID);
+      if Length(RawLinks) > 0 then
+      begin
+        for i := 0 to High(RawLinks) do
+        begin
+          if RawLinks[i].RawSize > 0 then
+          begin
+            SetLength(tempdata, RawLinks[i].RawSize);
+            Connection.LoadRawFile(FileID, RawLinks[i].SrcOffset, tempdata);
+            mimecoder      := TStringFormat_MIME64.Create;
+            Query.SQL.Text :=
+              'INSERT INTO rawmap (src_id,src_link_offset,sep,size,data) VALUES (' +
+              IntToStr(FileID) + ', ' + IntToStr(RawLinks[i].SrcOffset) + ',' +
+              BoolToStr(RawLinks[i].LocSep) + ', ' +
+              IntToStr(RawLinks[i].RawSize) + ', ' +
+              'MimeToBin("' + MimeCoder.StrTo(@tempdata[0], RawLinks[i].RawSize) + '") );';
+            Query.ExecSQL;
+            mimecoder.Free;
+          end
+          else
+          begin
+            Query.SQL.Text :=
+              'INSERT INTO rawmap (src_id,src_link_offset,sep,size) VALUES (' +
+              IntToStr(FileID) + ', ' + IntToStr(RawLinks[i].SrcOffset) + ', ' +
+              BoolToStr(RawLinks[i].LocSep) + ', 0);';
+            Query.ExecSQL;
+          end;
+        end;
+      end;
+
+      DatLinks := Connection.GetDatLinks(FileID);
+      if Length(DatLinks) > 0 then
+      begin
+        for i := 0 to High(DatLinks) do
+        begin
+          Query.SQL.Text :=
+            'INSERT INTO linkmap (src_id, src_link_offset, target_id) VALUES (' +
+            IntToStr(FileID) + ', ' + IntToStr(DatLinks[i].SrcOffset) + ', ' +
+            IntToStr(DatLinks[i].DestID) + ');';
+          Query.ExecSQL;
+        end;
+      end;
+    end
+    else
+    begin
+      Query.SQL.Text :=
+        'INSERT INTO datfiles (id,extension,name,contenttype,size) VALUES (' +
+        IntToStr(FileID) + ', "' + fileinfo.Extension + '", ' +
+        '"' + fileinfo.Name + '", "' + IntToHex(fileinfo.FileType, 8) + '", 0);';
+      Query.ExecSQL;
+    end;
+    if ((FileID mod 100) = 0) and (FileID > 0) then
+    begin
+      Database.Commit(False);
+      Database.StartTransaction;
+    end;
+    if ((FileID mod 10) = 0) and (FileID >= 100) then
+      lbl_estimation.Caption := 'Estimated time left: ' + TimeToStr(
+        (Time - FileTime) / FileID * (progress.Max - FileID + 1) * 1.1, timeformat );
+    progress.Position := FileID;
+    lbl_progress.Caption := 'Files done: ' + IntToStr(FileID) + '/' + IntToStr(progress.Max);
+    Application.ProcessMessages;
+    if abort then
+    begin
+      StopConvert;
+      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 - BeginTime, timeformat) + ')';
+
+  DoStep('FIN');
+  btn_abortok.Caption := '&OK';
+  btn_abortok.Default := True;
+
+  converting := False;
+  TAccess_OniArchive(Connection).UnloadWhenUnused := True;
+
+  Query.Close;
+  Query.Free;
+  DataBase.Close;
+  DataBase.Free;
+end;
+
+
+
+
+procedure TForm_LevelDB.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
+    Self.Visible := False;
+    Form_Main.Visible  := True;
+  end;
+end;
+
+
+end.
Index: oup/releases/0.34a/Helper/ValueEdit.dfm
===================================================================
--- oup/releases/0.34a/Helper/ValueEdit.dfm	(revision 200)
+++ oup/releases/0.34a/Helper/ValueEdit.dfm	(revision 200)
@@ -0,0 +1,123 @@
+object Form_ValueEdit: TForm_ValueEdit
+  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
+  OnCreate = FormCreate
+  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
+  end
+end
Index: oup/releases/0.34a/Helper/ValueEdit.pas
===================================================================
--- oup/releases/0.34a/Helper/ValueEdit.pas	(revision 200)
+++ oup/releases/0.34a/Helper/ValueEdit.pas	(revision 200)
@@ -0,0 +1,185 @@
+unit ValueEdit;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, CrossEdit, Math;
+
+type
+  TForm_ValueEdit = 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;
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure MakeVarInput(objectname: String; offset: Integer;
+      datatype: Word; current: String; caller: TObject);
+    procedure FormCreate(Sender: TObject);
+  private
+  public
+    edit_new:   TCrossEdit;
+  end;
+
+var
+  Form_ValueEdit: TForm_ValueEdit;
+
+
+implementation
+
+uses BinEdit, RawEdit, DatStructureLoader, Main;
+
+{$R *.dfm}
+
+var
+  caller_win_dat: TForm_BinEdit;
+  caller_win_raw: TForm_RawEdit;
+  _datatype: Word;
+  _offset: Integer;
+
+
+
+
+procedure TForm_ValueEdit.MakeVarInput(objectname: String; offset: Integer;
+  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 := TForm_RawEdit(caller)
+  else
+    caller_win_dat := TForm_BinEdit(caller);
+  Form_Main.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.MaxLength := 0;
+  edit_new.Max := 0;
+  edit_new.BorderStyle := bsSingle;
+  Self.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;
+      Self.Width := 700;
+    end;
+  end;
+  edit_new.Text := current;
+  edit_new.SetFocus;
+  edit_new.SelectAll;
+end;
+
+
+
+
+procedure TForm_ValueEdit.btn_okClick(Sender: TObject);
+begin
+  if not edit_new.NoValidValue then
+  begin
+    Form_Main.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 TForm_ValueEdit.FormCreate(Sender: TObject);
+begin
+  DecimalSeparator := '.';
+  edit_new := TCrossEdit.Create(Self);
+  with edit_new do
+  begin
+    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 := 14;
+    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;
+  Self.InsertControl(edit_new);
+end;
+
+procedure TForm_ValueEdit.btn_cancelClick(Sender: TObject);
+begin
+  Form_Main.Enabled := True;
+  Self.Visible  := False;
+end;
+
+end.
Index: oup/releases/0.34a/Helper/WhatLinksHere.dfm
===================================================================
--- oup/releases/0.34a/Helper/WhatLinksHere.dfm	(revision 200)
+++ oup/releases/0.34a/Helper/WhatLinksHere.dfm	(revision 200)
@@ -0,0 +1,124 @@
+object Form_WhatLinksHere: TForm_WhatLinksHere
+  Left = 0
+  Top = 0
+  BorderStyle = bsSizeToolWin
+  Caption = 'What links here?'
+  ClientHeight = 232
+  ClientWidth = 404
+  Color = clBtnFace
+  Constraints.MinHeight = 232
+  Constraints.MinWidth = 275
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 0
+    Top = 100
+    Width = 404
+    Height = 8
+    Cursor = crVSplit
+    Align = alTop
+    AutoSnap = False
+    Beveled = True
+    MinSize = 100
+    ExplicitTop = 171
+    ExplicitWidth = 655
+  end
+  object Panel1: TPanel
+    Left = 0
+    Top = 0
+    Width = 404
+    Height = 100
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 0
+    ExplicitWidth = 267
+    object label_what: TLabel
+      AlignWithMargins = True
+      Left = 3
+      Top = 3
+      Width = 398
+      Height = 16
+      Align = alTop
+      AutoSize = False
+      Caption = 'What links to:'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = [fsBold]
+      ParentFont = False
+      ExplicitLeft = 10
+      ExplicitTop = 11
+      ExplicitWidth = 415
+    end
+    object list_from: TListBox
+      AlignWithMargins = True
+      Left = 3
+      Top = 25
+      Width = 398
+      Height = 72
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnDblClick = list_fromDblClick
+      ExplicitLeft = 38
+      ExplicitTop = 65
+      ExplicitWidth = 415
+      ExplicitHeight = 84
+    end
+  end
+  object Panel2: TPanel
+    Left = 0
+    Top = 108
+    Width = 404
+    Height = 124
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 1
+    ExplicitLeft = 28
+    ExplicitTop = 212
+    ExplicitWidth = 337
+    ExplicitHeight = 169
+    object label_to: TLabel
+      AlignWithMargins = True
+      Left = 3
+      Top = 3
+      Width = 398
+      Height = 16
+      Align = alTop
+      AutoSize = False
+      Caption = 'File links to:'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = [fsBold]
+      ParentFont = False
+      ExplicitLeft = 6
+      ExplicitWidth = 179
+    end
+    object list_to: TListBox
+      AlignWithMargins = True
+      Left = 3
+      Top = 25
+      Width = 398
+      Height = 96
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnDblClick = list_fromDblClick
+      ExplicitLeft = -230
+      ExplicitTop = -43
+      ExplicitWidth = 415
+      ExplicitHeight = 84
+    end
+  end
+end
Index: oup/releases/0.34a/Helper/WhatLinksHere.pas
===================================================================
--- oup/releases/0.34a/Helper/WhatLinksHere.pas	(revision 200)
+++ oup/releases/0.34a/Helper/WhatLinksHere.pas	(revision 200)
@@ -0,0 +1,100 @@
+unit WhatLinksHere;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, Template, ExtCtrls;
+
+type
+  TForm_WhatLinksHere = class(TForm)
+    Panel1: TPanel;
+    list_from: TListBox;
+    label_what: TLabel;
+    Panel2: TPanel;
+    label_to: TLabel;
+    list_to: TListBox;
+    Splitter1: TSplitter;
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    procedure list_fromDblClick(Sender: TObject);
+  private
+  public
+    SenderForm: TForm_ToolTemplate;
+    ConID: Integer;
+    FileID: Integer;
+  end;
+
+var
+  Form_WhatLinksHere: TForm_WhatLinksHere;
+
+implementation
+{$R *.dfm}
+uses ConnectionManager, Access_OUP_ADB, TypeDefs, Functions, Main;
+
+{ TForm_WhatLinksHere }
+
+procedure TForm_WhatLinksHere.FormCloseQuery(Sender: TObject;
+  var CanClose: Boolean);
+begin
+  Form_Main.Enabled := True;
+  Visible := False;
+  CanClose := False;
+end;
+
+procedure TForm_WhatLinksHere.FormShow(Sender: TObject);
+var
+  fileinfo: TFileInfo;
+  links: TLinks;
+  i: Integer;
+  fullname: String;
+  links_to: TDatLinkList;
+begin
+  Form_Main.Enabled := False;
+  list_from.Items.Clear;
+  list_to.Items.Clear;
+  fileinfo := ConManager.Connection[ConID].GetFileInfo(FileID);
+  label_what.Caption := FormatNumber(fileinfo.ID, 5, '0') + '-' +
+      fileinfo.Name + '.' + fileinfo.Extension;
+  links_to := ConManager.Connection[ConID].GetDatLinks(fileinfo.ID);
+  if ConManager.Connection[ConID] is TAccess_OUP_ADB then begin
+    links := TAccess_OUP_ADB(ConManager.Connection[ConID]).GetLinksToFile(fileinfo.ID);
+    if Length(links.ByID) > 0 then
+      for i := 0 to High(links.ByID) do
+      begin
+        fileinfo := ConManager.Connection[ConID].GetFileInfo(links.ByID[i].Destination);
+        fullname := FormatNumber(fileinfo.ID, 5, '0') + '-' + fileinfo.Name + '.' + fileinfo.Extension;
+        list_from.Items.Add(fullname + ' (Offset 0x' + IntToHex(links.ByID[i].SrcOffset, 8) + ')');
+      end;
+  end;
+  if Length(links_to) > 0 then
+  begin
+    for i := 0 to High(links_to) do
+    begin
+      if links_to[i].DestID >= 0 then
+      begin
+        fileinfo := ConManager.Connection[ConID].GetFileInfo(links_to[i].DestID);
+        fullname := FormatNumber(fileinfo.ID, 5, '0') + '-' + fileinfo.Name + '.' + fileinfo.Extension;
+      end else
+        fullname := 'no link';
+      list_to.Items.Add(fullname + ' (Offset 0x' + IntToHex(links_to[i].SrcOffset, 8) + ')');
+    end;
+  end;
+end;
+
+procedure TForm_WhatLinksHere.list_fromDblClick(Sender: TObject);
+var
+  id: Integer;
+  box: TListBox;
+  name: String;
+begin
+  box := TListBox(Sender);
+  name := box.Items.Strings[box.ItemIndex];
+  if Pos('no link', name) > 0 then
+    Exit
+  else
+    id := ConManager.Connection[ConID].ExtractFileIDOfName(name);
+  SenderForm.SelectFileID(ConID, id);
+  Form_Main.Enabled := True;
+  Visible := False;
+end;
+
+end.
Index: oup/releases/0.34a/ImportedStuff/FTypeReg.pas
===================================================================
--- oup/releases/0.34a/ImportedStuff/FTypeReg.pas	(revision 200)
+++ oup/releases/0.34a/ImportedStuff/FTypeReg.pas	(revision 200)
@@ -0,0 +1,625 @@
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse (Win32-API)
+// Copyright (c) 2004 Mathias Simmack
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * erste Version
+//
+// -----------------------------------------------------------------------------
+unit FTypeReg;
+
+interface
+
+uses
+  Windows, ShlObj, SysUtils;
+
+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}
+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;
+
+
+// -----------------------------------------------------------------------------
+//
+// 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.34a/ImportedStuff/FolderBrowser.pas
===================================================================
--- oup/releases/0.34a/ImportedStuff/FolderBrowser.pas	(revision 200)
+++ oup/releases/0.34a/ImportedStuff/FolderBrowser.pas	(revision 200)
@@ -0,0 +1,549 @@
+// -----------------------------------------------------------------------------
+//
+// TFolderBrowser-Klasse
+// Copyright (c) 2003-2005 Delphi-Forum
+// Tino, Popov, Christian Stelzman (PL), Luckie, Aton, Mathias Simmack (msi)
+//
+// basiert auf den folgenden Beiträgen
+//   - http://www.delphi-forum.de/viewtopic.php?t=11240
+//   - http://www.delphi-forum.de/viewtopic.php?t=21471
+//   * http://www.delphi-forum.de/viewtopic.php?t=25302
+//   - http://www.delphi-forum.de/viewtopic.php?t=27010&start=0
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * ursprüngliche Version von PL (s. Link #3)
+//   * Fehlerkorrekturen von Luckie
+//       - Result bei Callback ergänzt
+//       - Properties als private deklariert
+//       - Bugs in "Execute"-Methode behoben
+//   * Dateifilter in Callback-Funktion
+//       - Idee (Aton)
+//       - globale Stringvariable (msi)
+//       - TFolderBrowser-Klasse (PL)
+//   * Unterstützung für mehrere Filter ergänzt (msi)
+//   * Unterstützung für verschiedene Root-Ordner (msi)
+//   * Änderungen bei den Properties (msi)
+//       - "SelFolder" in "SelectedItem" umbenannt
+//       - "FNewFolder" als "NewFolderButton" verfügbar
+//       - "FShowFiles" als "ShowFiles" verfügbar
+//       - "FNoTT" als "NoTargetTranslation" verfügbar (XP-Flag)
+//   * Funktion zum Ermitteln von Verknüpfungszielen ergänzt (msi)
+//       - Ergänzung, um Umgebungsvariablen umzuwandeln
+//   * "InitFolder" (s. Create) umbenannt in "PreSelectedFolder" (PL)
+//   * "FNoTT" (NoTargetTranslation) standardmäßig auf TRUE gesetzt,
+//     damit alle Windows-Versionen, inkl. XP, gleich reagieren (msi)
+//   * "CoInitializeEx" (Execute & TranslateLink) geändert (msi)
+//   * "TranslateMsiLink" (PL, msi)
+//        - ermittelt Pfad/Programm aus MSI-Verknüpfungen (Office, Openoffice)
+//        - benötigt installierten MSI
+//
+// -----------------------------------------------------------------------------
+unit FolderBrowser;
+
+
+interface
+
+uses
+  ShlObj, ActiveX, Windows, Messages;
+
+type
+  TFolderBrowser = class
+  private
+    // alles private gemacht; geht niemanden was an,
+    // da nachträglicher Zugriff sinnlos (Luckie)
+    FHandle      : THandle;
+    FCaption     : string;
+    FShowFiles   : boolean;
+    FNewFolder   : boolean;
+    FStatusText  : boolean;
+    FNoTT        : boolean;
+    FInitFolder  : string;
+    FSelected    : string;
+    FTop,
+    FLeft        : integer;
+    FPosChanged  : boolean;
+
+    // mehrere Filter müssen durch #0 voneinander getrennt
+    // werden, bspw. '*.txt'#0'*.*htm*'#0'*.xml'
+    // der letzte Filter kann mit #0#0 enden, muss er aber
+    // nicht, weil die Funktion "CheckFilter" diese beiden
+    // Zeichen automatisch anhängt (Mathias)
+    FFilter      : string;
+    FRoot        : PItemIdList;
+    procedure FreeItemIDList(var pidl: pItemIDList);
+    procedure SetTopPosition(const Value: Integer);
+    procedure SetLeftPosition(const Value: Integer);
+  public
+    constructor Create(Handle: THandle; const Caption: string;
+      const PreSelectedFolder: string = ''; ShowFiles: Boolean = False;
+      NewFolder: Boolean = False);
+    destructor Destroy; override;
+    function SetDefaultRoot: boolean;
+    function SetRoot(const SpecialFolderId: integer): boolean; overload;
+    function SetRoot(const Path: string): boolean; overload;
+    function Execute: Boolean; overload;
+    function TranslateLink(const LnkFile: string): string;
+    function TranslateMsiLink(const LnkFile: string): string;
+    property SelectedItem: string read FSelected;
+    property Filter: string read FFilter write FFilter;
+    property NewFolderButton: boolean read FNewFolder write FNewFolder;
+    property ShowFiles: boolean read FShowFiles write FShowFiles;
+    property StatusText: boolean read FStatusText write FStatusText;
+    property NoTargetTranslation: boolean read FNoTT write FNoTT;
+    property Top: integer read FTop write SetTopPosition;
+    property Left: integer read FLeft write SetLeftPosition;
+  end;
+
+implementation
+
+
+//
+// erweiterte SHBrowseForFolder-Eigenschaften
+// (Deklaration ist notwendig, weil u.U. nicht in jeder Delphi-Version
+// bekannt und verfügbar)
+//
+const
+  BIF_NEWDIALOGSTYLE     = $0040;
+  BIF_USENEWUI           = BIF_NEWDIALOGSTYLE or BIF_EDITBOX;
+  BIF_BROWSEINCLUDEURLS  = $0080;
+  BIF_UAHINT             = $0100;
+  BIF_NONEWFOLDERBUTTON  = $0200;
+  BIF_NOTRANSLATETARGETS = $0400;
+  BIF_SHAREABLE          = $8000;
+
+  BFFM_IUNKNOWN          = 5;
+  BFFM_SETOKTEXT         = WM_USER + 105; // Unicode only
+  BFFM_SETEXPANDED       = WM_USER + 106; // Unicode only
+
+
+// -- helper functions ---------------------------------------------------------
+
+function fileexists(const FileName: string): boolean;
+var
+  Handle   : THandle;
+  FindData : TWin32FindData;
+begin
+  Handle   := FindFirstFile(pchar(FileName),FindData);
+  Result   := (Handle <> INVALID_HANDLE_VALUE);
+
+  if(Result) then FindClose(Handle);
+end;
+
+function CheckFilter(const Path, Filter: string): boolean;
+var
+  p      : pchar;
+begin
+  // Standardergebnis
+  Result := false;
+  if(Path = '') or (Filter = '') then exit;
+
+  // #0#0 an den Filter anhängen, damit später das Ende
+  // korrekt erkannt wird
+  p      := pchar(Filter + #0#0);
+  while(p[0] <> #0) do
+  begin
+    // Datei mit entsprechendem Filter wurde gefunden, ...
+    if(fileexists(Path + '\' + p)) then
+    begin
+    // ... Ergebnis auf TRUE setzen, und Schleife abbrechen
+      Result := true;
+      break;
+    end;
+
+    // ansonsten zum nächsten Filter
+    inc(p,lstrlen(p) + 1);
+  end;
+end;
+
+function SHGetIDListFromPath(const Path: string; out pidl: PItemIDList):
+  boolean;
+var
+  ppshf        : IShellFolder;
+  wpath        : array[0..MAX_PATH]of widechar;
+  pchEaten,
+  dwAttributes : Cardinal;
+begin
+  // Standardergebnis
+  Result       := false;
+
+  // IShellFolder-Handle holen
+  if(SHGetDesktopFolder(ppshf) = S_OK) then
+  try
+    if(StringToWideChar(Path,wpath,sizeof(wpath)) <> nil) then
+    begin
+      // Pfadname in "PItemIdList" umwandeln
+      ppshf.ParseDisplayName(0,nil,wpath,pchEaten,pidl,dwAttributes);
+      Result   := pidl <> nil;
+    end;
+  finally
+    ppshf      := nil;
+  end;
+end;
+
+//
+// "CreateComObject" (modifizierte Version; Mathias)
+//
+function CreateComObject(const ClassID: TGUID;
+  out OleResult : HRESULT): IUnknown;
+begin
+  OleResult := CoCreateInstance(ClassID,nil,CLSCTX_INPROC_SERVER or
+    CLSCTX_LOCAL_SERVER,IUnknown,Result);
+end;
+
+//
+// "ExpandEnvStr"
+//
+function ExpandEnvStr(const szInput: string): string;
+const
+  MAXSIZE = 32768;
+begin
+  SetLength(Result,MAXSIZE);
+  SetLength(Result,ExpandEnvironmentStrings(pchar(szInput),
+    @Result[1],length(Result)));
+end;
+
+
+
+// -----------------------------------------------------------------------------
+//
+// TFolderBrowser-Klasse
+//
+// -----------------------------------------------------------------------------
+
+function FolderCallback(wnd: HWND; uMsg: UINT; lp, lpData: LPARAM): LRESULT;
+  stdcall;
+var
+  path : array[0..MAX_PATH + 1]of char;
+  fb   : TFolderBrowser;
+begin
+  fb   := TFolderBrowser(lpData);
+
+  case uMsg of
+    // Dialog wurde initialisiert
+    BFFM_INITIALIZED:
+      begin
+        // Ordner auswählen, ...
+        if(fb.FInitFolder <> '') then
+          SendMessage(wnd,BFFM_SETSELECTION,WPARAM(true),
+          LPARAM(pchar(fb.FInitFolder)));
+
+        // ... & OK-Button deaktivieren, wenn Filter benutzt werden
+        SendMessage(wnd,BFFM_ENABLEOK,0,LPARAM(fb.FFilter = ''));
+        // oder anders gesagt: OK-Button aktivieren, wenn keine
+        // Filter benutzt werden. ;o)
+        // (Mathias)
+
+        // Dialog neu positionieren
+        if(fb.FPosChanged) then
+          SetWindowPos(wnd,0,fb.Left,fb.Top,0,0,SWP_NOSIZE or SWP_NOZORDER);
+      end;
+    BFFM_SELCHANGED:
+      if(PItemIdList(lp) <> nil) and (fb.FFilter <> '') then
+      begin
+        // den aktuellen Pfadnamen holen, ...
+        ZeroMemory(@path,sizeof(path));
+        if(SHGetPathFromIdList(PItemIdList(lp),path)) then
+        begin
+        // ... & anzeigen
+          SendMessage(wnd,BFFM_SETSTATUSTEXT,0,LPARAM(@path));
+
+        // gibt´s Dateien mit dem Filter?
+        // nur dann wird der OK-Button des Dialogs aktiviert
+          SendMessage(wnd,BFFM_ENABLEOK,0,LPARAM(CheckFilter(path,fb.FFilter)));
+        end;
+      end;
+  end;
+
+  Result := 0; // von Luckie hinzugefügt, hatte ich vergessen (oops)
+end;
+
+
+constructor TFolderBrowser.Create(Handle: THandle; const Caption: string;
+  const PreSelectedFolder: string = ''; ShowFiles: Boolean = False;
+  NewFolder: Boolean = False);
+begin
+  FHandle     := Handle;
+  FCaption    := Caption;
+  FInitFolder := PreSelectedFolder;
+  FShowFiles  := ShowFiles;
+  FNewFolder  := NewFolder;
+  FStatusText := true;
+  FNoTT       := true;
+  FFilter     := '';
+  FRoot       := nil;
+  FTop        := 0;
+  FLeft       := 0;
+  FPosChanged := false;
+end;
+
+destructor TFolderBrowser.Destroy;
+begin
+  // ggf. belegte "PItemIdList" freigeben
+  if(FRoot <> nil) then
+    self.FreeItemIdList(FRoot);
+
+  inherited Destroy;
+end;
+
+procedure TFolderBrowser.SetTopPosition(const Value: integer);
+begin
+  FPosChanged := true;
+  FTop        := Value;
+end;
+
+procedure TFolderBrowser.SetLeftPosition(const Value: integer);
+begin
+  FPosChanged := true;
+  FLeft       := Value;
+end;
+
+function TFolderBrowser.SetDefaultRoot: boolean;
+begin
+  // altes Objekt freigeben
+  if(FRoot <> nil) then
+    self.FreeItemIDList(FRoot);
+
+  // und alles zurücksetzen
+  FRoot  := nil;
+  Result := true;
+end;
+
+function TFolderBrowser.SetRoot(const SpecialFolderId: integer): boolean;
+begin
+  // altes Objekt freigeben
+  if(FRoot <> nil) then
+    self.FreeItemIDList(FRoot);
+
+  // SpecialFolderId kann eine der CSIDL_*-Konstanten sein,
+  //   CSIDL_DESKTOP
+  //   CSIDL_STARTMENU
+  //   CSIDL_PERSONAL
+  //   ...
+  // s. PSDK
+
+  // neuen Root setzen
+  Result := SHGetSpecialFolderLocation(FHandle,SpecialFolderId,FRoot) = S_OK;
+end;
+
+function TFolderBrowser.SetRoot(const Path: string): boolean;
+begin
+  // altes Objekt freigeben
+  if(FRoot <> nil) then
+    self.FreeItemIDList(FRoot);
+
+  // neuen Root setzen
+  Result := SHGetIDListFromPath(Path,FRoot);
+end;
+
+function TFolderBrowser.Execute: Boolean;
+var
+  hr           : HRESULT;
+  BrowseInfo   : TBrowseInfo;
+  pidlResult   : PItemIDList;
+  DisplayName,
+  Path         : array[0..MAX_PATH + 1]of char;
+begin
+  Result       := false;
+
+  hr           := CoInitializeEx(nil,COINIT_APARTMENTTHREADED);
+  // Wenn die COM-Bibliothek noch nicht initialisiert ist,
+  // dann ist das Ergebnis S_OK; ist sie bereits initialisiert
+  // ist sie S_FALSE
+  if(hr = S_OK) or (hr = S_FALSE) then
+  try
+    // "BrowseInfo" mit Werten füllen
+    ZeroMemory(@BrowseInfo,sizeof(BrowseInfo));
+    BrowseInfo.hwndOwner      := FHandle;
+    BrowseInfo.pidlRoot       := FRoot;
+    BrowseInfo.pszDisplayName := @Displayname;
+    BrowseInfo.lpszTitle      := pchar(FCaption);
+    BrowseInfo.lpfn           := @FolderCallBack;
+
+    // TFolderBrowser-Klasse als Referenz für Callback-Funktion
+    // übergeben (PL)
+    BrowseInfo.lParam         := LPARAM(self);
+
+    // Flags
+    if(FStatusText) then
+      BrowseInfo.ulFlags      := BrowseInfo.ulFlags or BIF_STATUSTEXT;
+
+
+    // BIF_USENEWUI sorgt dafür dass besagter Button immer angezeigt wird,
+    // egal, ob BIF_BROWSEINCLUDEFILES gesetzt wird oder nicht, daher
+    // rausgenommen (Luckie)
+    if(FShowFiles) then
+      BrowseInfo.ulFlags      := BrowseInfo.ulFlags or BIF_BROWSEINCLUDEFILES;
+
+    // Button zum Erstellen neuer Ordner anzeigen? (Luckie, PL)
+    if(FNewFolder) then
+      BrowseInfo.ulFlags      := BrowseInfo.ulFlags or BIF_NEWDIALOGSTYLE
+    else
+      BrowseInfo.ulFlags      := BrowseInfo.ulFlags or BIF_NONEWFOLDERBUTTON;
+
+    // Windows XP sucht automatisch die Verknüpfungsziele von
+    // Shortcuts heraus; soll stattdessen aber der Name der
+    // Verknüpfung angezeigt werden, ist das Flag BIF_NOTRANSLATETARGETS
+    // erforderlich; Sinn macht es nur unter Windows XP
+    if(FNoTT) then
+      BrowseInfo.ulFlags      := BrowseInfo.ulFlags or BIF_NOTRANSLATETARGETS;
+    // für die älteren Windows-Versionen gibt es mit der Funktion
+    // "TranslateLink" (s. weiter unten) eine Entsprechung, um die
+    // Ziele von Shortcuts zu ermitteln (Mathias)
+
+
+    // Dialog aufrufen
+    pidlResult := SHBrowseForFolder(BrowseInfo);
+    if(pidlResult <> nil) then
+    begin
+      if(FSelected = '') then
+        if(SHGetPathFromIdList(pidlResult,Path)) and
+          (Path[0] <> #0) then
+        begin
+          FSelected := Path;
+          Result    := true;
+        end;
+
+      self.FreeItemIdList(pidlResult);
+    end;
+  finally
+    CoUninitialize;
+  end;
+end;
+
+function TFolderBrowser.TranslateLink(const LnkFile: string): string;
+var
+  link       : IShellLink;
+  hr         : HRESULT;
+  afile      : IPersistFile;
+  pwcLnkFile : array[0..MAX_PATH]of widechar;
+  szData     : array[0..MAX_PATH]of char;
+  FindData   : TWin32FindData;
+begin
+  // Standardergebnis
+  Result     := '';
+  link       := nil;
+  afile      := nil;
+
+  hr         := CoInitializeEx(nil,COINIT_APARTMENTTHREADED);
+  if(hr = S_OK) or (hr = S_FALSE) then
+  try
+    // IShellLink-Interface erzeugen, ...
+    link   := CreateComObject(CLSID_ShellLink,hr) as IShellLink;
+    if(hr = S_OK) and (link <> nil) then
+    begin
+    // ... & Verknüpfung laden
+      StringToWideChar(LnkFile,pwcLnkFile,sizeof(pwcLnkFile));
+      afile := link as IPersistFile;
+
+      if(afile <> nil) and
+        (afile.Load(pwcLnkFile,STGM_READ) = S_OK) then
+      begin
+        ZeroMemory(@szData,sizeof(szData));
+
+    // Pfad + Dateiname ermitteln, ...
+        if(link.GetPath(szData,sizeof(szData),FindData,
+          SLGP_RAWPATH) = S_OK) then
+        begin
+          SetString(Result,szData,lstrlen(szData));
+    // ... & evtl. Umgebungsvariablen filtern
+          Result := ExpandEnvStr(Result);
+        end;
+      end;
+    end;
+  finally
+    if(afile <> nil) then afile := nil;
+    if(link <> nil) then link := nil;
+
+    CoUninitialize;
+  end;
+end;
+
+procedure TFolderBrowser.FreeItemIDList(var pidl: pItemIDList);
+var
+  ppMalloc : iMalloc;
+begin
+  if(SHGetMalloc(ppMalloc) = S_OK) then
+  try
+    ppMalloc.Free(pidl);
+    pidl     := nil;
+  finally
+    ppMalloc := nil;
+  end;
+end;
+
+
+const
+  MsiDllName                = 'msi.dll';
+
+  INSTALLSTATE_ABSENT       =  2;    // uninstalled
+  INSTALLSTATE_LOCAL        =  3;    // installed on local drive
+  INSTALLSTATE_SOURCE       =  4;    // run from source, CD or net
+  INSTALLSTATE_SOURCEABSENT = -4;    // run from source, source is unavailable
+  INSTALLSTATE_NOTUSED      = -7;    // component disabled
+  INSTALLSTATE_INVALIDARG   = -2;    // invalid function argument
+  INSTALLSTATE_UNKNOWN      = -1;    // unrecognized product or feature
+
+type
+  INSTALLSTATE              = LongInt;
+
+  TMsiGetShortcutTarget     = function(szShortcutTarget, szProductCode,
+    szFeatureId, szComponentCode: PAnsiChar): uint; stdcall;
+  TMsiGetComponentPath      = function(szProduct, szComponent: PAnsiChar;
+    lpPathBuf: PAnsiChar; pcchBuf: pdword): INSTALLSTATE; stdcall;
+var
+  MsiGetShortcutTarget      : TMsiGetShortcutTarget = nil;
+  MsiGetComponentPath       : TMsiGetComponentPath  = nil;
+  MsiDll                    : dword = 0;
+
+function TFolderBrowser.TranslateMsiLink(const LnkFile: string): string;
+var
+  ProductCode,
+  FeatureId,
+  ComponentCode : array[0..MAX_PATH]of char;
+  Path          : array[0..MAX_PATH]of char;
+  PathLen       : dword;
+begin
+  Result := '';
+  if(@MsiGetShortcutTarget = nil) or (@MsiGetComponentPath = nil) then exit;
+
+  ZeroMemory(@ProductCode, sizeof(ProductCode));
+  ZeroMemory(@FeatureId, sizeof(FeatureId));
+  ZeroMemory(@ComponentCode, sizeof(ComponentCode));
+
+  if(MsiGetShortcutTarget(PAnsiChar(LnkFile), ProductCode, FeatureId,
+    ComponentCode) = ERROR_SUCCESS) then
+  begin
+    ZeroMemory(@Path, sizeof(Path));
+    PathLen := sizeof(Path);
+
+    case MsiGetComponentPath(ProductCode, ComponentCode, Path, @PathLen) of
+      INSTALLSTATE_LOCAL,
+      INSTALLSTATE_SOURCE:
+        SetString(Result, Path, lstrlen(Path));
+    end;
+  end;
+end;
+
+
+initialization
+  MsiDll                     := GetModuleHandle(MsiDllName);
+  if(MsiDll = 0) then MsiDll := LoadLibrary(MsiDllName);
+
+  if(MsiDll <> 0) then
+  begin
+    MsiGetShortcutTarget     := GetProcAddress(MsiDll, 'MsiGetShortcutTargetA');
+    MsiGetComponentPath      := GetProcAddress(MsiDll, 'MsiGetComponentPathA');
+
+    if(@MsiGetShortcutTarget = nil) or
+      (@MsiGetComponentPath  = nil) then
+    begin
+      FreeLibrary(MsiDll);
+      MsiDll := 0;
+    end;
+  end;
+finalization
+  if(MsiDll <> 0) then FreeLibrary(MsiDll);
+end.
Index: oup/releases/0.34a/ImportedStuff/OneInst.pas
===================================================================
--- oup/releases/0.34a/ImportedStuff/OneInst.pas	(revision 200)
+++ oup/releases/0.34a/ImportedStuff/OneInst.pas	(revision 200)
@@ -0,0 +1,203 @@
+{ Downloaded from: http://www.michael-puff.de/Developer/Delphi/Importe/Nico/oneinst.zip  }
+
+unit OneInst;
+interface
+uses
+  Windows, Messages;
+
+var
+  { Mit dieser MessageId meldet sich dann eine zweite Instanz }
+  SecondInstMsgId: UINT = 0;
+
+function ParamBlobToStr(lpData: Pointer): string;
+function ParamStrToBlob(out cbData: DWORD): Pointer;
+
+implementation
+
+const
+  { Maximale Zeit, die auf die Antwort der ersten Instanz gewartet wird (ms) }
+  TimeoutWaitForReply = 5000;
+
+var
+  { Der Text den diese Variable hat sollte bei jedem neuen Programm geändert }
+  { werden und möglichst eindeutig (und nicht zu kurz) sein.                 }
+  UniqueName: array [0..MAX_PATH] of Char = 'Oni Un/Packer'#0;
+  MutexHandle: THandle = 0;
+
+{ kleine Hilfsfunktion die uns die Kommandozeilenparameter entpackt }
+function ParamBlobToStr(lpData: Pointer): string;
+var
+  pStr: PChar;
+begin
+  Result := '';
+  pStr := lpData;
+  while pStr[0] <> #0 do
+  begin
+    Result := Result + string(pStr) + #13#10;
+    pStr := @pStr[lstrlen(pStr) + 1];
+  end;
+end;
+
+{ kleine Hilfsfunktion die uns die Kommandozeilenparameter einpackt }
+function ParamStrToBlob(out cbData: DWORD): Pointer;
+var
+  Loop: Integer;
+  pStr: PChar;
+begin
+  cbData := Length(ParamStr(1)) + 3;  { gleich inklusive #0#0 }
+  for Loop := 2 to ParamCount do
+    cbData := cbData + DWORD(Length(ParamStr(Loop)) + 1);
+  Result := GetMemory(cbData);
+  ZeroMemory(Result, cbData);
+  pStr := Result;
+  for Loop := 1 to ParamCount do
+  begin
+    lstrcpy(pStr, PChar(ParamStr(Loop)));
+    pStr := @pStr[lstrlen(pStr) + 1];
+  end;
+end;
+
+procedure HandleSecondInstance;
+var
+  Run: DWORD;
+  Now: DWORD;
+  Msg: TMsg;
+  Wnd: HWND;
+  Dat: TCopyDataStruct;
+begin
+  // MessageBox(0, 'läuft schon', nil, MB_ICONINFORMATION);
+  {----------------------------------------------------------------------------}
+  { Wir versenden eine Nachricht an alle Hauptfenster (HWND_BROADCAST) mit der }
+  { eindeutigen Message-Id, die wir zuvor registriert haben. Da nur eine       }
+  { Instanz unseres Programms läuft sollte auch nur eine Anwendung antworten.  }
+  {                                                                            }
+  { (Broadcast sollten _NUR_ mit registrierten Nachrichten-Ids erfolgen!)      }
+  {----------------------------------------------------------------------------}
+
+  SendMessage(HWND_BROADCAST, SecondInstMsgId, GetCurrentThreadId, 0);
+
+  { Wir warten auf die Antwort der ersten Instanz                        }
+  { Für die, die es nicht wußten - auch Threads haben Message-Queues ;o) }
+  Wnd := 0;
+  Run := GetTickCount;
+  while True do
+  begin
+    if PeekMessage(Msg, 0, SecondInstMsgId, SecondInstMsgId, PM_NOREMOVE) then
+    begin
+      GetMessage(Msg, 0, SecondInstMsgId, SecondInstMsgId);
+      if Msg.message = SecondInstMsgId then
+      begin
+        Wnd := Msg.wParam;
+        Break;
+      end;
+    end;
+    Now := GetTickCount;
+    if Now < Run then
+      Run := Now;  { Überlaufschutz - passiert nur alle 48 Tage, aber naja }
+    if Now - Run > TimeoutWaitForReply then
+      Break;
+  end;
+
+  if (Wnd <> 0) and IsWindow(Wnd) then
+  begin
+    { Als Antwort haben wir das Handle bekommen, an das wir die Daten senden. }
+
+    {-------------------------------------------------------------------------}
+    { Wir verschicken nun eine Message mit WM_COPYDATA. Dabei handelt es sich }
+    { eine der wenigen Nachrichten, bei der Windows Daten aus einem Prozeß in }
+    { einen anderen einblendet. Nach Behandlung der Nachricht werden diese    }
+    { wieder aus dem Adreßraum des Empfängers ausgeblendet, sodaß derjenige,  }
+    { der die Nachricht erhält und die Daten weiter verwenden will, sich die  }
+    { Daten kopieren muß.                                                     }
+    {-------------------------------------------------------------------------}
+
+    { Zur Absicherung schreiben wir nochmal die eindeutige Nachrichten-Id in  }
+    { das Tag-Feld, das uns die Nachricht bietet.                             }
+    { Ansonsten schreiben wir die Kommandozeilenparameter als                 }
+    { durch #0 getrennte und durch #0#0 beendete Liste in den Datenblock      }
+    Dat.dwData := SecondInstMsgId;
+    Dat.lpData := ParamStrToBlob(Dat.cbData);
+    SendMessage(Wnd, WM_COPYDATA, 0, LPARAM(@Dat));
+    FreeMemory(Dat.lpData);
+  end;
+end;
+
+procedure CheckForSecondInstance;
+var
+  Loop: Integer;
+begin
+  {-----------------------------------------------------------------------------}
+  { Wir versuchen ein systemweit eindeutiges benanntes Kernelobjekt, ein Mutex  }
+  { anzulegen und prüfen, ob dieses Objekt schon existiert.                     }
+  { Der Name zum Anlegen eines Mutex darf nicht länger als MAX_PATH (260) sein  }
+  { und darf alle Zeichen außer '\' enthalten.                                  }
+  {                                                                             }
+  { (Einzige Ausnahme sind die beiden Schlüsselwörter 'Global\' und 'Local\'    }
+  {  mit denen ein Mutexname auf einem Terminalserver beginnen darf, damit der  }
+  {  Mutex nicht nur oder expliziet für eine Session dient. Das wird aber nur   }
+  {  sehr selten benötigt, wenn, dann meist bei Diensten auf Terminalservern.)  }
+  {                                                                             }
+  { Windows kennt nur einen Namensraum für Events, Semaphoren und andere        }
+  { benannte Kernelobjekte. Das heißt es kommt zum Beispiel zu einem Fehler bei }
+  { dem Versuch mit dem Namen eines existierenden benannten Events einen Mutex  }
+  { zu erzeugen. (da gewinnt das Wort 'Sonderfall' fast eine neue Bedeutung ;o) }
+  {-----------------------------------------------------------------------------}
+
+  for Loop := lstrlen(UniqueName) to MAX_PATH - 1 do
+  begin
+    MutexHandle := CreateMutex(nil, False, UniqueName);
+    if (MutexHandle = 0) and (GetLastError = INVALID_HANDLE_VALUE) then
+      { Es scheint schon ein Kernelobjekt mit diesem Namen zu geben. }
+      { Wir versuchen das Problem durch Anhängen von '_' zu lösen.   }
+      lstrcat(UniqueName, '_')
+    else
+      { es gibt zumindest keinen Konflikt durch den geteilten Namensraum }
+      Break;
+  end;
+
+  case GetLastError of
+    0:
+      begin
+        { Wir haben den Mutex angelegt; sind also die erste Instanz. }
+      end;
+    ERROR_ALREADY_EXISTS:
+      begin
+        { Es gibt also schon eine Instanz - beginnen wir mit dem Prozedere. }
+        try
+          HandleSecondInstance;
+        finally
+          { was auch immer passiert, alles endet hier ;o) }
+          { Die 183 ist nicht ganz zufällig, kleiner Spaß }
+          Halt(183);
+        end;
+      end;
+  else
+    { Keine Ahnung warum wir hier landen sollten,        }
+    { außer Microsoft hat wiedermal die Regeln geändert. }
+    { Wie auch immer - wir lassen das Programm starten.  }
+  end;
+end;
+
+initialization
+
+  { Wir holen uns gleich zu Beginn eine eindeutige Nachrichten-Id die wir im }
+  { Programm zur eindeutigen Kommunikation zwischen den Instanzen brauchen.  }
+  { Jedes Programm bekommt, wenn es den gleichen Text benutzt, die gleiche   }
+  { Id zurück (zumindest innerhalb einer Windows Sitzung)                    }
+  SecondInstMsgId := RegisterWindowMessage(UniqueName);
+
+  { Auf eine schon laufende Instanz überprüfen. }
+  CheckForSecondInstance;
+
+finalization
+
+  { Den Mutex wieder freigeben, was eigentlich nicht nötig wäre, da Windows NT }
+  { Alle angeforderten Kernel-Objekte zum Prozeßende freigibt. Aber sicher ist }
+  { sicher (Windows 95/98 kann nur 65535 Objekte verwalten - jaja 32-Bit ;o).  }
+  if MutexHandle <> 0 then
+  begin
+    ReleaseMutex(MutexHandle);
+    MutexHandle := 0;  { hilft beim Debuggen }
+  end;
+
+end.
Index: oup/releases/0.34a/Main.dfm
===================================================================
--- oup/releases/0.34a/Main.dfm	(revision 200)
+++ oup/releases/0.34a/Main.dfm	(revision 200)
@@ -0,0 +1,1063 @@
+object Form_Main: TForm_Main
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form_Main'
+  ClientHeight = 571
+  ClientWidth = 742
+  Color = clBtnFace
+  Constraints.MinHeight = 500
+  Constraints.MinWidth = 750
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIForm
+  OldCreateOrder = False
+  WindowState = wsMaximized
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 554
+    Width = 742
+    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 DockTop: TTBDock
+    Left = 0
+    Top = 0
+    Width = 742
+    Height = 75
+    object MainMenu: TTBToolbar
+      Left = 0
+      Top = 0
+      Caption = 'MainMenu'
+      CloseButton = False
+      DragHandleStyle = dhDouble
+      FullSize = True
+      Images = MenuImages
+      MenuBar = True
+      ProcessShortCuts = True
+      ShrinkMode = tbsmWrap
+      TabOrder = 0
+      object menu_main: TTBSubmenuItem
+        Caption = '&Main'
+        object menu_loadfile: TTBItem
+          Caption = '&Open .dat/.raw ...'
+          ImageIndex = 0
+          ShortCut = 16463
+          OnClick = menu_loadfileClick
+        end
+        object menu_loaddb: TTBItem
+          Caption = 'Open level-&db ...'
+          ImageIndex = 1
+          OnClick = menu_loaddbClick
+        end
+        object menu_sep1: TTBSeparatorItem
+        end
+        object menu_settings: TTBItem
+          Caption = 'Se&ttings...'
+          OnClick = menu_settingsClick
+        end
+        object menu_sep4: TTBSeparatorItem
+        end
+        object menu_exit: TTBItem
+          Caption = '&Exit'
+          OnClick = menu_exitClick
+        end
+      end
+      object menu_convert: TTBSubmenuItem
+        Caption = '&Convert'
+        object menu_createdb: TTBItem
+          Caption = 'Convert .dat/.raw to DB ...'
+          ImageIndex = 2
+          OnClick = menu_createdbClick
+        end
+        object menu_createlvl: TTBItem
+          Caption = 'Convert DB to .dat/.raw ...'
+          ImageIndex = 3
+          OnClick = menu_createlvlClick
+        end
+      end
+      object menu_tools: TTBSubmenuItem
+        Caption = '&Tools'
+        Enabled = False
+        object menu_preview: TTBItem
+          Caption = '&Preview window ...'
+          ImageIndex = 4
+          ShortCut = 16464
+          OnClick = menu_previewClick
+        end
+        object menu_binedit: TTBItem
+          Caption = 'Binary .&dat editor ...'
+          ImageIndex = 5
+          ShortCut = 16452
+          OnClick = menu_bineditClick
+        end
+        object menu_rawedit: TTBItem
+          Caption = 'Binary .&raw editor ...'
+          ImageIndex = 6
+          ShortCut = 16466
+          OnClick = menu_raweditClick
+        end
+        object menu_txmpreplace: TTBItem
+          Caption = '&TXMP replacer ...'
+          ImageIndex = 7
+          ShortCut = 16468
+          OnClick = menu_txmpreplaceClick
+        end
+        object menu_extractor: TTBItem
+          Caption = 'File &extractor ...'
+          ImageIndex = 8
+          ShortCut = 16453
+          OnClick = menu_extractorClick
+        end
+        object menu_meta: TTBItem
+          Caption = '&Meta editor'
+          Enabled = False
+          ImageIndex = 11
+          ShortCut = 16461
+          OnClick = menu_metaClick
+        end
+        object menu_filecompare: TTBItem
+          Caption = '&File compare ...'
+          Enabled = False
+          ImageIndex = 10
+          ShortCut = 16454
+          OnClick = menu_filecompareClick
+        end
+        object menu_levelstructedit: TTBItem
+          Caption = 'Levelfile structure editor ...'
+          Enabled = False
+          ImageIndex = 12
+          ShortCut = 16460
+        end
+      end
+      object menu_view: TTBSubmenuItem
+        Caption = '&View'
+        object menu_windows_cascade: TTBItem
+          Caption = 'Cascade'
+          OnClick = menu_windows_cascadeClick
+        end
+        object menu_windows_tilevert: TTBItem
+          Caption = 'Tile vertical'
+          OnClick = menu_windows_tilevertClick
+        end
+        object menu_windows_tile: TTBItem
+          Caption = 'Tile horizontal'
+          OnClick = menu_windows_tileClick
+        end
+        object menu_windows_closeall: TTBItem
+          Caption = '&Close all'
+          OnClick = menu_windows_closeallClick
+        end
+        object menu_sep3: TTBSeparatorItem
+        end
+        object menu_windows_next: TTBItem
+          Caption = 'Next window'
+          ShortCut = 16417
+          OnClick = menu_windows_nextClick
+        end
+        object menu_windows_previous: TTBItem
+          Caption = 'Previous window'
+          ShortCut = 16418
+          OnClick = menu_windows_previousClick
+        end
+        object menu_sep2: TTBSeparatorItem
+        end
+        object menu_windows: TTBSubmenuItem
+          Caption = '&Windows'
+        end
+        object menu_conns: TTBSubmenuItem
+          Caption = 'Connections'
+          Enabled = False
+        end
+        object menu_toolbars: TTBSubmenuItem
+          Caption = '&Toolbars'
+          object menu_view_toolbar: TTBItem
+            Caption = '&Toolbar'
+            Checked = True
+            OnClick = menu_view_toolbarClick
+          end
+          object menu_view_statusbar: TTBItem
+            Caption = '&Status bar'
+            Checked = True
+            OnClick = menu_view_statusbarClick
+          end
+          object menu_view_mdibar: TTBItem
+            Caption = '&Window list'
+            Checked = True
+            OnClick = menu_view_mdibarClick
+          end
+        end
+      end
+      object menu_About: TTBItem
+        Caption = '&About'
+        OnClick = menu_AboutClick
+      end
+    end
+    object Toolbar: TTBToolbar
+      Left = 0
+      Top = 23
+      Caption = 'Toolbar'
+      DragHandleStyle = dhDouble
+      Images = MenuImages
+      TabOrder = 1
+      OnDockChanged = ToolbarDockChanged
+      object tbOpen: TTBItem
+        Caption = 'Open .dat'
+        DisplayMode = nbdmImageAndText
+        ImageIndex = 0
+        OnClick = menu_loadfileClick
+      end
+      object tb_opendb: TTBItem
+        Caption = 'Open DB'
+        DisplayMode = nbdmImageAndText
+        ImageIndex = 1
+        OnClick = menu_loaddbClick
+      end
+      object tb_separator1: TTBSeparatorItem
+      end
+      object tb_dat2db: TTBItem
+        Caption = '.dat -> DB'
+        DisplayMode = nbdmImageAndText
+        ImageIndex = 2
+        OnClick = menu_createdbClick
+      end
+      object tb_db2dat: TTBItem
+        Caption = 'DB -> .dat'
+        DisplayMode = nbdmImageAndText
+        ImageIndex = 3
+        OnClick = menu_createlvlClick
+      end
+      object TBSeparatorItem1: TTBSeparatorItem
+      end
+      object tb_preview: TTBItem
+        Caption = 'Preview'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 4
+        OnClick = menu_previewClick
+      end
+      object tb_datedit: TTBItem
+        Caption = 'DatEditor'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 5
+        OnClick = menu_bineditClick
+      end
+      object tb_rawedit: TTBItem
+        Caption = 'RawEditor'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 6
+        OnClick = menu_raweditClick
+      end
+      object tb_txmpreplacer: TTBItem
+        Caption = 'TXMP replacer'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 7
+        OnClick = menu_txmpreplaceClick
+      end
+      object tb_extractor: TTBItem
+        Caption = 'File extractor'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 8
+        OnClick = menu_extractorClick
+      end
+      object tb_meta: TTBItem
+        Caption = 'MetaEditor'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 11
+        OnClick = menu_metaClick
+      end
+      object tb_compare: TTBItem
+        Caption = 'File compare'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 10
+        OnClick = menu_filecompareClick
+      end
+      object tb_structure: TTBItem
+        Caption = 'Level structure'
+        DisplayMode = nbdmImageAndText
+        Enabled = False
+        ImageIndex = 12
+      end
+    end
+    object MDIToolbar: TTBToolbar
+      Left = 0
+      Top = 49
+      Caption = 'MDIToolbar'
+      DockableTo = [dpTop, dpBottom]
+      DockMode = dmCannotFloat
+      DockPos = 0
+      DockRow = 2
+      DragHandleStyle = dhDouble
+      TabOrder = 2
+      object TBControlItem1: TTBControlItem
+        Control = MDITab
+      end
+      object MDITab: TMDITab
+        Left = 0
+        Top = 0
+        Width = 300
+        Height = 22
+        Cursor = crHandPoint
+        About = 'MDI Tab Control 1.4 - Copyright '#169' 1999,2002 MichaL MutL'
+        Align = alTop
+        DragKind = dkDock
+        HotTrack = True
+        Images = MenuImages
+        OwnerDraw = True
+        Style = tsFlatButtons
+        OnDrawTab = MDITabDrawTab
+        ParentShowHint = False
+        ShowHint = True
+        ShowOnChange = True
+        TabOrder = 0
+        OnMouseMove = MDITabMouseMove
+        OnMouseUp = MDITabMouseUp
+      end
+    end
+  end
+  object DockLeft: TTBDock
+    Left = 0
+    Top = 75
+    Width = 9
+    Height = 470
+    Position = dpLeft
+  end
+  object DockRight: TTBDock
+    Left = 733
+    Top = 75
+    Width = 9
+    Height = 470
+    Position = dpRight
+  end
+  object DockBottom: TTBDock
+    Left = 0
+    Top = 545
+    Width = 742
+    Height = 9
+    Position = dpBottom
+  end
+  object opend: TOpenDialog
+    Filter = 
+      'Compatible level files|*.dat;*.oldb|Oni level (*.dat)|*.dat|OUP ' +
+      'level database (*.oldb)|*.oldb|Any (*.*)|*'
+    Options = [ofAllowMultiSelect, ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 32
+    Top = 64
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 32
+    Top = 88
+  end
+  object MenuImages: TImageList
+    Left = 16
+    Top = 136
+    Bitmap = {
+      494C01010D000E00040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000004000000001002000000000000040
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF000000FF000000FF
+      000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF
+      000000FF000000FF000000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF000000000000000000000000000000000000000000000000000000
+      0000FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF00000000000000000000000000000000000000000000000000FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF000000000000000000000000000000000000000000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF0000000000000000000000000000000000FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF000000
+      FF00FFFFFF00000000000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF0000FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+      FF00FFFFFF00FFFFFF0000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FF000000FF000000FF
+      000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF
+      000000FF000000FF000000FF0000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF00000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF0000FFFF000000FF0000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000FFFF000000FF000000FF000000FF00000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000FFFF00000000000000FF0000000000000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000FF0000000000000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000000000000000000000FF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000000000000000000000FF000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000FF000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      000000000000000000000000FF000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      000000000000000000000000FF000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF000000FF0000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000FF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF00000000000000
+      000000000000000000000000FF00000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF000000FF000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF00000000000000
+      000000000000000000000000FF00000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000FF00000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000FFFF000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000000000000000000000
+      000000000000000000000000FF00000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF0000FFFF000000FF0000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000FF000000000008080800080808000808
+      0800080808001018180010101000080808001010100008080800080810001010
+      1000101010000808080008080800000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000FFFF0000FFFF0000FFFF0000FFFF000000000000000000000000000000
+      000000FFFF0000FFFF0000FFFF0000FFFF000000000000000000202018002920
+      18005252520039313100393131009C9C9C0039313100393131009C9C9C000000
+      0000292020002920180000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000FFFF0000000000000000000000
+      00000000000000FFFF0000FFFF0000FFFF0000FFFF0000000000000000000000
+      00000000000000FFFF0000FFFF0000FFFF000000000000000000292018002920
+      20005252520039313100DEDEDE00A4A4A40039313100DEDEDE00A4A4A4000000
+      000029202000292020000000000000000000FF00000000000000FF0000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FF00000000000000FF0000000000FF00000000000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000FF00000000000000FF0000FFFF0000FFFF00000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000FFFF0000FFFF000000000000000000292018002920
+      20005252520039313100DEDEDE00A4A4A40039313100DEDEDE00A4A4A4000000
+      000029202000292020000000000000000000FF00000000000000FF000000FF00
+      0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF00000000000000FF0000FFFF0000FFFF0000FFFF000000
+      0000000000000000000000FFFF0000FFFF0000FFFF0000FFFF00000000000000
+      000000000000000000000000000000FFFF000000000000000000292029003129
+      2900525252003931310039313100A4A4A4003931310039313100A4A4A4000000
+      000031292900312929000000000000000000FF00000000000000FF0000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000FF000000FF00000000000000FF0000FFFF0000FFFF0000FFFF000000
+      000000FFFF0000FFFF0000FFFF00000000000000000000FFFF0000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000525252005252
+      5200525252005252520052525200525252005252520052525200525252005252
+      520052525200525252000000000000000000FF00000000000000FF0000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000FF000000FF00000000000000FF000000000000FFFF0000FFFF000000
+      000000FFFF0000FFFF00000000000000FF000000FF000000000000FFFF0000FF
+      FF00000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000FF00000000000000FF000000FF00
+      0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF00000000000000FF0000000000000000000000000000FF
+      FF0000FFFF0000000000000000000000000000000000000000000000000000FF
+      FF0000FFFF0000000000000000000000000000000000000000000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF000000000000000000FF00000000000000FF0000000000
+      000000000000000000000000000000000000000000000000000000000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      FF000000FF000000FF00000000000000FF0000000000000000000000000000FF
+      FF000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      000000FFFF000000000000FFFF000000000000000000000000000000FF000000
+      FF000000FF000000000000000000000000000000000000000000000000000000
+      FF000000FF000000FF000000000000000000FF00000000000000FF0000000000
+      000000000000000000000000000000000000000000000000000000000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      FF000000FF000000FF00000000000000FF0000000000000000000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000FFFF0000FFFF0000000000000000000000FF000000
+      FF000000000000000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000
+      00000000FF000000FF000000000000000000FF00000000000000FF000000FF00
+      0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF00000000000000FF0000FFFF00000000000000000000FF
+      FF0000FFFF00000000000000000000FFFF0000FFFF00000000000000000000FF
+      FF0000FFFF000000000000FFFF0000FFFF0000000000000000000000FF000000
+      000000000000FFFFFF00FFFFFF000000000000000000FFFFFF00FFFFFF000000
+      0000000000000000FF000000000000000000FF00000000000000FF0000000000
+      0000000000000000000000000000000000000000000000000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      00000000000000000000000000000000000000000000000000000000FF000000
+      FF000000FF000000FF00000000000000FF0000FFFF0000FFFF00000000000000
+      000000FFFF00000000000000000000FFFF0000FFFF00000000000000000000FF
+      FF00000000000000000000FFFF0000FFFF0000000000000000000000FF000000
+      0000FFFFFF00FFFFFF00000000006A00BD006A00BD0000000000FFFFFF00FFFF
+      FF00000000000000FF000000000000000000FF00000000000000FF0000000000
+      0000000000000000000000000000000000000000000000000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      00000000000000000000000000000000000000000000000000000000FF000000
+      FF000000FF000000FF00000000000000FF0000FFFF0000FFFF0000FFFF000000
+      000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000000000000000000000000000FFFF0000000000000000000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000FF000000000000000000FF00000000000000FF000000FF00
+      0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF00000000000000FF0000FFFF0000FFFF0000FFFF0000FF
+      FF00000000000000000000FFFF0000FFFF0000FFFF0000FFFF00000000000000
+      00000000000000000000000000000000000000000000000000000000FF000000
+      FF00000000000000000000000000000000000000000000000000000000000000
+      00000000FF000000FF000000000000000000FF00000000000000FF0000000000
+      00000000000000000000000000000000000000000000FF000000FF000000FF00
+      0000FF000000FF00000000000000FF0000000000FF00000000000000FF000000
+      000000000000000000000000000000000000000000000000FF000000FF000000
+      FF000000FF000000FF00000000000000FF000000000000FFFF0000FFFF0000FF
+      FF0000FFFF00000000000000000000000000000000000000000000FFFF0000FF
+      FF0000FFFF0000000000000000000000000000000000000000000000FF000000
+      FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000
+      FF000000FF000000FF0000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000000000000FFFF0000FF
+      FF0000FFFF0000FFFF000000000000000000000000000000000000FFFF0000FF
+      FF0000FFFF0000FFFF0000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000000000000000FF
+      FF0000FFFF0000FFFF0000FFFF000000000000000000000000000000000000FF
+      FF0000FFFF0000FFFF0000FFFF00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000FF000000FF000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000FF000000FF000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FF0000000000FF0000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000FF0000000000FF0000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FF000000FF0000000000000000000000FF000000FF00000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FF000000FF0000000000000000000000FF000000FF00000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      00000000000000000000000000000000000000000000000000000000000000FF
+      000000FF00000000000000000000FF0000000000FF00000000000000000000FF
+      000000FF000000000000000000000000000000000000000000000000000000FF
+      000000FF000000000000000000000000000000000000000000000000000000FF
+      000000FF0000000000000000000000000000000000000000000000000000FF00
+      0000FF000000FF00000000000000000000000000000000000000000000000000
+      FF000000FF00000000000000000000000000000000000000000000000000FF00
+      0000FF000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      FF000000FF000000000000000000000000000000000000FF000000FF00000000
+      000000000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      00000000000000FF000000FF0000000000000000000000FF000000FF00000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FF000000FF00000000000000000000FF000000FF000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      00000000FF000000FF000000FF000000000000000000FF000000FF0000000000
+      0000000000000000000000000000FF0000000000FF0000000000000000000000
+      0000000000000000FF000000FF00000000000000000000FF000000000000FF00
+      0000FF000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      FF000000FF000000000000FF0000000000000000000000FF0000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000FF00000000000000000000FF000000FF000000FF00
+      0000000000000000000000000000FF0000000000FF000000FF00000000000000
+      0000000000000000FF000000FF000000000000000000FF000000FF000000FF00
+      0000000000000000000000000000FF0000000000FF0000000000000000000000
+      00000000FF000000FF000000FF00000000000000000000FF000000000000FF00
+      0000FF000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      FF000000FF000000000000FF0000000000000000000000FF0000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000FF00000000000000000000FF000000FF000000FF00
+      00000000000000000000FF000000FF0000000000FF000000FF000000FF000000
+      0000000000000000FF000000FF000000000000000000FF000000FF0000000000
+      0000000000000000000000000000FF0000000000FF0000000000000000000000
+      0000000000000000FF000000FF00000000000000000000FF000000000000FF00
+      0000FF000000FF000000FF000000FF0000000000FF000000FF000000FF000000
+      FF000000FF000000000000FF0000000000000000000000FF0000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000FF00000000000000000000FF000000FF000000FF00
+      00000000000000000000FF000000FF0000000000FF000000FF000000FF000000
+      FF000000FF000000FF000000FF000000000000000000FF000000FF0000000000
+      000000000000FF00000000000000FF0000000000FF00000000000000FF000000
+      0000000000000000FF000000FF00000000000000000000FF000000000000FF00
+      0000FF000000FF000000FF00000000000000000000000000FF000000FF000000
+      FF000000FF000000000000FF0000000000000000000000FF0000000000000000
+      000000000000000000000000000000FFFF0000FFFF0000000000000000000000
+      0000000000000000000000FF00000000000000000000FF000000FF000000FF00
+      0000000000000000000000FFFF0000FFFF0000FFFF0000FFFF000000FF000000
+      FF000000FF000000FF000000FF000000000000000000FF000000FF0000000000
+      000000000000FF00000000FFFF0000FFFF0000FFFF0000FFFF000000FF000000
+      0000000000000000FF000000FF00000000000000000000FF000000000000FF00
+      0000FF0000000000000000000000000000000000000000000000000000000000
+      FF000000FF000000000000FF0000000000000000000000FF0000000000000000
+      00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      0000000000000000000000FF00000000000000000000FF000000FF000000FF00
+      000000000000000000000000000000FFFF000000000000FFFF0000FFFF0000FF
+      FF000000FF000000FF000000FF000000000000000000FF000000FF0000000000
+      00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      0000000000000000FF000000FF00000000000000000000FF0000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000FF0000000000000000000000FF00000000000000FF
+      FF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FF
+      FF0000FFFF000000000000FF00000000000000000000FF00000000FFFF0000FF
+      FF0000FFFF000000000000000000000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF0000FFFF000000FF000000000000000000FF000000FF0000000000
+      0000000000000000000000FFFF0000FFFF0000FFFF0000FFFF00000000000000
+      0000000000000000FF000000FF00000000000000000000FF000000FF00000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FF000000FF0000000000000000000000FF000000FF00000000
+      00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      00000000000000FF000000FF0000000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF0000FFFF0000000000000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF0000FFFF0000FFFF00000000000000000000FFFF0000FFFF0000FF
+      FF0000000000000000000000000000FFFF0000FFFF0000000000000000000000
+      000000FFFF0000FFFF0000FFFF000000000000000000000000000000000000FF
+      000000FF000000000000000000000000000000000000000000000000000000FF
+      000000FF000000000000000000000000000000000000000000000000000000FF
+      000000FF0000000000000000000000FFFF0000FFFF00000000000000000000FF
+      000000FF000000000000000000000000000000000000000000000000000000FF
+      FF0000FFFF000000000000000000000000000000000000FFFF0000FFFF0000FF
+      FF0000FFFF0000000000000000000000000000000000000000000000000000FF
+      FF0000FFFF00000000000000000000FFFF0000FFFF00000000000000000000FF
+      FF0000FFFF000000000000000000000000000000000000000000000000000000
+      00000000000000FF000000FF0000000000000000000000FF000000FF00000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FF000000FF0000000000000000000000FF000000FF00000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000FF000000FF000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000FF000000FF000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000FFFF0000FFFF0000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000FFFF0000FFFF0000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000424D3E000000000000003E000000
+      2800000040000000400000000100010000000000000200000000000000000000
+      000000000000000000000000FFFFFF0000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000003FB03BF00FF000003FD037900FF0000
+      0200020100FF000003FD037F1F07000003FB03B91F07000003EF03E91F070000
+      03F703DF1F070000020303831F07000003F703DF1F07000003E803E81F070000
+      03B803B81F07000003D803781F070000020F02071F07000003D8037800FF0000
+      03B803B800FF000003F803F800FF00008001FFFFFFFF00008001A007A0070000
+      8001000200020000800100020002000080010002000200000000000200020000
+      0000000200020000800100020002000080010002000200008001000200020000
+      8001000200020000800100020002000080010002000200008001000200020000
+      8001A07FA07F00008001FFFFFFFF0000FE7FFE7FFE7FFE7FF81FF81FF81FF81F
+      E007E007E007E007800180018001800100000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000008001800180018001E007E007E007E007
+      F81FF81FF81FF81FFE7FFE7FFE7FFE7F00000000000000000000000000000000
+      000000000000}
+  end
+  object Images_Close: TImageList
+    Left = 16
+    Top = 176
+    Bitmap = {
+      494C010102000400040010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
+      0000000000003600000028000000400000001000000001002000000000000010
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000005459BB00343B
+      B2000F19A7000F19A7000F19A7000F19A7000F19A7000F19A7000F19A7000F19
+      A700343BB2005459BB0000000000000000000000000000000000767676005E5E
+      5E00434343004343430043434300434343004343430043434300434343004343
+      43005E5E5E007676760000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000005358BA005B69E1006877
+      EE006575EE006273ED005F71ED005C6EEC00596CEC00566AEB005268EB004F66
+      EA004C63EA003F54DD005358BA000000000000000000757575008B8B8B009999
+      990098989800969696009494940092929200909090008F8F8F008D8D8D008B8B
+      8B00898989007B7B7B0075757500000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000333AB1006D7BEE005766
+      E5003E4FDA003445D5003345D4003343D3003142D2003141D1003040CF003647
+      D3004357DF004C63EA003D46BB0000000000000000005D5D5D009C9C9C008A8A
+      8A00777777006E6E6E006E6E6E006C6C6C006B6B6B006A6A6A00696969006F6F
+      6F007E7E7E008989890068686800000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A700707DEF004354
+      DD004354DA00C5CAF300606DDD003446D5003345D4005F6BDB00C4C8F000404E
+      D2003445D1004F66EA00202DB8000000000000000000434343009E9E9E007B7B
+      7B007A7A7A00D6D6D6008D8D8D006F6F6F006E6E6E008B8B8B00D4D4D4007474
+      74006D6D6D008B8B8B0055555500000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A700737FEF004657
+      DF00C5CAF300FFFFFF00F3F4FD00606EDE00606DDD00F3F4FC00FFFFFF00C4C8
+      F0003040CF005268EB00202EB8000000000000000000434343009F9F9F007E7E
+      7E00D6D6D600FFFFFF00F7F7F7008E8E8E008D8D8D00F6F6F600FFFFFF00D4D4
+      D400696969008D8D8D0056565600000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A7007681EF004859
+      E1006270E300F3F4FD00FFFFFF00F3F4FD00F3F4FD00FFFFFF00F3F4FC005F6B
+      DB003141D000566AEB00222FB800000000000000000043434300A1A1A1008080
+      800091919100F7F7F700FFFFFF00F7F7F700F7F7F700FFFFFF00F6F6F6008B8B
+      8B006A6A6A008F8F8F0057575700000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A7007A87F000495B
+      E300384CDE006371E400F3F4FD00FFFFFF00FFFFFF00F3F4FD00606DDD003343
+      D3003142D1005C71EC002735B900000000000000000043434300A5A5A5008282
+      82007676760092929200F7F7F700FFFFFF00FFFFFF00F7F7F7008D8D8D006C6C
+      6C006B6B6B00949494005B5B5B00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A7008697F3005066
+      E7004059E3006778E700F3F4FD00FFFFFF00FFFFFF00F3F4FD006373DF003B50
+      D700394FD5006983EF002A39BA00000000000000000043434300B1B1B1008A8A
+      8A008080800097979700F7F7F700FFFFFF00FFFFFF00F7F7F700929292007676
+      760075757500A1A1A1005E5E5E00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A7008EA3F4006484
+      ED007994EE00F5F7FD00FFFFFF00F5F7FD00F5F7FD00FFFFFF00F5F7FD00758E
+      E6004F71DE007491F2002B3BBA00000000000000000043434300B9B9B900A0A0
+      A000ACACAC00F9F9F900FFFFFF00F9F9F900F9F9F900FFFFFF00F9F9F900A6A6
+      A6008E8E8E00ABABAB005F5F5F00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A70091A4F4006685
+      EE00CED7F900FFFFFF00F5F7FD007792EC007791EA00F5F7FD00FFFFFF00CCD5
+      F5004F71DE007693F2002B3BBA00000000000000000043434300BABABA00A1A1
+      A100E0E0E000FFFFFF00F9F9F900A9A9A900A9A9A900F9F9F900FFFFFF00DEDE
+      DE008E8E8E00ACACAC005F5F5F00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000000F19A70092A4F5006686
+      EF006283EE00CDD7F8007892EE005277E8005175E600758FE900CBD5F6005C7A
+      E3005475E1007894F2002D3CBA00000000000000000043434300BABABA00A2A2
+      A2009F9F9F00E0E0E000ABABAB009595950093939300A7A7A700DEDEDE009696
+      960092929200ADADAD0060606000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000002C34AD008FA0F500778D
+      F2005D7BEE005C7AED005B79EC005977EA005876E8005674E7005473E6005371
+      E400647FEA00748DF2003F49BA00000000000000000057575700B8B8B800A9A9
+      A9009A9A9A009999990098989800969696009595950093939300929292009090
+      90009C9C9C00A9A9A9006A6A6A00000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000000000004449B3007783E7008998
+      F4008795F4008493F4008191F3007E90F3007B8EF300798DF300768AF3007389
+      F3007187F2005F73E3004449B200000000000000000068686800A0A0A000B2B2
+      B200B0B0B000AEAEAE00ADADAD00ACACAC00A9A9A900A9A9A900A7A7A700A6A6
+      A600A5A5A5009292920068686800000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      00000000000000000000000000000000000000000000000000004449B3002C33
+      AD000F19A7000F19A7000F19A7000F19A7000F19A7000F19A7000F19A7000F19
+      A7002C33AC004449B20000000000000000000000000000000000686868005757
+      5700434343004343430043434300434343004343430043434300434343004343
+      4300575757006868680000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      0000000000000000000000000000000000000000000000000000000000000000
+      000000000000000000000000000000000000424D3E000000000000003E000000
+      2800000040000000100000000100010000000000800000000000000000000000
+      000000000000000000000000FFFFFF00FFFFFFFF00000000C003C00300000000
+      8001800100000000800180010000000080018001000000008001800100000000
+      8001800100000000800180010000000080018001000000008001800100000000
+      8001800100000000800180010000000080018001000000008001800100000000
+      C003C00300000000FFFFFFFF0000000000000000000000000000000000000000
+      000000000000}
+  end
+end
Index: oup/releases/0.34a/Main.pas
===================================================================
--- oup/releases/0.34a/Main.pas	(revision 200)
+++ oup/releases/0.34a/Main.pas	(revision 200)
@@ -0,0 +1,792 @@
+unit Main;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus, Grids,
+  MPHexEditor, ToolWin, ImgList, Tabs,
+  MDITab, TB2Item, TB2Dock, TB2Toolbar, TB2MDI, OneInst,
+  Data, TypeDefs, ConnectionManager,
+  Functions, Settings, Template,
+  RawEdit, BinEdit, Extractor, Preview, TxmpReplace;
+
+type
+  TForm_Main = class(TForm)
+    saved:      TSaveDialog;
+    opend:      TOpenDialog;
+    statbar:    TStatusBar;
+    MenuImages: TImageList;
+    DockTop:    TTBDock;
+    MainMenu:   TTBToolbar;
+    menu_main:  TTBSubmenuItem;
+    menu_loadfile: TTBItem;
+    menu_sep1:  TTBSeparatorItem;
+    menu_settings: TTBItem;
+    menu_sep4:  TTBSeparatorItem;
+    menu_exit:  TTBItem;
+    menu_convert: TTBSubmenuItem;
+    menu_createdb: TTBItem;
+    menu_createlvl: TTBItem;
+    menu_tools: TTBSubmenuItem;
+    menu_preview: TTBItem;
+    menu_binedit: TTBItem;
+    menu_rawedit: TTBItem;
+    menu_txmpreplace: TTBItem;
+    menu_extractor: TTBItem;
+    menu_filecompare: TTBItem;
+    menu_levelstructedit: TTBItem;
+    menu_view: TTBSubmenuItem;
+    menu_windows_cascade: TTBItem;
+    menu_windows_tile: TTBItem;
+    menu_windows_closeall: TTBItem;
+    menu_sep3:  TTBSeparatorItem;
+    menu_windows_next: TTBItem;
+    menu_windows_previous: TTBItem;
+    menu_sep2:  TTBSeparatorItem;
+    menu_About: TTBItem;
+    Toolbar:    TTBToolbar;
+    tbOpen:     TTBItem;
+    DockLeft:   TTBDock;
+    DockRight:  TTBDock;
+    DockBottom: TTBDock;
+    MDIToolbar: TTBToolbar;
+    TBControlItem1: TTBControlItem;
+    MDITab:     TMDITab;
+    menu_toolbars: TTBSubmenuItem;
+    menu_view_mdibar: TTBItem;
+    menu_view_statusbar: TTBItem;
+    menu_view_toolbar: TTBItem;
+    tb_separator1: TTBSeparatorItem;
+    tb_preview: TTBItem;
+    tb_structure: TTBItem;
+    tb_compare: TTBItem;
+    tb_extractor: TTBItem;
+    tb_txmpreplacer: TTBItem;
+    tb_rawedit: TTBItem;
+    tb_datedit: TTBItem;
+    menu_windows_tilevert: TTBItem;
+    tb_meta: TTBItem;
+    menu_meta: TTBItem;
+    TBSeparatorItem1: TTBSeparatorItem;
+    tb_db2dat: TTBItem;
+    tb_dat2db: TTBItem;
+    menu_loaddb: TTBItem;
+    tb_opendb: TTBItem;
+    Images_Close: TImageList;
+    menu_conns: TTBSubmenuItem;
+    menu_windows: TTBSubmenuItem;
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure FormResize(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure ActivateTools(active: Boolean);
+    procedure UpdateStatBar;
+    procedure UpdateConLists;
+    procedure LoadFile(typedb: Boolean);
+    function TryCloseAll: Boolean;
+    procedure MDITabDrawTab(Control: TCustomTabControl; TabIndex: Integer;
+      const Rect: TRect; Active: Boolean);
+    procedure MDITabMouseUp(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure MDITabMouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer);
+    procedure ToolbarDockChanged(Sender: TObject);
+    procedure CreateConnection(filename: String);
+    function CheckConnectionCloseable(index: Integer): Boolean;
+
+    procedure menu_loadfileClick(Sender: TObject);
+    procedure menu_loaddbClick(Sender: TObject);
+    procedure menu_settingsClick(Sender: TObject);
+    procedure menu_exitClick(Sender: TObject);
+
+    procedure menu_createlvlClick(Sender: TObject);
+    procedure menu_createdbClick(Sender: TObject);
+
+    procedure menu_bineditClick(Sender: TObject);
+    procedure menu_filecompareClick(Sender: TObject);
+    procedure menu_raweditClick(Sender: TObject);
+    procedure menu_extractorClick(Sender: TObject);
+    procedure menu_txmpreplaceClick(Sender: TObject);
+    procedure menu_previewClick(Sender: TObject);
+    procedure menu_metaClick(Sender: TObject);
+    function open_child(window_context: String; connection, fileid: Integer): TForm_ToolTemplate;
+
+    procedure menu_windows_cascadeClick(Sender: TObject);
+    procedure menu_windows_tilevertClick(Sender: TObject);
+    procedure menu_windows_tileClick(Sender: TObject);
+    procedure menu_windows_closeallClick(Sender: TObject);
+    procedure menu_windows_previousClick(Sender: TObject);
+    procedure menu_windows_nextClick(Sender: TObject);
+    procedure menu_conns_itemClick(Sender: TObject);
+    procedure menu_windows_itemClick(Sender: TObject);
+    procedure menu_view_mdibarClick(Sender: TObject);
+    procedure menu_view_statusbarClick(Sender: TObject);
+    procedure menu_view_toolbarClick(Sender: TObject);
+
+    procedure menu_AboutClick(Sender: TObject);
+
+    procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA;
+  private
+  public
+    procedure DefaultHandler(var Message); override;
+  end;
+
+var
+  Form_Main: TForm_Main;
+
+implementation
+
+uses
+  LevelDB;
+
+{$R *.dfm}
+
+
+procedure ShowOpenMsg(msg: TStatusMessages);
+begin
+  case msg of
+    SM_AlreadyOpened:    ShowMessage('File already opened.');
+    SM_FileNotFound:     ShowMessage('File not found.');
+    SM_UnknownExtension: ShowMessage('Unknown extension.');
+    SM_IncompatibleFile: ShowMessage('Incompatible file format.');
+    SM_UnknownError:     ShowMessage('Unknown error.');
+  end;
+end;
+
+procedure TForm_Main.CreateConnection(filename: String);
+var
+  RepMsg: TStatusMessages;
+begin
+  ConManager.OpenConnection(filename, RepMsg);
+  ShowOpenMsg(RepMsg);
+  if RepMsg = SM_OK then
+  begin
+    UpdateStatBar;
+    UpdateConLists;
+  end;
+end;
+
+function TForm_Main.CheckConnectionCloseable(index: Integer): Boolean;
+var
+  i: Integer;
+  toolform: TForm_ToolTemplate;
+begin
+  Result := True;
+  if MDITab.MDIChildCount > 0 then
+  begin
+    for i := 0 to MDITab.MDIChildCount - 1 do
+    begin
+      if MDITab.MDIChildren[i] is TForm_ToolTemplate then
+      begin
+        toolform := TForm_ToolTemplate(MDITab.MDIChildren[i]);
+        if toolform.ConnectionID = ConManager.ConnectionByIndex[index].ConnectionID then
+        begin
+          if not toolform.Closeable then
+          begin
+            ShowMessage('Can not close toolwindow: ' + toolform.Caption);
+            Result := False;
+          end;
+        end; 
+      end;
+    end;
+  end;
+end;
+
+
+{ Eine zweite Instanz hat uns ihre Kommandozeilenparameter geschickt }
+procedure TForm_Main.WMCopyData(var Msg: TWMCopyData);
+var
+  strings: TStringList;
+begin
+  if (Msg.CopyDataStruct.dwData = SecondInstMsgId) and (SecondInstMsgId <> 0) then
+  begin
+    Application.BringToFront;
+    
+    strings := TStringList.Create;
+    strings.Text := ParamBlobToStr(Msg.CopyDataStruct.lpData);
+    if strings.Count = 2 then
+    begin
+      if strings.Strings[0] = 'opf' then
+      begin
+        ShowMessage('Load OPF-File: ' + ParamStr(2));
+      end
+      else if (strings.Strings[0] = 'oldb') or (strings.Strings[0] = 'dat') then
+      begin
+        CreateConnection(strings.Strings[1]);
+      end;
+    end;
+  end
+  else
+    inherited;
+end;
+
+{----------------------------------------------------------------------------}
+{ Wir überschreiben den DefaultHandler, der alle Nachrichten zuerst bekommt, }
+{ damit wir auf die Nachricht mit der ID SecondInstMsgId reagieren können.   }
+{ (Dies ist notwendig, da wir jetzt noch nicht wissen welchen Wert           }
+{  die ID haben wird, weswegen wir keine statische Message-Prozedure,        }
+{  so wie bei WM_COPYDATA, schreiben können.)                                }
+{----------------------------------------------------------------------------}
+procedure TForm_Main.DefaultHandler(var Message);
+begin
+  if TMessage(Message).Msg = SecondInstMsgId then
+    { Eine zweite Instanz hat uns nach dem Handle gefragt }
+    { Es wird in die Message-Queue des Threads gepostet.  }
+    PostThreadMessage(TMessage(Message).WParam, SecondInstMsgId, Handle, 0)
+  else
+    inherited;
+end;
+
+
+
+procedure TForm_Main.FormCreate(Sender: TObject);
+begin
+  Self.Caption := 'Oni Un/Packer ' + version;
+  Self.FormResize(Self);
+
+  ConManager.OnCoonnectionListChanged := UpdateConLists;
+
+  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
+    ShowMessage('Warning!' + #13#10 +
+                'It seems like this is the first time you OUP.' + #13#10 +
+                'I do not take any responsibility for messed up data files' + #13+#10 +
+                'Do not forget to make backup copies of your *.dat/*.raw/*.sep files!');
+    AppSettings.DatPath        := ExtractFilepath(Application.EXEname);
+    AppSettings.ExtractPath    := ExtractFilepath(Application.EXEname) + '\extract';
+    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') or (MidStr(ParamStr(1), 1, 3) = 'dat') then
+  begin
+    CreateConnection(ParamStr(2));
+  end;
+  UpdateStatBar;
+end;
+
+
+
+
+procedure TForm_Main.FormResize(Sender: TObject);
+begin
+  statbar.Panels.Items[0].Width := Self.Width - 200;
+  MDITab.Width := Self.Width - 20;
+end;
+
+
+
+
+procedure TForm_Main.MDITabDrawTab(Control: TCustomTabControl;
+  TabIndex: Integer; const Rect: TRect; Active: Boolean);
+var
+  x, y: Integer;
+  iconindex: Integer;
+  caption: String;
+begin
+  iconindex := TMDITab(Control).Glyphs[TabIndex];
+  caption := TMDITab(Control).Captions[TabIndex];
+  if active then
+  begin
+    Control.Canvas.Font.Style := Control.Canvas.Font.Style + [fsItalic];
+    y := Rect.Top + 1;
+  end else
+    y := Rect.Top;
+  if iconindex >= 0 then
+  begin
+    TMDITab(Control).Images.Draw(Control.Canvas, Rect.Left + 4, y, iconindex);
+    x := Rect.Left + 26;
+  end else
+    x := Rect.Left + 4;
+  Control.Canvas.TextOut(x, y + 2, caption);
+  if active then
+    Images_Close.Draw(Control.Canvas, Rect.Right - 18, y, 0)
+  else
+    Images_Close.Draw(Control.Canvas, Rect.Right - 18, y, 1);
+end;
+
+
+procedure TForm_Main.MDITabMouseMove(Sender: TObject; Shift: TShiftState; X,
+  Y: Integer);
+var
+  pt: TPoint;
+  tabIndex: Integer;
+  hint: String;
+  tool: TForm_ToolTemplate;
+begin
+  pt.X := X;
+  pt.Y := Y;
+  tabIndex := MDITab.GetTabAtPos(pt);
+  hint := '';
+
+  if tabIndex >= 0 then
+  begin
+    if MDITab.MDIChildren[tabIndex] is TForm_ToolTemplate then
+    begin
+      tool := TForm_ToolTemplate(MDITab.MDIChildren[tabIndex]);
+      if tool.ConnectionID > -1 then
+        hint := 'Connection: ' +
+              ExtractFileName(ConManager.Connection[tool.ConnectionID].FileName) + #13+#10
+      else
+        hint := 'Connection: none' + #13+#10;
+      if tool.SelectedFile.ID > -1 then
+        hint := hint + 'Selected File: ' +
+              FormatNumber(tool.SelectedFile.ID, 5, '0') + '-' +
+              tool.SelectedFile.Name + '.' +
+              tool.SelectedFile.Extension
+      else
+        hint := hint + 'Selected File: none';
+    end
+    else
+      hint := 'Window: ' + MDITab.MDIChildren[tabIndex].Caption;
+    if hint <> MDITab.Hint then
+    begin
+      MDITab.Hint := hint;
+      MDITab.ShowHint := True;
+    end;
+  end
+  else
+  begin
+    MDITab.ShowHint := False;
+    MDITab.Hint := '';
+  end;
+end;
+
+procedure TForm_Main.MDITabMouseUp(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+var
+  pt: TPoint;
+  tabIndex: Integer;
+  tabRect: TRect;
+  tabX, tabY, tabWidth: Integer;
+begin
+  pt.X := X;
+  pt.Y := Y;
+  tabIndex := MDITab.GetTabAtPos(pt);
+
+//  if (Button = mbRight) and (tabIndex >= 0) then
+//    MDITab.MDIChildren[tabIndex].Close;
+
+  if (Button = mbLeft) and (tabIndex >= 0) then
+  begin
+    tabrect := MDITab.TabRect(tabIndex);
+    tabX := X - tabrect.Left;
+    tabY := Y - tabrect.Top;
+    tabwidth := tabrect.Right - tabrect.Left;
+    if (tabY >= 4) and (tabY <= 17) then
+      if (tabX >= tabwidth - 19) and (tabX <= tabwidth - 7) then
+        MDITab.MDIChildren[tabIndex].Close;
+  end;
+end;
+
+
+
+
+procedure TForm_Main.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 TForm_Main.ActivateTools(active: Boolean);
+begin
+  menu_tools.Enabled := active;
+  tb_preview.Enabled := active;
+  tb_datedit.Enabled := active;
+  tb_rawedit.Enabled := active;
+  tb_txmpreplacer.Enabled := active;
+  tb_extractor.Enabled := active;
+//  tb_compare.Enabled := active;
+//  tb_structure.Enabled := active;
+end;
+
+procedure TForm_Main.UpdateStatBar;
+begin
+  if ConManager.Count > 0 then
+  begin
+    Self.Caption      := 'Oni Un/Packer ' + version;
+    ActivateTools(True);
+    statbar.Panels.Items[1].Text := 'Connections: ' + IntToStr(ConManager.Count);
+  end
+  else
+  begin
+    Self.Caption      := 'Oni Un/Packer ' + version;
+    statbar.Panels.Items[0].Text := '';
+    statbar.Panels.Items[1].Text := 'Connections: -';
+    statbar.Panels.Items[2].Text := '';
+    ActivateTools(False);
+  end;
+  menu_conns.Enabled := ConManager.Count > 0;
+end;
+
+
+
+
+procedure TForm_Main.ToolbarDockChanged(Sender: TObject);
+var
+  toolbar: TTBToolbar;
+  position: TTBDockPosition;
+  mode: TTBItemDisplayMode;
+  i: Integer;
+begin
+  toolbar := TTBToolbar(Sender);
+  if toolbar.Floating then
+    mode := nbdmImageAndText
+  else begin
+    position := toolbar.CurrentDock.Position;
+    if position in [dpLeft, dpRight] then
+      mode := nbdmDefault
+    else
+      mode := nbdmImageAndText;
+  end;
+  for i := 0 to toolbar.Items.Count - 1 do
+    toolbar.Items.Items[i].DisplayMode := mode;
+end;
+
+function TForm_Main.TryCloseAll: Boolean;
+begin
+  menu_windows_closeallClick(Self);
+  Application.ProcessMessages;
+  if MDITab.MDIChildCount = 0 then
+    Result := True
+  else
+    Result := False;
+end;
+
+
+procedure TForm_Main.UpdateConLists;
+var
+  i: Integer;
+  entry: TTBItem;
+begin
+  if MDITab.MDIChildCount > 0 then
+    for i := 0 to MDITab.MDIChildCount - 1 do
+      if MDITab.MDIChildren[i] is TForm_ToolTemplate then
+        TForm_ToolTemplate(MDITab.MDIChildren[i]).UpdateConList;
+
+  menu_conns.Clear;
+  if ConManager.Count > 0 then
+  begin
+    for i := 0 to ConManager.Count - 1 do
+    begin
+      entry := TTBItem.Create(menu_conns);
+      entry.Caption := ExtractFileName(ConManager.ConnectionByIndex[i].FileName);
+      entry.Name := 'menu_conn_' + IntToStr(i);
+      entry.OnClick := menu_conns_itemClick;
+      menu_conns.Add(entry);
+      entry := nil;
+    end;
+  end;
+end;
+
+
+procedure TForm_Main.LoadFile(typedb: Boolean);
+var
+  i: Integer;
+begin
+  opend.InitialDir := AppSettings.DatPath;
+  opend.Filter     := 'Compatible level files|*.dat;*.oldb|Oni level (*.dat)|*.dat|OUP level database (*.oldb)|*.oldb|Any (*.*)|*';
+  if typedb then
+    opend.FilterIndex := 3
+  else
+    opend.FilterIndex := 2;
+  if opend.Execute then
+  begin
+    if opend.Files.Count > 0 then
+      for i := 0 to opend.Files.Count - 1 do
+        CreateConnection(opend.Files.Strings[i]);
+    AppSettings.DatPath := ExtractFilepath(opend.FileName);
+  end;
+  UpdateStatBar;
+end;
+
+
+ {#################################}
+ {##### Main-Menu-Handlers    #####}
+ {#################################}
+procedure TForm_Main.menu_loaddbClick(Sender: TObject);
+begin
+  LoadFile(True);
+end;
+
+procedure TForm_Main.menu_loadfileClick(Sender: TObject);
+begin
+  LoadFile(False);
+end;
+
+
+procedure TForm_Main.menu_settingsClick(Sender: TObject);
+begin
+  Form_Settings.Visible := True;
+  Self.Enabled   := False;
+end;
+
+
+procedure TForm_Main.menu_exitClick(Sender: TObject);
+begin
+  Self.Close;
+end;
+
+
+ {####################################}
+ {##### Converters-Menu-Handlers #####}
+ {####################################}
+procedure TForm_Main.menu_createdbClick(Sender: TObject);
+begin
+//  ShowMessage('Not yet usable');
+
+  opend.Filter     := 'Oni-Dat-Files|*.dat';
+  saved.Filter     := 'OUP-Level-DB (*.oldb)|*.oldb';
+  saved.DefaultExt := 'oldb';
+  if opend.Execute then
+    if saved.Execute then
+      Form_LevelDB.CreateDatabase(opend.FileName, saved.FileName);
+end;
+
+
+procedure TForm_Main.menu_createlvlClick(Sender: TObject);
+begin
+//  ShowMessage('Not yet usable');
+
+  opend.Filter     := 'OUP-Level-DB (*.oldb)|*.oldb';
+  saved.Filter     := 'Oni-Dat-Files|*.dat';
+  saved.DefaultExt := 'dat';
+  if opend.Execute then
+    if saved.Execute then
+      Form_LevelDB.CreateLevel(opend.FileName, saved.FileName);
+end;
+
+
+ {#################################}
+ {##### Tools-Menu-Handlers   #####}
+ {#################################}
+procedure TForm_Main.menu_previewClick(Sender: TObject);
+begin
+  open_child('preview', -1, -1);
+end;
+
+procedure TForm_Main.menu_bineditClick(Sender: TObject);
+begin
+  open_child('binedit', -1, -1);
+end;
+
+procedure TForm_Main.menu_raweditClick(Sender: TObject);
+begin
+  open_child('rawedit', -1, -1);
+end;
+
+procedure TForm_Main.menu_txmpreplaceClick(Sender: TObject);
+begin
+  open_child('txmpreplace', -1, -1);
+end;
+
+procedure TForm_Main.menu_extractorClick(Sender: TObject);
+begin
+  open_child('extractor', -1, -1);
+end;
+
+procedure TForm_Main.menu_metaClick(Sender: TObject);
+begin
+  ShowMessage('TBD');
+end;
+
+procedure TForm_Main.menu_filecompareClick(Sender: TObject);
+begin
+  open_child('compare', -1, -1);
+end;
+
+
+ {#################################}
+ {#####   View-Menu-Handlers  #####}
+ {#################################}
+procedure TForm_Main.menu_windows_cascadeClick(Sender: TObject);
+begin
+  Self.Cascade;
+end;
+
+procedure TForm_Main.menu_windows_tilevertClick(Sender: TObject);
+begin
+  Self.TileMode := tbVertical;
+  Self.Tile;
+end;
+
+procedure TForm_Main.menu_windows_tileClick(Sender: TObject);
+begin
+  Self.TileMode := tbHorizontal;
+  Self.Tile;
+end;
+
+procedure TForm_Main.menu_windows_closeallClick(Sender: TObject);
+begin
+  MDITab.CloseAll;
+end;
+
+procedure TForm_Main.menu_windows_nextClick(Sender: TObject);
+begin
+  if MDIChildCount > 1 then
+    if MDITab.TabIndex = MDITab.MDIChildCount - 1 then
+      MDITab.MDIChildren[0].BringToFront
+    else
+      MDITab.MDIChildren[MDITab.TabIndex + 1].BringToFront;
+end;
+
+procedure TForm_Main.menu_windows_previousClick(Sender: TObject);
+begin
+  if MDIChildCount > 1 then
+    if MDITab.TabIndex = 0 then
+      MDITab.MDIChildren[MDITab.MDIChildCount - 1].BringToFront
+    else
+      MDITab.MDIChildren[MDITab.TabIndex - 1].BringToFront;
+end;
+
+
+ {##################################}
+ {#####  Windows-Menu-Handlers #####}
+ {##################################}
+procedure TForm_Main.menu_windows_itemClick(Sender: TObject);
+var
+  name: String;
+begin
+  name := TTBItem(Sender).Name;
+end;
+
+
+
+ {######################################}
+ {#####  Connections-Menu-Handlers #####}
+ {######################################}
+procedure TForm_Main.menu_conns_itemClick(Sender: TObject);
+var
+  name: String;
+  index: Integer;
+  RepMsg: TStatusMessages;
+begin
+//  name := TTBItem(Sender).Caption;
+  index := TTBItem(Sender).Parent.IndexOf(TTBItem(Sender));
+  name := ExtractFileName(ConManager.ConnectionByIndex[index].FileName);
+  if MessageBox(Handle, PChar('Do you really want to close data-connection to' +#13+#10+
+        name + '?'), PChar('Close?'), MB_YESNO + MB_ICONQUESTION) = ID_YES then
+  begin
+    CheckConnectionCloseable(index);
+    ConManager.CloseConnectionByIndex(index, RepMsg);
+    ShowOpenMsg(RepMsg);
+    UpdateConLists;
+  end;
+  UpdateStatBar;
+end;
+
+
+ {###################################}
+ {#####  Toolbars-Menu-Handlers #####}
+ {###################################}
+procedure TForm_Main.menu_view_toolbarClick(Sender: TObject);
+begin
+  menu_view_toolbar.Checked := not menu_view_toolbar.Checked;
+  Toolbar.Visible := menu_view_toolbar.Checked;
+end;
+
+procedure TForm_Main.menu_view_statusbarClick(Sender: TObject);
+begin
+  menu_view_statusbar.Checked := not menu_view_statusbar.Checked;
+  statbar.Visible := menu_view_statusbar.Checked;
+end;
+
+procedure TForm_Main.menu_view_mdibarClick(Sender: TObject);
+begin
+  menu_view_mdibar.Checked := not menu_view_mdibar.Checked;
+  mditoolbar.Visible := menu_view_mdibar.Checked;
+end;
+
+
+
+procedure TForm_Main.menu_AboutClick(Sender: TObject);
+begin
+  ShowMessage('Will be implemented later ;)');
+end;
+
+
+
+
+
+function TForm_Main.open_child(window_context: String; connection, fileid: Integer): TForm_ToolTemplate;
+type
+  TTemplate = class of TForm_ToolTemplate;
+  TTool = record
+      name: String;
+      icon: Integer;
+      caption: String;
+      classt: TTemplate;
+  end;
+const
+  Tools: array[0..4] of TTool = (
+    (name: 'binedit';     icon: 5; caption: 'Binary .dat-Editor'; classt: TForm_BinEdit),
+    (name: 'extractor';   icon: 8; caption: 'Extractor';          classt: TForm_Extractor),
+    (name: 'preview';     icon: 4; caption: 'Preview-Window';     classt: TForm_Preview),
+    (name: 'rawedit';     icon: 6; caption: 'Binary .raw-Editor'; classt: TForm_RawEdit),
+    (name: 'txmpreplace'; icon: 7; caption: 'TXMP Replacer';      classt: TForm_TxmpReplace)
+  );
+var
+  toolform:    TForm_ToolTemplate;
+  i:           Integer;
+  tag:         Integer;
+  iconindex:   Integer;
+begin
+  Result := nil;
+
+  tag := 1;
+  if MDIChildCount > 0 then
+    for i := 0 to MDIChildCount - 1 do
+      if MDIChildren[i].Tag >= tag then
+        tag := MDIChildren[i].Tag + 1;
+
+  iconindex := -1;
+
+  toolform := nil;
+
+  for i := 0 to High(Tools) do
+    if Tools[i].name = window_context then
+      Break;
+  if i < Length(Tools) then
+  begin
+    toolform         := TTemplate(Tools[i].classt).Create(Self);
+    toolform.Caption := Tools[i].caption + ' ' + IntToStr(tag) + '       ';
+    iconindex        := Tools[i].icon;
+  end else begin
+    ShowMessage('WindowContext not found!');
+  end;
+
+  if Assigned(toolform) then
+  begin
+    toolform.Name    := window_context + IntToStr(tag);
+    toolform.Tag     := tag;
+    MDITab.AddTab(TForm(toolform), iconindex);
+    toolform.Caption := AnsiReplaceStr(toolform.Caption, '       ', '');
+    if connection > -1 then
+    begin
+      toolform.SelectConnection(connection);
+      if fileid > -1 then
+        toolform.SelectFileID(connection, fileid);
+    end;
+    Result := toolform;
+  end;
+end;
+
+end.
Index: oup/releases/0.34a/OniUnPacker.bdsproj
===================================================================
--- oup/releases/0.34a/OniUnPacker.bdsproj	(revision 200)
+++ oup/releases/0.34a/OniUnPacker.bdsproj	(revision 200)
@@ -0,0 +1,182 @@
+﻿<?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">dat "C:\Spiele\Oni\GameDataFolder\level1_final.dat"</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="d:\programme\borland\bds\3.0\Bin\dbwebxprt.bpl">Borland Web Wizard Package</Excluded_Packages>
+    </Excluded_Packages>
+  </Delphi.Personality>
+</BorlandProject>
Index: oup/releases/0.34a/OniUnPacker.dpr
===================================================================
--- oup/releases/0.34a/OniUnPacker.dpr	(revision 200)
+++ oup/releases/0.34a/OniUnPacker.dpr	(revision 200)
@@ -0,0 +1,47 @@
+program OniUnPacker;
+
+uses
+  Forms,
+  FTypeReg in 'ImportedStuff\FTypeReg.pas',
+  FolderBrowser in 'ImportedStuff\FolderBrowser.pas',
+  OneInst in 'ImportedStuff\OneInst.pas',
+  Data in 'Global\Data.pas',
+  TypeDefs in 'Global\TypeDefs.pas',
+  DataAccess in 'DataAccess\DataAccess.pas',
+  Access_OniArchive in 'DataAccess\Access_OniArchive.pas',
+  Access_OUP_ADB in 'DataAccess\Access_OUP_ADB.pas',
+  ConnectionManager in 'DataAccess\ConnectionManager.pas',
+  Main in 'Main.pas' {Form_Main},
+  Settings in 'Settings.pas' {Form_Settings},
+  Template in 'Tools\Template.pas' {Form_ToolTemplate},
+  Preview in 'Tools\Preview.pas' {Form_Preview},
+  OniImgClass in 'Global\OniImgClass.pas',
+  Functions in 'Global\Functions.pas',
+  RawList in 'Global\RawList.pas',
+  DatStructureLoader in 'Global\DatStructureLoader.pas',
+  Exporters in 'Global\Exporters.pas',
+  ValueEdit in 'Helper\ValueEdit.pas' {Form_ValueEdit},
+  BinEdit in 'Tools\BinEdit.pas' {Form_BinEdit},
+  RawEdit in 'Tools\RawEdit.pas' {Form_RawEdit},
+  Extractor in 'Tools\Extractor.pas' {Form_Extractor},
+  TxmpReplace in 'Tools\TxmpReplace.pas' {Form_TxmpReplace},
+  WhatLinksHere in 'Helper\WhatLinksHere.pas' {Form_WhatLinksHere},
+  DatLinks in 'Global\DatLinks.pas',
+  _DataTypes in 'FileClasses\_DataTypes.pas',
+  _FileTypes in 'FileClasses\_FileTypes.pas',
+  LevelDB in 'Helper\LevelDB.pas' {Form_LevelDB},
+  Img_DDSTypes in 'Global\Img_DDSTypes.pas';
+
+{$R *.res}
+{$R ExtraIcos.res}
+
+begin
+  Application.Initialize;
+  Application.Title := 'Oni Un/Packer';
+  Application.CreateForm(TForm_Main, Form_Main);
+  Application.CreateForm(TForm_Settings, Form_Settings);
+  Application.CreateForm(TForm_ValueEdit, Form_ValueEdit);
+  Application.CreateForm(TForm_WhatLinksHere, Form_WhatLinksHere);
+  Application.CreateForm(TForm_LevelDB, Form_LevelDB);
+  Application.Run;
+end.
Index: oup/releases/0.34a/Settings.dfm
===================================================================
--- oup/releases/0.34a/Settings.dfm	(revision 200)
+++ oup/releases/0.34a/Settings.dfm	(revision 200)
@@ -0,0 +1,102 @@
+object Form_Settings: TForm_Settings
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 197
+  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 = 8
+    Width = 145
+    Height = 26
+    AutoSize = False
+    Caption = 'CharSet for displaying strings in ValueViewer/StructViewer:'
+    WordWrap = True
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 168
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 0
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 112
+    Top = 168
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 1
+    OnClick = btn_cancelClick
+  end
+  object combo_charset: TComboBox
+    Left = 160
+    Top = 9
+    Width = 156
+    Height = 21
+    Style = csDropDownList
+    ItemHeight = 13
+    ItemIndex = 0
+    TabOrder = 2
+    Text = 'default - 1'
+    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 = 48
+    Width = 209
+    Height = 17
+    Caption = 'Hide "Unused" data in StructureViewer'
+    TabOrder = 3
+  end
+  object check_reg_dat: TCheckBox
+    Left = 8
+    Top = 87
+    Width = 180
+    Height = 17
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 4
+  end
+  object check_reg_oldb: TCheckBox
+    Left = 8
+    Top = 110
+    Width = 180
+    Height = 17
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 5
+  end
+  object check_reg_opf: TCheckBox
+    Left = 8
+    Top = 133
+    Width = 180
+    Height = 17
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 6
+  end
+end
Index: oup/releases/0.34a/Settings.pas
===================================================================
--- oup/releases/0.34a/Settings.pas	(revision 200)
+++ oup/releases/0.34a/Settings.pas	(revision 200)
@@ -0,0 +1,192 @@
+unit Settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils;
+
+type
+  TForm_Settings = class(TForm)
+    btn_ok:     TButton;
+    btn_cancel: TButton;
+    label_charset: TLabel;
+    combo_charset: TComboBox;
+    check_hideunused: TCheckBox;
+    check_reg_dat: TCheckBox;
+    check_reg_oldb: TCheckBox;
+    check_reg_opf: TCheckBox;
+    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; iconindex: Integer; reg: Boolean): Integer;
+  private
+  public
+  end;
+
+var
+  Form_Settings: TForm_Settings;
+
+implementation
+
+{$R *.dfm}
+
+uses
+  Main, Data, FTypeReg;
+
+
+
+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 TForm_Settings.RegisterExtension(ext: String; iconindex: Integer; reg: Boolean): Integer;
+var
+  ftr:     TFileTypeRegistration;
+  temps:   String;
+  warnmsg: String;
+begin
+  Result := -1;
+  ftr := TFileTypeRegistration.Create;
+  if reg then
+  begin
+    if ExtensionRegistered(ext, temps) then
+      if not ftr.UnregisterExtension(ext) then
+        ShowMessage('Could not unregister ' + ext + '-files');
+    if ftr.RegisterType(ext, 'ONI' + ext, 'ONI ' + ext + '-file', Application.EXEname, iconindex) then
+    begin
+      ftr.AddHandler('open', '"' + Application.EXEname + '" ' + MidStr(
+        ext, 2, Length(ext) - 1) + ' "%1"');
+      ftr.SetDefaultHandler;
+    end;
+  end else begin
+    if ExtensionRegistered(ext, temps) then
+      if not ftr.UnregisterExtension(ext) then
+        ShowMessage('Could not unregister ' + ext + '-files');
+  end;
+  ftr.Free;
+end;
+
+
+
+procedure TForm_Settings.btn_cancelClick(Sender: TObject);
+begin
+  Self.Close;
+end;
+
+
+
+procedure TForm_Settings.btn_okClick(Sender: TObject);
+var
+  temps: String;
+begin
+  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;
+
+  if check_reg_dat.Checked then
+  begin
+    if ExtensionRegistered('.dat', temps) then
+    begin
+      if temps <> 'ONI.dat' then
+        if MessageBox(Self.Handle, PChar('.dat-files already registered to "' +
+              temps+'". Reregister?'), PChar('Reregister?'),
+              MB_YESNO + MB_ICONQUESTION) = ID_YES then
+          RegisterExtension('.dat', 2, True);
+    end else
+      RegisterExtension('.dat', 2, True);
+  end else
+    RegisterExtension('.dat', 2, False);
+
+  if check_reg_oldb.Checked then
+  begin
+    if ExtensionRegistered('.oldb', temps) then
+    begin
+      if temps <> 'ONI.oldb' then
+        if MessageBox(Self.Handle, PChar('.oldb-files already registered to "' +
+              temps+'". Reregister?'), PChar('Reregister?'),
+              MB_YESNO + MB_ICONQUESTION) = ID_YES then
+          RegisterExtension('.oldb', 1, True);
+    end else
+      RegisterExtension('.oldb', 1, True);
+  end else
+    RegisterExtension('.oldb', 1, False);
+
+  if check_reg_opf.Checked then
+  begin
+    if ExtensionRegistered('.opf', temps) then
+    begin
+      if temps <> 'ONI.opf' then
+        if MessageBox(Self.Handle, PChar('.opf-files already registered to "' +
+              temps+'". Reregister?'), PChar('Reregister?'),
+              MB_YESNO + MB_ICONQUESTION) = ID_YES then
+          RegisterExtension('.opf', 0, True);
+    end else
+      RegisterExtension('.opf', 0, True);
+  end else
+    RegisterExtension('.opf', 0, False);
+
+  Self.Close;
+end;
+
+
+
+procedure TForm_Settings.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+begin
+  CanClose      := False;
+  Self.Visible  := False;
+  Form_Main.Enabled := True;
+  Form_Main.SetFocus;
+end;
+
+
+
+procedure TForm_Settings.FormShow(Sender: TObject);
+var
+  temps: String;
+  i:     Byte;
+begin
+  if ExtensionRegistered('.dat', temps) then
+    check_reg_dat.Checked := temps = 'ONI.dat'
+  else
+    check_reg_dat.Checked := False;
+
+  if ExtensionRegistered('.oldb', temps) then
+    check_reg_oldb.Checked := temps = 'ONI.oldb'
+  else
+    check_reg_oldb.Checked := False;
+
+  if ExtensionRegistered('.opf', temps) then
+    check_reg_opf.Checked := temps = 'ONI.opf'
+  else
+    check_reg_opf.Checked := False;
+
+  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.34a/Tools/BinEdit.dfm
===================================================================
--- oup/releases/0.34a/Tools/BinEdit.dfm	(revision 200)
+++ oup/releases/0.34a/Tools/BinEdit.dfm	(revision 200)
@@ -0,0 +1,266 @@
+inherited Form_BinEdit: TForm_BinEdit
+  Caption = 'BinEdit'
+  KeyPreview = True
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  ExplicitWidth = 500
+  ExplicitHeight = 450
+  PixelsPerInch = 96
+  TextHeight = 13
+  inherited panel_files: TPanel
+    inherited filelist: TListBox
+      Height = 210
+      ExplicitHeight = 210
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 363
+      Width = 200
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 2
+      DesignSize = (
+        200
+        60)
+      object btn_export: TButton
+        Left = 4
+        Top = 4
+        Width = 190
+        Height = 25
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Export to file...'
+        TabOrder = 0
+        OnClick = popup_exportClick
+      end
+      object btn_import: TButton
+        Left = 4
+        Top = 32
+        Width = 190
+        Height = 25
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Import from file...'
+        TabOrder = 1
+        OnClick = popup_importClick
+      end
+    end
+  end
+  inherited content: TPanel
+    object Splitter2: TSplitter
+      Left = 0
+      Top = 209
+      Width = 283
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitWidth = 425
+    end
+    object Splitter3: TSplitter
+      Left = 0
+      Top = 318
+      Width = 283
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitLeft = -9
+      ExplicitTop = 430
+      ExplicitWidth = 425
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 283
+      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 = 283
+      Height = 100
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      ScrollBars = ssVertical
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 326
+      Width = 283
+      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 value_viewer_context: TPopupMenu [3]
+    AutoHotkeys = maManual
+    AutoLineReduction = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 280
+    Top = 232
+    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 [4]
+    OnColumnChange = VTHPopupColumnChange
+    Left = 272
+    Top = 376
+  end
+end
Index: oup/releases/0.34a/Tools/BinEdit.pas
===================================================================
--- oup/releases/0.34a/Tools/BinEdit.pas	(revision 200)
+++ oup/releases/0.34a/Tools/BinEdit.pas	(revision 200)
@@ -0,0 +1,1005 @@
+unit BinEdit;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Template, StdCtrls, ExtCtrls, VirtualTrees, Grids, Wrapgrid,
+  MPHexEditor, VTHeaderPopup, Menus, StrUtils, Clipbrd,
+  Data, TypeDefs, ConnectionManager, Buttons;
+
+type
+  TForm_BinEdit = class(TForm_ToolTemplate)
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    value_viewer: TWrapGrid;
+    VST: TVirtualStringTree;
+    Splitter3: TSplitter;
+    value_viewer_context: TPopupMenu;
+    value_viewer_context_copy: TMenuItem;
+    value_viewer_context_copyasdec: TMenuItem;
+    value_viewer_context_copyasfloat: TMenuItem;
+    value_viewer_context_copyasbitset: TMenuItem;
+    value_viewer_context_copyasstring: TMenuItem;
+    value_viewer_context_copyashex: TMenuItem;
+    VTHPopup: TVTHeaderPopupMenu;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    procedure FormCreate(Sender: TObject);
+    procedure NewFile(fileinfo: TFileInfo);
+
+    procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    procedure hexSelectionChanged(Sender: TObject);
+    procedure hexChange(Sender: TObject);
+
+    procedure LoadDat(_fileid: Integer);
+    function Save: Boolean;
+    function GetValue(datatype: Word; offset: Integer): String;
+    procedure SetNewValue(datatype: Word; offset: Integer; Value: String);
+
+    procedure WriteStructureInfos;
+    procedure ClearStructViewer;
+    procedure VSTDblClick(Sender: TObject);
+    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex);
+    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 ClearValues;
+    procedure WriteValues;
+    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);
+  private
+    fileid: Integer;
+    ConID: Integer;
+    rawlist: TRawDataList;
+  public
+  end;
+
+var
+  Form_BinEdit: TForm_BinEdit;
+
+implementation
+
+uses ValueEdit, Main, Functions, DatStructureLoader, RawEdit;
+{$R *.dfm}
+
+type
+  PNodeData = ^TNodeData;
+
+  TNodeData = record
+    Caption:  String;
+    Offset:   LongInt;
+    DataType: Word;
+    Value:    String;
+    Description: String;
+  end;
+
+
+
+procedure TForm_BinEdit.FormCreate(Sender: TObject);
+begin
+  inherited;
+  Self.OnNewFileSelected := NewFile;
+
+  Self.Caption := '';
+  fileid     := 0;
+  VST.NodeDataSize := SizeOf(TNodeData);
+  value_viewer.ColCount := 2;
+  value_viewer.RowCount := 8;
+  value_viewer.FixedRows := 1;
+  value_viewer.FixedCols := 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] := 120;
+  value_viewer.ColWidths[1] := 1000;
+//  hex.Height := content.Height - 215;
+  //
+  value_viewer.Font.Charset := AppSettings.CharSet;
+  VST.Font.Charset := AppSettings.CharSet;
+  hex.Translation := tkAsIs;
+  hex.Font.Charset := AppSettings.CharSet;
+  //
+end;
+
+procedure TForm_BinEdit.NewFile(fileinfo: TFileInfo);
+begin
+  LoadDat(fileinfo.ID);
+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 TForm_BinEdit.LoadDat(_fileid: Integer);
+var
+  mem:  TMemoryStream;
+begin
+  if ConID <> -1 then
+  begin
+    if hex.Modified then
+    begin
+      if not Save then
+      begin
+        Self.SelectFileID(ConnectionID, FileID);
+        Exit;
+      end;
+    end;
+  end;
+  if _fileid >= 0 then
+  begin
+    fileid := _fileid;
+    ConID := ConnectionID;
+    if ConManager.Connection[ConID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]) <> fileid then
+      Self.SelectFileID(ConnectionID, fileid);
+    Self.ClearStructViewer;
+    mem := nil;
+    ConManager.Connection[ConID].LoadDatFile(fileid, TStream(mem));
+    rawlist := ConManager.Connection[ConID].GetRawList(fileid);
+    hex.LoadFromStream(mem);
+    mem.Free;
+    ClearValues;
+    WriteStructureInfos;
+  end
+  else
+  begin
+    fileid := _fileid;
+    ConID := -1;
+    Self.ClearStructViewer;
+    ClearValues;
+    hex.DataSize := 0;
+    SetLength(rawlist, 0);
+  end;
+end;
+
+
+
+function TForm_BinEdit.GetValue(datatype: Word; offset: Integer): String;
+var
+  Data: TByteData;
+  i:    Integer;
+  tempi: Integer;
+  floatformat: TFormatSettings;
+begin
+  floatformat.DecimalSeparator := '.';
+  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), floatformat);
+    end;
+    10:
+      Result := IntToBin(hex.Data[offset]);
+    11:
+    begin
+      if Length(rawlist) > 0 then
+      begin
+        for i := 0 to High(rawlist) do
+          if rawlist[i].SrcOffset = offset then
+          begin
+            if rawlist[i].RawAddr > 0 then
+              Result := '0x' + IntToHex(rawlist[i].RawAddr, 8)
+            else
+              Result := 'unused';
+            Break;
+          end;
+        if i > High(rawlist) then
+          Result := 'unused';
+      end;
+    end;
+    12:
+      if hex.Data[offset] = 1 then
+        Result := FormatNumber(hex.Data[offset + 1] + hex.Data[offset + 2] * 256 +
+          hex.Data[offset + 3] * 256 * 256, 5, '0')
+      else
+        Result := 'no link';
+    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 TForm_BinEdit.WriteStructureInfos;
+var
+  i, j:    Integer;
+  pdata:   PNodeData;
+  Data:    TNodeData;
+  node:    PVirtualNode;
+  structs: TStructDef;
+begin
+  VST.BeginUpdate;
+  if VST.RootNodeCount = 0 then
+  begin
+    structs := LoadStructureDefinition(ConID, 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  := StrToInt('$'+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 TForm_BinEdit.ClearValues;
+var
+  i: Byte;
+begin
+  for i := 1 to value_viewer.RowCount - 1 do
+  begin
+    value_viewer.Cells[1, i] := '';
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.WriteValues;
+var
+  i, j:  Integer;
+  Data:  TByteData;
+  str:   String;
+  Value: Integer;
+  floatformat: TFormatSettings;
+begin
+  floatformat.DecimalSeparator := '.';
+  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), floatformat);
+      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.SelStart + j) < hex.DataSize do
+        begin
+          if hex.Data[hex.SelStart + j] = 0 then
+            Break;
+          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;
+
+
+
+
+function TForm_BinEdit.Save: Boolean;
+var
+  mem:  TMemoryStream;
+  i:    Integer;
+begin
+  case MessageBox(Self.Handle, PChar('Save changes to file ' +
+      ConManager.Connection[ConID].GetFileInfo(fileid).Name + '?'), PChar('Data changed...'),
+      MB_YESNOCANCEL + MB_ICONQUESTION) of
+    idYes:
+    begin
+      mem := TMemoryStream.Create;
+      hex.SaveToStream(mem);
+      mem.Seek(0, soFromBeginning);
+      ConManager.Connection[ConID].UpdateDatFile(fileid, mem);
+      mem.Free;
+      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 TForm_BinEdit.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+begin
+  if hex.Modified then
+  begin
+    if not Save then
+      CanClose := False;
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.ClearStructViewer;
+begin
+  VST.Clear;
+end;
+
+
+
+
+
+
+procedure TForm_BinEdit.hexChange(Sender: TObject);
+begin
+  ClearValues;
+  if hex.DataSize > 0 then
+  begin
+    WriteStructureInfos;
+    WriteValues;
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.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 TForm_BinEdit.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) < GetDataTypeLength(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 TForm_BinEdit.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 TForm_BinEdit.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 TForm_BinEdit.value_viewer_context_copyClick(Sender: TObject);
+var
+  Name:  String;
+  Value: Integer;
+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 TForm_BinEdit.VSTDblClick(Sender: TObject);
+var
+  node: PVirtualNode;
+  nodedata: PNodeData;
+  rawinfo: TRawDataInfo;
+  form: TForm_ToolTemplate;
+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
+      Form_ValueEdit.MakeVarInput(nodedata.Caption, nodedata.offset,
+        nodedata.datatype, nodedata.Value, Self);
+    end
+    else
+    begin
+      if (nodedata.DataType = 11) and (nodedata.Value <> 'unused') then
+      begin
+        rawinfo := ConManager.Connection[ConID].GetRawInfo(fileid, nodedata.offset);
+        if rawinfo.RawSize > 0 then
+        begin
+          form := nil;
+          form := Form_Main.open_child('rawedit', ConID, fileid);
+          if Assigned(form) then
+            TForm_RawEdit(form).LoadRaw(rawinfo);
+        end;
+      end;
+      if (nodedata.DataType = 12) and (nodedata.Value <> 'no link') then
+      begin
+        if (StrToInt(nodedata.Value) < ConManager.Connection[ConID].GetFileCount) and
+          (StrToInt(nodedata.Value) > 0) and
+          (StrToInt(nodedata.Value) <> fileid) then
+        begin
+          if ConManager.Connection[ConID].GetFileInfo(StrToInt(nodedata.Value)).Size > 0 then
+            Form_Main.open_child('binedit', ConID, StrToInt(nodedata.Value))
+          else
+            ShowMessage('Linked filed is a zero-byte-file');
+        end;
+      end;
+      if (nodedata.DataType >= 100) and (nodedata.DataType <= 300) then
+      begin
+        form := Form_Main.open_child('binedit', ConID, -1);
+        if Assigned(form) then
+          form.SetFileFilters(nodedata.Value, '', False);
+      end;
+    end;
+
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.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 + GetDataTypeLength(Data.DataType) - 1;
+  end
+  else
+  begin
+    hex.SelStart := Data.Offset;
+    hex.SelEnd   := Data.Offset + StrToInt(Data.Value) - 1;
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.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(StrToInt(Data.Value)) + ' Bytes';
+      4:
+        CellText := Data.Description;
+    end;
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+begin
+  if Sender.Columns.Items[column].Position < 1 then
+    Sender.Columns.Items[column].Position := OldPosition;
+end;
+
+
+
+
+procedure TForm_BinEdit.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 TForm_BinEdit.SetNewValue(datatype: Word; offset: Integer; Value: String);
+var
+  Data: TByteData;
+  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 TForm_BinEdit.value_viewerDblClick(Sender: TObject);
+var
+  offset:     Integer;
+  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);
+    Form_ValueEdit.MakeVarInput(objectname, offset, datatype, Value, Self);
+  end;
+end;
+
+
+
+
+procedure TForm_BinEdit.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;
+
+
+begin
+  AddToolListEntry('binedit', 'Binary .dat-Editor', '');
+end.
Index: oup/releases/0.34a/Tools/Extractor.dfm
===================================================================
--- oup/releases/0.34a/Tools/Extractor.dfm	(revision 200)
+++ oup/releases/0.34a/Tools/Extractor.dfm	(revision 200)
@@ -0,0 +1,221 @@
+inherited Form_Extractor: TForm_Extractor
+  Caption = 'Extractor'
+  ClientHeight = 491
+  ExplicitHeight = 518
+  PixelsPerInch = 96
+  TextHeight = 13
+  inherited Splitter1: TSplitter
+    Left = 483
+    Height = 491
+    Align = alRight
+    Visible = False
+    ExplicitLeft = 172
+    ExplicitTop = -8
+    ExplicitHeight = 423
+  end
+  inherited panel_files: TPanel
+    Width = 333
+    Height = 491
+    ExplicitWidth = 333
+    ExplicitHeight = 491
+    inherited filelist: TListBox
+      Width = 333
+      Height = 338
+      MultiSelect = True
+      ExplicitWidth = 333
+      ExplicitHeight = 338
+    end
+    inherited panel_extension: TPanel
+      Width = 333
+      ExplicitWidth = 333
+      inherited Bevel1: TBevel
+        Width = 327
+        ExplicitWidth = 327
+      end
+      inherited combo_extension: TComboBox
+        Width = 325
+        ExplicitWidth = 325
+      end
+      inherited check_zerobyte: TCheckBox
+        Visible = False
+      end
+      inherited edit_filtername: TEdit
+        Width = 325
+        ExplicitWidth = 325
+      end
+      inherited combo_connection: TComboBox
+        Width = 263
+        ExplicitWidth = 263
+      end
+    end
+  end
+  inherited content: TPanel
+    Left = 333
+    Width = 150
+    Height = 491
+    ExplicitLeft = 333
+    ExplicitWidth = 150
+    ExplicitHeight = 491
+    object group_extract: TGroupBox
+      AlignWithMargins = True
+      Left = 6
+      Top = 3
+      Width = 138
+      Height = 374
+      Margins.Left = 6
+      Margins.Right = 6
+      Align = alClient
+      Caption = '2. Select extract-method'
+      TabOrder = 0
+      DesignSize = (
+        138
+        374)
+      object label_export_sel: TLabel
+        Left = 7
+        Top = 18
+        Width = 62
+        Height = 20
+        AutoSize = False
+        Caption = 'Export ...'
+      end
+      object label_path: TLabel
+        Left = 7
+        Top = 136
+        Width = 30
+        Height = 18
+        AutoSize = False
+        Caption = 'Path:'
+      end
+      object check_dat: TCheckBox
+        Left = 7
+        Top = 75
+        Width = 121
+        Height = 18
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Export .dat-entries'
+        Checked = True
+        State = cbChecked
+        TabOrder = 0
+      end
+      object check_raw: TCheckBox
+        Left = 7
+        Top = 94
+        Width = 121
+        Height = 18
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Export .raw-entries'
+        TabOrder = 1
+      end
+      object check_convert: TCheckBox
+        Left = 7
+        Top = 112
+        Width = 121
+        Height = 18
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Convert files'
+        TabOrder = 2
+      end
+      object radio_selected: TRadioButton
+        Left = 7
+        Top = 36
+        Width = 113
+        Height = 17
+        Caption = 'selected files'
+        Checked = True
+        TabOrder = 3
+        TabStop = True
+      end
+      object radio_all: TRadioButton
+        Left = 7
+        Top = 52
+        Width = 113
+        Height = 17
+        Caption = 'all files in list'
+        TabOrder = 4
+      end
+      object edit_path: TEdit
+        Left = 36
+        Top = 133
+        Width = 28
+        Height = 21
+        Anchors = [akLeft, akTop, akRight]
+        ReadOnly = True
+        TabOrder = 5
+        Text = 'C:\'
+        OnClick = btn_pathClick
+      end
+      object btn_path: TButton
+        Left = 70
+        Top = 133
+        Width = 62
+        Height = 21
+        Anchors = [akTop, akRight]
+        Caption = 'Select...'
+        TabOrder = 6
+        OnClick = btn_pathClick
+      end
+      object btn_export: TButton
+        Left = 7
+        Top = 180
+        Width = 75
+        Height = 25
+        Caption = 'Export!'
+        TabOrder = 7
+        OnClick = btn_exportClick
+      end
+    end
+    object group_progress: TGroupBox
+      AlignWithMargins = True
+      Left = 6
+      Top = 381
+      Width = 138
+      Height = 104
+      Margins.Left = 6
+      Margins.Top = 1
+      Margins.Right = 6
+      Margins.Bottom = 6
+      Align = alBottom
+      Caption = 'Progress ...'
+      TabOrder = 1
+      Visible = False
+      DesignSize = (
+        138
+        104)
+      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 = 122
+        Height = 17
+        Anchors = [akLeft, akTop, akRight]
+        Smooth = True
+        TabOrder = 0
+      end
+      object btn_abort: TButton
+        Left = 8
+        Top = 72
+        Width = 97
+        Height = 23
+        Caption = 'Abort'
+        Enabled = False
+        TabOrder = 1
+        OnClick = btn_abortClick
+      end
+    end
+  end
+end
Index: oup/releases/0.34a/Tools/Extractor.pas
===================================================================
--- oup/releases/0.34a/Tools/Extractor.pas	(revision 200)
+++ oup/releases/0.34a/Tools/Extractor.pas	(revision 200)
@@ -0,0 +1,134 @@
+unit Extractor;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Template, StdCtrls, ExtCtrls, ComCtrls, Menus, Buttons, StrUtils;
+
+type
+  TForm_Extractor = class(TForm_ToolTemplate)
+    group_extract: TGroupBox;
+    check_dat: TCheckBox;
+    check_raw: TCheckBox;
+    check_convert: TCheckBox;
+    radio_selected: TRadioButton;
+    label_export_sel: TLabel;
+    radio_all: TRadioButton;
+    label_path: TLabel;
+    edit_path: TEdit;
+    btn_path: TButton;
+    btn_export: TButton;
+    group_progress: TGroupBox;
+    lbl_progress: TLabel;
+    lbl_estimated: TLabel;
+    progress: TProgressBar;
+    btn_abort: TButton;
+    procedure FormCreate(Sender: TObject);
+    procedure btn_abortClick(Sender: TObject);
+    procedure btn_pathClick(Sender: TObject);
+    procedure btn_exportClick(Sender: TObject);
+  private
+  public
+  end;
+
+var
+  Form_Extractor: TForm_Extractor;
+
+implementation
+{$R *.dfm}
+uses Main, Functions, Data, ConnectionManager, FolderBrowser, Exporters;
+
+
+procedure TForm_Extractor.FormCreate(Sender: TObject);
+begin
+  inherited;
+  Self.AllowMultiSelect := True;
+  edit_path.Text := AppSettings.ExtractPath;
+end;
+
+procedure TForm_Extractor.btn_abortClick(Sender: TObject);
+begin
+  ShowMessage('X');
+end;
+
+procedure TForm_Extractor.btn_pathClick(Sender: TObject);
+var
+  fb: TFolderBrowser;
+begin
+  inherited;
+
+  fb := TFolderBrowser.Create(Handle, 'Please select a folder where you want ' +
+        'the files to be stored...', edit_path.Text, False, True);
+  if fb.Execute then
+  begin
+    edit_path.Text := fb.SelectedItem;
+    AppSettings.ExtractPath := edit_path.Text;
+  end;
+  fb.Free;
+end;
+
+procedure TForm_Extractor.btn_exportClick(Sender: TObject);
+var
+  begintime: Double;
+  files:     Integer;
+  i, done:   Integer;
+  selonly:   Boolean;
+  fileid:    Integer;
+  filename:  String;
+  path:      String;
+begin
+  inherited;
+  panel_files.Enabled := False;
+  group_extract.Enabled := False;
+  group_progress.Visible := True;
+
+  path := edit_path.Text;
+  if not EndsText('\', path) then
+    path := path + '\';
+
+  begintime := Time;
+  lbl_estimated.Caption := 'Estimated finishing time: unknown';
+  progress.Position := 0;
+
+  selonly := radio_selected.Checked;
+
+  if selonly then
+    files := filelist.SelCount
+  else
+    files := filelist.Count;
+
+  lbl_progress.Caption := 'Files done: 0/' + IntToStr(files);
+  progress.Max := files;
+  done  := 0;
+
+  for i := 0 to filelist.Count - 1 do
+  begin
+    if (selonly and filelist.Selected[i]) or not selonly then
+    begin
+      fileid := ConManager.Connection[ConnectionID].ExtractFileIDOfName(filelist.Items.Strings[i]);
+      filename := GetWinFilename(filelist.Items.Strings[i]);
+      if check_dat.Checked then
+        ExportDatFile(ConnectionID, fileid, path + filename);
+      if check_raw.Checked then
+        ExportRawFiles(ConnectionID, fileid, path + filename);
+      if check_convert.Checked then
+        ExportConverted(ConnectionID, fileid, path + filename);
+      Inc(done);
+    end;
+    if ((done mod 10) = 0) and (done >= 50) then
+      lbl_estimated.Caption := 'Estimated finishing time: ' + TimeToStr(
+            (Time - begintime) / done * files + begintime);
+
+    progress.Position    := done;
+    lbl_progress.Caption := 'Files done: ' + IntToStr(done) + '/' + IntToStr(files);
+    Application.ProcessMessages;
+  end;
+
+  panel_files.Enabled := True;
+  group_extract.Enabled := True;
+  group_progress.Visible := False;
+end;
+
+
+begin
+  AddToolListEntry('extractor', 'Extractor', '');
+end.
Index: oup/releases/0.34a/Tools/Preview.dfm
===================================================================
--- oup/releases/0.34a/Tools/Preview.dfm	(revision 200)
+++ oup/releases/0.34a/Tools/Preview.dfm	(revision 200)
@@ -0,0 +1,84 @@
+inherited Form_Preview: TForm_Preview
+  Caption = 'Preview'
+  OnCreate = FormCreate
+  ExplicitWidth = 500
+  ExplicitHeight = 450
+  PixelsPerInch = 96
+  TextHeight = 13
+  inherited Splitter1: TSplitter
+    OnMoved = Splitter1Moved
+  end
+  inherited content: TPanel
+    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 img: TImage
+      Left = 0
+      Top = 20
+      Width = 283
+      Height = 403
+      Align = alClient
+      ExplicitWidth = 313
+      ExplicitHeight = 453
+    end
+    object panel_buttons: TPanel
+      Left = 0
+      Top = 0
+      Width = 283
+      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 timer: TTimer [3]
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 400
+    Top = 120
+  end
+end
Index: oup/releases/0.34a/Tools/Preview.pas
===================================================================
--- oup/releases/0.34a/Tools/Preview.pas	(revision 200)
+++ oup/releases/0.34a/Tools/Preview.pas	(revision 200)
@@ -0,0 +1,215 @@
+unit Preview;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, Template, ExtCtrls, Math, StrUtils,
+  ConnectionManager, OniImgClass, Data, TypeDefs, Menus, Buttons;
+
+type
+  TForm_Preview = class(TForm_ToolTemplate)
+    lbl_notpossible: TLabel;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    img: TImage;
+    timer: TTimer;
+    procedure FormCreate(Sender: TObject);
+    procedure NewFile(fileinfo: TFileInfo);
+
+    procedure PreviewImage;
+    procedure PreviewTXAN;
+    procedure btn_incClick(Sender: TObject);
+    procedure btn_decClick(Sender: TObject);
+    procedure btn_startstopClick(Sender: TObject);
+    procedure timerTimer(Sender: TObject);
+    procedure panel_buttonsResize(Sender: TObject);
+
+    procedure DrawImage(index: Integer);
+    procedure SetBitmapCount(Count: Integer);
+    procedure LoadImage(fileid, index: Integer);
+    procedure Splitter1Moved(Sender: TObject);
+  private
+    bitmaps:   array of TOniImage;
+    actualimg: Byte;
+    _fileid:   Integer;
+  public
+  end;
+
+var
+  Form_Preview: TForm_Preview;
+
+implementation
+{$R *.dfm}
+uses Imaging, ImagingComponents, ImagingTypes, jpeg;
+
+
+procedure TForm_Preview.FormCreate(Sender: TObject);
+begin
+  inherited;
+  Self.OnNewFileSelected := NewFile;
+  SetBitmapCount(0);
+end;
+
+
+procedure TForm_Preview.NewFile(fileinfo: TFileInfo);
+var
+  ext: String;
+begin
+  _fileid := fileinfo.ID;
+  SetBitmapCount(0);
+  if _fileid >= 0 then
+  begin
+    lbl_notpossible.Visible := False;
+    Self.img.Visible := True;
+    Self.timer.Enabled := False;
+    Self.panel_buttons.Visible := False;
+    ext     := fileinfo.Extension;
+    if (ext = 'PSpc') or (ext = 'TXMB') or (ext = 'TXMP') then
+      PreviewImage
+    else if ext = 'TXAN' then
+      PreviewTXAN
+    else
+    begin
+      Self.lbl_notpossible.Visible := True;
+      Self.img.Visible := False;
+    end;
+  end
+  else
+  begin
+    Self.img.Visible := False;
+    lbl_notpossible.Visible := False;
+    Self.timer.Enabled := False;
+    Self.panel_buttons.Visible := False;
+  end;
+end;
+
+
+procedure TForm_Preview.LoadImage(fileid, index: Integer);
+begin
+  bitmaps[index].Load(ConnectionID, fileid);
+end;
+
+
+procedure TForm_Preview.DrawImage(index: Integer);
+begin
+  bitmaps[index].DrawOnCanvas(img.Canvas, 1);
+end;
+
+
+procedure TForm_Preview.SetBitmapCount(Count: Integer);
+var
+  i: Integer;
+begin
+  if Length(bitmaps) > Count then
+  begin
+    for i := Count to High(bitmaps) do
+      bitmaps[i].Free;
+    SetLength(bitmaps, Count);
+  end;
+  if Length(bitmaps) < Count then
+  begin
+    i := Length(bitmaps);
+    SetLength(bitmaps, Count);
+    for i := i to High(bitmaps) do
+      bitmaps[i] := TOniImage.Create;
+  end;
+end;
+
+
+procedure TForm_Preview.Splitter1Moved(Sender: TObject);
+begin
+  inherited;
+  img.Picture.Assign(nil);
+  if Length(bitmaps) > 0 then
+    DrawImage(0);
+end;
+
+procedure TForm_Preview.PreviewImage;
+begin
+  SetBitmapCount(1);
+  LoadImage(_fileid, 0);
+  DrawImage(0);
+end;
+
+
+procedure TForm_Preview.PreviewTXAN;
+var
+  loop_speed: Word;
+  linkcount: Integer;
+  link: Integer;
+  i:    Byte;
+begin
+  ConManager.Connection[ConnectionID].LoadDatFilePart(_fileid, $14, SizeOf(loop_speed), @loop_speed);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(_fileid, $1C, SizeOf(linkcount), @linkcount);
+  SetBitmapCount(linkcount);
+  for i := 0 to linkcount - 1 do
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(_fileid, $20 + i * 4, SizeOf(link), @link);
+    link := link div 256;
+    if link = 0 then
+      link := _fileid - 1;
+    LoadImage(link, i);
+  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 TForm_Preview.timerTimer(Sender: TObject);
+begin
+  btn_incClick(Self);
+end;
+
+
+procedure TForm_Preview.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
+    timerTimer(Self);
+  if Self.timer.Enabled then
+    Self.btn_startstop.Caption := 'Stop automatic'
+  else
+    Self.btn_startstop.Caption := 'Start automatic';
+end;
+
+
+procedure TForm_Preview.btn_decClick(Sender: TObject);
+begin
+  if actualimg > 0 then
+    Dec(actualimg)
+  else
+    actualimg := High(bitmaps);
+  Self.Caption := 'Preview ' + ConManager.Connection[ConnectionID].GetFileInfo(_fileid).Name +
+    ' (' + IntToStr(actualimg + 1) + '/' + IntToStr(Length(bitmaps)) + ')';
+  DrawImage(actualimg);
+end;
+
+
+procedure TForm_Preview.btn_incClick(Sender: TObject);
+begin
+  if actualimg < High(bitmaps) then
+    Inc(actualimg)
+  else
+    actualimg := 0;
+  Self.Caption := 'Preview ' + ConManager.Connection[ConnectionID].GetFileInfo(_fileid).Name +
+    ' (' + IntToStr(actualimg + 1) + '/' + IntToStr(Length(bitmaps)) + ')';
+  DrawImage(actualimg);
+end;
+
+
+procedure TForm_Preview.panel_buttonsResize(Sender: TObject);
+begin
+  btn_startstop.Width := panel_buttons.Width - 45;
+  btn_inc.Left := panel_buttons.Width - 23;
+end;
+
+
+begin
+  AddToolListEntry('preview', 'Preview-Window', '');
+end.
Index: oup/releases/0.34a/Tools/RawEdit.dfm
===================================================================
--- oup/releases/0.34a/Tools/RawEdit.dfm	(revision 200)
+++ oup/releases/0.34a/Tools/RawEdit.dfm	(revision 200)
@@ -0,0 +1,200 @@
+inherited Form_RawEdit: TForm_RawEdit
+  Caption = 'RawEdit'
+  KeyPreview = True
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  ExplicitWidth = 500
+  ExplicitHeight = 450
+  PixelsPerInch = 96
+  TextHeight = 13
+  inherited panel_files: TPanel
+    object Splitter4: TSplitter [0]
+      Left = 0
+      Top = 205
+      Width = 200
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+      ExplicitLeft = 3
+      ExplicitTop = 89
+    end
+    inherited filelist: TListBox
+      Height = 52
+      ExplicitHeight = 52
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 363
+      Width = 200
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 3
+      DesignSize = (
+        200
+        60)
+      object btn_export: TButton
+        Left = 4
+        Top = 4
+        Width = 190
+        Height = 25
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Export to file...'
+        TabOrder = 0
+        OnClick = btn_exportClick
+      end
+      object btn_import: TButton
+        Left = 4
+        Top = 32
+        Width = 190
+        Height = 25
+        Anchors = [akLeft, akTop, akRight]
+        Caption = 'Import from file...'
+        TabOrder = 1
+        OnClick = btn_importClick
+      end
+    end
+    object GroupBox1: TGroupBox
+      Left = 0
+      Top = 213
+      Width = 200
+      Height = 150
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 196
+        Height = 133
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  inherited content: TPanel
+    object Splitter2: TSplitter
+      Left = 0
+      Top = 300
+      Width = 283
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 414
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 283
+      Height = 300
+      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
+    end
+    object value_viewer: TWrapGrid
+      Left = 0
+      Top = 309
+      Width = 283
+      Height = 114
+      Align = alClient
+      ColCount = 2
+      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
+      ScrollBars = ssVertical
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+  end
+  object value_viewer_context: TPopupMenu [3]
+    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 [4]
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 128
+    Top = 256
+  end
+  object saved: TSaveDialog [5]
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 128
+    Top = 280
+  end
+end
Index: oup/releases/0.34a/Tools/RawEdit.pas
===================================================================
--- oup/releases/0.34a/Tools/RawEdit.pas	(revision 200)
+++ oup/releases/0.34a/Tools/RawEdit.pas	(revision 200)
@@ -0,0 +1,814 @@
+unit RawEdit;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Template, StdCtrls, ExtCtrls, Menus, Grids, Wrapgrid,
+  MPHexEditor, Clipbrd, StrUtils, TypeDefs,
+  Data, Functions, DatStructureLoader, ConnectionManager, Buttons;
+
+type
+  TForm_RawEdit = class(TForm_ToolTemplate)
+    Splitter4: TSplitter;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    value_viewer: TWrapGrid;
+    value_viewer_context: TPopupMenu;
+    value_viewer_context_copy: TMenuItem;
+    value_viewer_context_copyasdec: TMenuItem;
+    value_viewer_context_copyasfloat: TMenuItem;
+    value_viewer_context_copyasbitset: TMenuItem;
+    value_viewer_context_copyasstring: TMenuItem;
+    value_viewer_context_copyashex: TMenuItem;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    procedure list_offsetClick(Sender: TObject);
+    procedure NewFile(fileinfo: TFileInfo);
+    procedure LoadRaw(raw_info: TRawDataInfo);
+    function Save: Boolean;
+
+    procedure btn_importClick(Sender: TObject);
+    procedure btn_exportClick(Sender: TObject);
+
+    procedure FormCreate(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+
+    function GetValue(datatype: Word; offset: Integer): String;
+    procedure ClearValues;
+    procedure WriteValues;
+    procedure SetNewValue(datatype: Word; offset: Integer; Value: String);
+
+    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 hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    procedure hexSelectionChanged(Sender: TObject);
+    procedure hexChange(Sender: TObject);
+  private
+    fileid, datoffset: Integer;
+  public
+  end;
+
+var
+  Form_RawEdit: TForm_RawEdit;
+
+implementation
+{$R *.dfm}
+uses Main, ValueEdit, RawList;
+
+procedure TForm_RawEdit.NewFile(fileinfo: TFileInfo);
+var
+  offsets: TRawDataList;
+  i: Integer;
+begin
+  if fileinfo.ID >= 0 then
+  begin
+    if hex.Modified then
+      if not Save then
+        Exit;
+    ClearValues;
+    hex.DataSize := 0;
+    fileid := fileinfo.ID;
+    list_offset.Enabled := False;
+    if fileinfo.size > 0 then
+    begin
+      offsets := ConManager.Connection[ConnectionID].GetRawList(fileid);
+      list_offset.Items.Clear;
+      if Length(offsets) > 0 then
+        for i := 0 to High(offsets) do
+          list_offset.Items.Add('0x' + IntToHex(offsets[i].SrcOffset, 8) +
+                ', ' + IntToStr(offsets[i].RawSize) + ' Bytes');
+      list_offset.Enabled := True;
+    end;
+  end
+  else
+  begin
+    ClearValues;
+    hex.DataSize := 0;
+    fileid := -1;
+    list_offset.Items.Clear;
+  end;
+end;
+
+procedure TForm_RawEdit.LoadRaw(raw_info: TRawDataInfo);
+var
+  i:    Integer;
+begin
+  if hex.Modified then
+  begin
+    if not Save then
+    begin
+      Exit;
+    end;
+  end;
+  for i := 0 to filelist.Count - 1 do
+  begin
+    if ConManager.Connection[ConnectionID].ExtractFileIDOfName(filelist.Items.Strings[i]) = Raw_Info.SrcID then
+    begin
+      filelist.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.SrcOffset, 8) then
+    begin
+      list_offset.ItemIndex := i;
+      list_offsetClick(Self);
+      Break;
+    end;
+  end;
+end;
+
+
+
+
+
+
+procedure TForm_RawEdit.list_offsetClick(Sender: TObject);
+var
+  mem: TMemoryStream;
+  rawinfo: TRawDataInfo;
+begin
+  datoffset := StrToInt('$' + MidStr(
+    list_offset.Items.Strings[list_offset.ItemIndex], 3, 8));
+
+  rawinfo := ConManager.Connection[ConnectionID].GetRawInfo(fileid, datoffset);
+
+  mem := nil;
+  ConManager.Connection[ConnectionID].LoadRawFile(rawinfo.SrcID, rawinfo.SrcOffset, TStream(mem));
+  hex.LoadFromStream(mem);
+  ClearValues;
+  hexSelectionChanged(Self);
+end;
+
+
+
+
+function TForm_RawEdit.GetValue(datatype: Word; offset: Integer): String;
+var
+  Data: TByteData;
+  i:    Word;
+  floatformat: TFormatSettings;
+begin
+  floatformat.DecimalSeparator := '.';
+  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), floatformat);
+    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 TForm_RawEdit.ClearValues;
+var
+  i: Byte;
+begin
+  for i := 1 to value_viewer.RowCount - 1 do
+    value_viewer.Cells[1, i] := '';
+end;
+
+
+
+
+procedure TForm_RawEdit.WriteValues;
+var
+  i, j:  Integer;
+  Data:  TByteData;
+  str:   String;
+  Value: Integer;
+  floatformat: TFormatSettings;
+begin
+  floatformat.DecimalSeparator := '.';
+  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), floatformat);
+      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.SelStart + j) < hex.DataSize do
+        begin
+          if hex.Data[hex.SelStart + j] = 0 then
+            Break;
+          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 TForm_RawEdit.FormCreate(Sender: TObject);
+var
+  i:     Integer;
+  exts: String;
+begin
+  inherited;
+  Self.OnNewFileSelected := Self.NewFile;
+
+  exts := '';
+  if Length(RawLists.RawListHandlers) > 0 then
+  begin
+    for i := 0 to High(RawLists.RawListHandlers) do
+      if Length(exts) > 0 then
+        exts := exts + ',' + RawLists.RawListHandlers[i].Ext
+      else
+        exts := RawLists.RawListHandlers[i].Ext;
+  end;
+  Self.AllowedExts := exts;
+
+  Self.Caption := '';
+  fileid     := -1;
+
+{
+  value_viewer.ColCount := 2;
+  value_viewer.RowCount := 8;
+}
+  value_viewer.FixedRows := 1;
+  value_viewer.FixedCols := 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] := 125;
+  value_viewer.ColWidths[1] := 1000;
+  //
+  value_viewer.Font.Charset := AppSettings.CharSet;
+  //
+end;
+
+
+
+
+function TForm_RawEdit.Save: Boolean;
+var
+  mem:  TMemoryStream;
+  i:    Integer;
+begin
+  case MessageBox(Self.Handle, PChar('Save changes to .raw-part of file ' +
+      ConManager.Connection[ConnectionID].GetFileInfo(fileid).Name + '?'), PChar('Data changed...'),
+      MB_YESNOCANCEL) of
+    idYes:
+    begin
+      mem := TMemoryStream.Create;
+      hex.SaveToStream(mem);
+      mem.Seek(0, soFromBeginning);
+      ConManager.Connection[ConnectionID].UpdateRawFile(fileid, datoffset, mem);
+      mem.Free;
+      hex.Modified := False;
+      for i := 0 to hex.Datasize - 1 do
+        hex.ByteChanged[i] := False;
+      Result := True;
+    end;
+    idNo:
+      Result := True;
+    idCancel:
+      Result := False;
+  end;
+end;
+
+
+
+
+procedure TForm_RawEdit.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+begin
+  if hex.Modified then
+    if not Save then
+      CanClose := False;
+end;
+
+
+
+
+procedure TForm_RawEdit.hexChange(Sender: TObject);
+begin
+  ClearValues;
+  if hex.DataSize > 0 then
+  begin
+{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+}    end;
+end;
+
+
+
+
+procedure TForm_RawEdit.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 TForm_RawEdit.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 TForm_RawEdit.btn_exportClick(Sender: TObject);
+var
+  fs: TFileStream;
+begin
+  saved.Filter     := 'Files of matching extension (*.' +
+    ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension + ')|*.' +
+    ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension +
+    '|All files|*.*';
+  saved.DefaultExt := ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension;
+  if saved.Execute then
+  begin
+    fs := TFileStream.Create(saved.FileName, fmCreate);
+    hex.SaveToStream(fs);
+    fs.Free;
+  end;
+end;
+
+
+
+
+procedure TForm_RawEdit.btn_importClick(Sender: TObject);
+var
+//  Data: Tdata;
+  fs:   TFileStream;
+  i: Integer;
+  rawinfo: TRawDataInfo;
+begin
+  opend.Filter := 'Files of matching extension (*.' +
+    ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension + ')|*.' +
+    ConManager.Connection[ConnectionID].GetFileInfo(fileid).Extension +
+    '|All files|*.*';
+  if opend.Execute then
+  begin
+    fs := TFileStream.Create(opend.FileName, fmOpenRead);
+    if fs.Size <> hex.DataSize then
+    begin
+      if
+        (not (CR_ResizeRaw in ConManager.Connection[ConnectionID].ChangeRights))
+        and (not (CR_AppendRaw in ConManager.Connection[ConnectionID].ChangeRights))
+        then
+      begin
+        ShowMessage('Can''t import ' + ExtractFilename(importd.FileName) +
+            ', file has to have same size as file in .raw with this backend.' + CrLf +
+            'Size of file in .raw: ' + FormatFileSize(hex.DataSize) + CrLf +
+            'Size of chosen file: ' + FormatFileSize(fs.Size));
+        Exit;
+      end else begin
+        if MessageBox(Self.Handle,
+              PChar('File has different size from the file in the .raw.' + CrLf +
+                    'Size of file in .dat: ' + FormatFileSize(hex.DataSize) + CrLf +
+                    'Size of chosen file: ' + FormatFileSize(fs.Size) + CrLf +
+                    'Replace anyway?' + CrLf +
+                    'WARNING: This only replaces the raw-data. It doesn''t' + CrLf +
+                    'do the according changes in the .dat. Oni probably' + CrLf +
+                    'won''t be able to use the data correctly!'), PChar('Different size'), MB_YESNO + MB_ICONWARNING) = ID_NO then
+        begin
+          Exit;
+        end;
+      end;
+      rawinfo := ConManager.Connection[ConnectionID].GetRawInfo(fileid, datoffset);
+      if CR_ResizeRaw in ConManager.Connection[ConnectionID].ChangeRights then
+        ConManager.Connection[ConnectionID].UpdateRawFile(fileid, datoffset, fs)
+      else if CR_AppendRaw in ConManager.Connection[ConnectionID].ChangeRights then
+        i := ConManager.Connection[ConnectionID].AppendRawFile(rawinfo.LocSep, fs);
+        ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, datoffset, 4, @i);
+    end else begin
+      ConManager.Connection[ConnectionID].UpdateRawFile(fileid, datoffset, fs);
+    end;
+    fs.Seek(0, soFromBeginning);
+    hex.LoadFromStream(fs);
+    hex.Modified := False;
+    for i := 0 to hex.Datasize - 1 do
+      hex.ByteChanged[i] := False;
+    fs.Free;
+  end;
+end;
+
+
+
+
+procedure TForm_RawEdit.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 TForm_RawEdit.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 TForm_RawEdit.value_viewer_context_copyClick(Sender: TObject);
+var
+//  i:     Byte;
+  Name:  String;
+  Value: Integer;
+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 TForm_RawEdit.SetNewValue(datatype: Word; offset: Integer; Value: String);
+var
+  Data: TByteData;
+  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 TForm_RawEdit.value_viewerDblClick(Sender: TObject);
+var
+  offset:     Integer;
+  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);
+    Form_ValueEdit.MakeVarInput(objectname, offset, datatype, Value, Self);
+  end;
+end;
+
+
+
+
+procedure TForm_RawEdit.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;
+
+begin
+  AddToolListEntry('rawedit', 'Binary .raw-Editor', '');
+end.
Index: oup/releases/0.34a/Tools/Template.dfm
===================================================================
--- oup/releases/0.34a/Tools/Template.dfm	(revision 200)
+++ oup/releases/0.34a/Tools/Template.dfm	(revision 200)
@@ -0,0 +1,339 @@
+object Form_ToolTemplate: TForm_ToolTemplate
+  Left = 0
+  Top = 0
+  Caption = 'Template'
+  ClientHeight = 423
+  ClientWidth = 492
+  Color = clBtnFace
+  Constraints.MinHeight = 450
+  Constraints.MinWidth = 500
+  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
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 200
+    Top = 0
+    Width = 9
+    Height = 423
+    AutoSnap = False
+    Beveled = True
+    MinSize = 155
+    ExplicitHeight = 473
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 200
+    Height = 423
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 0
+    object filelist: TListBox
+      Left = 0
+      Top = 153
+      Width = 200
+      Height = 270
+      Align = alClient
+      ItemHeight = 13
+      PopupMenu = filepopup
+      TabOrder = 0
+      OnClick = listClick
+      OnMouseDown = listMouseDown
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 153
+      Align = alTop
+      BevelOuter = bvNone
+      TabOrder = 1
+      DesignSize = (
+        200
+        153)
+      object Label2: TLabel
+        Left = 100
+        Top = 129
+        Width = 17
+        Height = 18
+        AutoSize = False
+        Caption = '.'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Tahoma'
+        Font.Style = [fsBold]
+        ParentFont = False
+      end
+      object Label1: TLabel
+        Left = 47
+        Top = 129
+        Width = 17
+        Height = 18
+        AutoSize = False
+        Caption = '-'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Tahoma'
+        Font.Style = [fsBold]
+        ParentFont = False
+      end
+      object label_ext: TLabel
+        Left = 2
+        Top = 86
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = 'Filter by &extension:'
+        FocusControl = combo_extension
+      end
+      object btn_sort_id_asc: TSpeedButton
+        Left = 3
+        Top = 125
+        Width = 20
+        Height = 22
+        Hint = 'Sort files by id, ascending'
+        GroupIndex = 1
+        Down = True
+        Glyph.Data = {
+          F6000000424DF600000000000000760000002800000010000000100000000100
+          0400000000008000000000000000000000001000000000000000C0C0C0000000
+          9900990000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000001100000300000001001000030000000000100033300000001110003
+          3300000010010033333000001001000030000000011000003000000000000000
+          3000000002200000300000002002000030000000200200003000000020020000
+          3000000020020000300000002002000030000000022000003000}
+        ParentShowHint = False
+        ShowHint = True
+        OnClick = btn_sortClick
+      end
+      object btn_sort_id_desc: TSpeedButton
+        Left = 23
+        Top = 125
+        Width = 20
+        Height = 22
+        Hint = 'Sort files by id, descending'
+        GroupIndex = 1
+        Glyph.Data = {
+          F6000000424DF600000000000000760000002800000010000000100000000100
+          0400000000008000000000000000000000001000000000000000C0C0C0000000
+          9900990000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000000002200000300000002002000030000000200200033300000020020003
+          3300000020020033333000002002000030000000022000003000000000000000
+          3000000001100000300000001001000030000000000100003000000001110000
+          3000000010010000300000001001000030000000011000003000}
+        ParentShowHint = False
+        ShowHint = True
+        OnClick = btn_sortClick
+      end
+      object btn_sort_name_asc: TSpeedButton
+        Left = 58
+        Top = 125
+        Width = 20
+        Height = 22
+        Hint = 'Sort files by name, ascending'
+        GroupIndex = 1
+        Glyph.Data = {
+          F6000000424DF600000000000000760000002800000010000000100000000100
+          0400000000008000000000000000000000001000000000000000C0C0C0000000
+          9900990000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000011111100000300001100010000030000011000000033300000110000003
+          3300000011000033333001000110000030000111111000003000000000000000
+          3000022202220000300000200020000030000022222000003000000202000000
+          3000000222000000300000002000000030000000200000003000}
+        ParentShowHint = False
+        ShowHint = True
+        OnClick = btn_sortClick
+      end
+      object btn_sort_name_desc: TSpeedButton
+        Left = 78
+        Top = 125
+        Width = 20
+        Height = 22
+        Hint = 'Sort files by name, descending'
+        GroupIndex = 1
+        Glyph.Data = {
+          F6000000424DF600000000000000760000002800000010000000100000000100
+          0400000000008000000000000000000000001000000000000000C0C0C0000000
+          9900990000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000022202220000300000200020000030000022222000033300000202000003
+          3300000222000033333000002000000030000000200000003000000000000000
+          3000011111100000300001100010000030000011000000003000000110000000
+          3000000011000000300001000110000030000111111000003000}
+        ParentShowHint = False
+        ShowHint = True
+        OnClick = btn_sortClick
+      end
+      object btn_sort_ext_asc: TSpeedButton
+        Left = 108
+        Top = 125
+        Width = 20
+        Height = 22
+        Hint = 'Sort files by extension, ascending'
+        GroupIndex = 1
+        Glyph.Data = {
+          F6000000424DF600000000000000760000002800000010000000100000000100
+          0400000000008000000000000000000000001000000000000000C0C0C0000000
+          9900990000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000011111100000300001100010000030000011000000033300000110000003
+          3300000011000033333001000110000030000111111000003000000000000000
+          3000022202220000300000200020000030000022222000003000000202000000
+          3000000222000000300000002000000030000000200000003000}
+        ParentShowHint = False
+        ShowHint = True
+        OnClick = btn_sortClick
+      end
+      object btn_sort_ext_desc: TSpeedButton
+        Left = 128
+        Top = 125
+        Width = 20
+        Height = 22
+        Hint = 'Sort files by extension, descending'
+        GroupIndex = 1
+        Glyph.Data = {
+          F6000000424DF600000000000000760000002800000010000000100000000100
+          0400000000008000000000000000000000001000000000000000C0C0C0000000
+          9900990000000000000000000000000000000000000000000000000000000000
+          0000000000000000000000000000000000000000000000000000000000000000
+          0000022202220000300000200020000030000022222000033300000202000003
+          3300000222000033333000002000000030000000200000003000000000000000
+          3000011111100000300001100010000030000011000000003000000110000000
+          3000000011000000300001000110000030000111111000003000}
+        ParentShowHint = False
+        ShowHint = True
+        OnClick = btn_sortClick
+      end
+      object Label3: TLabel
+        Left = 3
+        Top = 6
+        Width = 61
+        Height = 13
+        Caption = 'Connection: '
+      end
+      object Bevel1: TBevel
+        Left = 0
+        Top = 25
+        Width = 199
+        Height = 3
+        Anchors = [akLeft, akTop, akRight]
+        Style = bsRaised
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 100
+        Width = 196
+        Height = 21
+        Style = csDropDownList
+        Anchors = [akLeft, akTop, akRight]
+        DropDownCount = 20
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Courier'
+        Font.Style = []
+        ItemHeight = 13
+        ParentFont = False
+        Sorted = True
+        TabOrder = 3
+        OnClick = combo_extensionClick
+      end
+      object check_zerobyte: TCheckBox
+        Left = 2
+        Top = 68
+        Width = 130
+        Height = 13
+        Caption = 'Show &zero-byte files'
+        TabOrder = 2
+        OnClick = check_zerobyteClick
+      end
+      object edit_filtername: TEdit
+        Left = 2
+        Top = 44
+        Width = 196
+        Height = 18
+        Anchors = [akLeft, akTop, akRight]
+        AutoSize = False
+        TabOrder = 1
+      end
+      object check_filtername: TCheckBox
+        Left = 2
+        Top = 29
+        Width = 130
+        Height = 15
+        Caption = 'Filter by file&name:'
+        TabOrder = 0
+        OnClick = check_filternameClick
+      end
+      object combo_connection: TComboBox
+        Left = 64
+        Top = 3
+        Width = 134
+        Height = 21
+        Style = csDropDownList
+        Anchors = [akLeft, akTop, akRight]
+        DropDownCount = 12
+        ItemHeight = 13
+        TabOrder = 4
+        OnChange = combo_connectionChange
+      end
+    end
+  end
+  object content: TPanel
+    Left = 209
+    Top = 0
+    Width = 283
+    Height = 423
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 1
+  end
+  object filepopup: TPopupMenu
+    OnPopup = filepopupPopup
+    Left = 72
+    Top = 216
+    object popup_separator2: TMenuItem
+      Caption = '-'
+    end
+    object popup_linkshere: TMenuItem
+      Caption = 'What links here? Where does this file link to?'
+      OnClick = popup_linkshereClick
+    end
+    object popup_separator: TMenuItem
+      Caption = '-'
+    end
+    object popup_import: TMenuItem
+      Caption = 'Import binary .dat-file'
+      OnClick = popup_importClick
+    end
+    object popup_export: TMenuItem
+      Caption = 'Export binary .dat-file'
+      OnClick = popup_exportClick
+    end
+  end
+  object importd: TOpenDialog
+    Options = [ofExtensionDifferent, ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 136
+    Top = 232
+  end
+  object exportd: TSaveDialog
+    Options = [ofHideReadOnly, ofExtensionDifferent, ofPathMustExist, ofEnableSizing]
+    Left = 144
+    Top = 256
+  end
+end
Index: oup/releases/0.34a/Tools/Template.pas
===================================================================
--- oup/releases/0.34a/Tools/Template.pas	(revision 200)
+++ oup/releases/0.34a/Tools/Template.pas	(revision 200)
@@ -0,0 +1,552 @@
+unit Template;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ExtCtrls, StdCtrls, StrUtils,
+  Data, TypeDefs, Menus, Buttons;
+
+type
+  TNewFileSelectedEvent = procedure(FileInfo: TFileInfo) of object;
+  TNewConnectionEvent = procedure(Connection: Integer) of object;
+  TCheckCloseableEvent = function: Boolean of object;
+
+  TForm_ToolTemplate = class(TForm)
+    panel_files: TPanel;
+    filelist: TListBox;
+    panel_extension: TPanel;
+    label_ext: TLabel;
+    combo_extension: TComboBox;
+    check_zerobyte: TCheckBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    Splitter1: TSplitter;
+    content: TPanel;
+    filepopup: TPopupMenu;
+    popup_import: TMenuItem;
+    popup_export: TMenuItem;
+    popup_separator: TMenuItem;
+    importd: TOpenDialog;
+    exportd: TSaveDialog;
+    btn_sort_id_asc: TSpeedButton;
+    btn_sort_id_desc: TSpeedButton;
+    btn_sort_name_asc: TSpeedButton;
+    btn_sort_name_desc: TSpeedButton;
+    btn_sort_ext_asc: TSpeedButton;
+    btn_sort_ext_desc: TSpeedButton;
+    Label1: TLabel;
+    Label2: TLabel;
+    Label3: TLabel;
+    combo_connection: TComboBox;
+    Bevel1: TBevel;
+    popup_linkshere: TMenuItem;
+    popup_separator2: TMenuItem;
+    procedure RecreateExtList;
+    procedure UpdateConList;
+    procedure LoadFileNames;
+    procedure SelectFileName(ConnectionID: Integer; FileName: String);
+    procedure SelectFileID(ConnectionID, FileID: Integer);
+    procedure SelectConnection(ConnectionID: Integer);
+    procedure check_filternameClick(Sender: TObject);
+    procedure check_zerobyteClick(Sender: TObject);
+    procedure combo_extensionClick(Sender: TObject);
+    procedure listClick(Sender: TObject);
+    procedure listMouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure popup_importClick(Sender: TObject);
+    procedure popup_exportClick(Sender: TObject);
+    procedure popup_opentool(Sender: TObject);
+    procedure filepopupPopup(Sender: TObject);
+    procedure btn_sortClick(Sender: TObject);
+    procedure FormActivate(Sender: TObject);
+    procedure combo_connectionChange(Sender: TObject);
+    procedure popup_linkshereClick(Sender: TObject);
+  private
+    FSortBy: TSortType;
+    FOnNewFileSelected: TNewFileSelectedEvent;
+    FOnNewConnection: TNewConnectionEvent;
+    FOnCheckCloseable: TCheckCloseableEvent;
+    FAllowedExts: String;
+    FAllowMultiSelect: Boolean;
+    FSelectedFile: TFileInfo;
+    FConnectionID: Integer;
+    procedure SetAllowedExts(exts: String);
+    procedure SetMultiSelect(allow: Boolean);
+    function GetToolCloseable: Boolean;
+  public
+    constructor Create(AOwner: TComponent); override;
+    procedure SetFileFilters(pattern, extension: String; zerobytes: Boolean);
+  published
+    property OnNewFileSelected: TNewFileSelectedEvent read FOnNewFileSelected write FOnNewFileSelected;
+    property OnNewConnection: TNewConnectionEvent read FOnNewConnection write FOnNewConnection;
+    property OnCheckCloseable: TCheckCloseableEvent read FOnCheckCloseable write FOnCheckCloseable;
+    property AllowedExts: String read FAllowedExts write SetAllowedExts;
+    property AllowMultiSelect: Boolean read FAllowMultiSelect write SetMultiSelect;
+    property SelectedFile: TFileInfo read FSelectedFile;
+    property ConnectionID: Integer read FConnectionID;
+    property Closeable: Boolean read GetToolCloseable;
+  end;
+
+var
+  ToolList: TToolList;
+procedure AddToolListEntry(context, name, exts: String);
+
+implementation
+{$R *.dfm}
+uses Main, ConnectionManager, Exporters, Functions, WhatLinksHere;
+
+
+procedure TForm_ToolTemplate.UpdateConList;
+var
+  i: Integer;
+  fn, datatype, boxstring: String;
+  level: Integer;
+begin
+  combo_connection.ItemIndex := -1;
+  combo_connection.Items.Clear;
+  if ConManager.Count > 0 then
+  begin
+    for i := 0 to ConManager.Count - 1 do
+    begin
+      level := ConManager.ConnectionByIndex[i].LevelNumber;
+      fn := ExtractFileName(ConManager.ConnectionByIndex[i].FileName);
+      if ConManager.ConnectionByIndex[i].Backend = DB_ONI then
+        datatype := 'ONI-.dat: '
+      else if ConManager.ConnectionByIndex[i].Backend = DB_ADB then
+        datatype := 'OUP-DB: '
+      else
+        datatype := 'Unknown: ';
+      boxstring := datatype + fn + ' (Level: ' + IntToStr(level) + ') [' + IntToStr(ConManager.ConnectionByIndex[i].ConnectionID) + ']';
+      combo_connection.Items.Add(boxstring);
+      if ConManager.ConnectionByIndex[i].ConnectionID = FConnectionID then
+        combo_connection.ItemIndex := combo_connection.Items.Count - 1;
+    end;
+    if combo_connection.ItemIndex = -1 then
+    begin
+      combo_connection.ItemIndex := 0;
+      combo_connectionChange(Self);
+    end;
+  end
+  else
+  begin
+    FConnectionID := 0;
+    filelist.Items.Clear;
+    combo_extension.Items.Clear;
+    combo_connectionChange(Self);
+    FSelectedFile.ID := -1;
+    if Assigned(FOnNewFileSelected) then
+      FOnNewFileSelected(FSelectedFile);
+  end;
+end;
+
+procedure TForm_ToolTemplate.RecreateExtList;
+var
+  i:    Integer;
+  exts: TStrings;
+begin
+  combo_extension.Items.Clear;
+  if FConnectionID > -1 then
+  begin
+    combo_extension.Items.Add('_All files_ (' +
+      IntToStr(ConManager.Connection[FConnectionID].GetFileCount) + ')');
+    exts := nil;
+    exts := ConManager.Connection[FConnectionID].GetExtensionsList(EF_ExtCount);
+    for i := 0 to exts.Count - 1 do
+      if Length(FAllowedExts) > 0 then
+      begin
+        if Pos(MidStr(exts.Strings[i],1,4), FAllowedExts) > 0 then
+          combo_extension.Items.Add(exts.Strings[i]);
+      end
+      else
+        combo_extension.Items.Add(exts.Strings[i]);
+    combo_extension.ItemIndex := 0;
+    combo_extensionClick(Self);
+    exts.Free;
+  end;
+end;
+
+
+
+
+procedure TForm_ToolTemplate.LoadFileNames;
+var
+  Extension: String;
+  no_zero_bytes: Boolean;
+  pattern: String;
+  files: TStrings;
+begin
+  if FConnectionID > -1 then
+  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
+      if Length(FAllowedExts) > 0 then
+        Extension := FAllowedExts
+      else
+        Extension := '';
+
+    files := nil;
+    files := ConManager.Connection[FConnectionID].GetFilesList(extension, pattern, no_zero_bytes, FSortBy);
+
+    filelist.Visible := False;
+    filelist.Items.Clear;
+    if files.Count > 0 then
+      filelist.Items.AddStrings(files);
+    filelist.Visible := True;
+  end;
+end;
+
+
+procedure TForm_ToolTemplate.popup_exportClick(Sender: TObject);
+var
+  id: Integer;
+  ext: String;
+begin
+  id := ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]);
+  ext := RightStr(filelist.Items.Strings[filelist.ItemIndex], 4);
+  exportd.Filter := 'Files of matching extension (*.' + ext + ')|*.' + ext + '|All files|*.*';
+  exportd.DefaultExt := ext;
+  if exportd.Execute then
+    ExportDatFile(FConnectionID, id, exportd.FileName);
+end;
+
+procedure TForm_ToolTemplate.popup_importClick(Sender: TObject);
+var
+  id: Integer;
+  finfo: TFileInfo;
+  fs: TFileStream;
+begin
+  if CR_EditDat in ConManager.Connection[FConnectionID].ChangeRights then
+  begin
+    id := ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]);
+    finfo := ConManager.Connection[FConnectionID].GetFileInfo(id);
+
+    importd.Filter := 'Files of matching extension (*.' + finfo.Extension + ')|*.' +
+          finfo.Extension + '|All files|*.*';
+    if importd.Execute then
+    begin
+      fs := TFileStream.Create(importd.FileName, fmOpenRead);
+      if fs.Size <> finfo.Size then
+      begin
+        if not (CR_ResizeDat in ConManager.Connection[FConnectionID].ChangeRights) then
+        begin
+          ShowMessage('Can''t import ' + ExtractFilename(importd.FileName) +
+            ', file has to have same size as file in .dat with this backend.' + CrLf +
+            'Size of file in .dat: ' + FormatFileSize(finfo.Size) + CrLf +
+            'Size of chosen file: ' + FormatFileSize(fs.Size));
+          Exit;
+        end else begin
+          if MessageBox(Self.Handle,
+              PChar('File has different size from the file in the .dat.' + CrLf +
+                    'Size of file in .dat: ' + FormatFileSize(finfo.Size) + CrLf +
+                    'Size of chosen file: ' + FormatFileSize(fs.Size) + CrLf +
+                    'Replace anyway?'), PChar('Different size'), MB_YESNO + MB_ICONWARNING) = ID_NO then
+          begin
+            Exit;
+          end;
+        end;
+      end;
+      ConManager.Connection[FConnectionID].UpdateDatFile(id, fs);
+      Self.listClick(Self);
+      fs.Free;
+    end;
+  end else begin
+    ShowMessage('Editing .dat-contents not allowed with this backend.');
+  end;
+end;
+
+procedure TForm_ToolTemplate.popup_linkshereClick(Sender: TObject);
+begin
+  Form_WhatLinksHere.ConID := FConnectionID;
+  Form_WhatLinksHere.FileID := FSelectedFile.ID;
+  Form_WhatLinksHere.SenderForm := Self;
+  Form_WhatLinksHere.Show;
+end;
+
+procedure TForm_ToolTemplate.popup_opentool(Sender: TObject);
+var
+  sender_name, context: String;
+  id: Integer;
+begin
+  sender_name := TComponent(Sender).Name;
+  id := ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[filelist.ItemIndex]);
+  context := MidStr(sender_name, Pos('_', sender_name) + 1, Length(sender_name) - Pos('_', sender_name));
+  Form_Main.open_child(context, FConnectionID, id);
+end;
+
+procedure TForm_ToolTemplate.combo_connectionChange(Sender: TObject);
+var
+  name: String;
+begin
+  if combo_connection.ItemIndex >= 0 then
+  begin
+    name := combo_connection.Items.Strings[combo_connection.ItemIndex];
+    FConnectionID := StrToInt(MidStr(name, Pos('[', name) + 1, Pos(']', name) - Pos('[', name)  - 1));
+  end
+  else
+    FConnectionID := -1;
+  RecreateExtList;
+  if Assigned(FOnNewConnection) then
+    FOnNewConnection(FConnectionID);
+end;
+
+procedure TForm_ToolTemplate.combo_extensionClick(Sender: TObject);
+begin
+  LoadFileNames;
+end;
+
+
+constructor TForm_ToolTemplate.Create(AOwner: TComponent);
+var
+  i: Integer;
+  item: TMenuItem;
+begin
+  inherited;
+  Self.Width  := 260;
+  Self.Height := 300;
+  FAllowedExts := '';
+  FAllowMultiSelect := False;
+  FOnNewFileSelected := nil;
+  FOnNewConnection := nil;
+  FOnCheckCloseable := nil;
+  FConnectionID := -1;
+  FSelectedFile.ID := -1;
+  UpdateConList;
+  if Length(ToolList) > 0 then
+  begin
+    for i := 0 to High(ToolList) do
+    begin
+      item := TMenuItem.Create(filepopup);
+      item.Name := 'popup_' + ToolList[i].context;
+      item.Caption := 'Open with ' + ToolList[i].name;
+      item.OnClick := Self.popup_opentool;
+      filepopup.Items.Insert(i, item);
+    end;
+  end;
+end;
+
+procedure TForm_ToolTemplate.filepopupPopup(Sender: TObject);
+var
+  ext: String;
+  i: Integer;
+begin
+  ext := RightStr(filelist.Items.Strings[filelist.ItemIndex], 4);
+  for i := 0 to High(ToolList) do
+  begin
+    filepopup.Items.Items[i].Enabled := True;
+    if Length(ToolList[i].exts) > 0 then
+      if Pos(ext, ToolList[i].exts) = 0 then
+        filepopup.Items.Items[i].Enabled := False;
+  end;
+end;
+
+procedure TForm_ToolTemplate.check_zerobyteClick(Sender: TObject);
+begin
+  LoadFileNames;
+end;
+
+procedure TForm_ToolTemplate.btn_sortClick(Sender: TObject);
+begin
+  if btn_sort_id_asc.Down then
+    FSortBy := ST_IDAsc
+  else if btn_sort_id_desc.Down then
+    FSortBy := ST_IDDesc
+  else if btn_sort_name_asc.Down then
+    FSortBy := ST_NameAsc
+  else if btn_sort_name_desc.Down then
+    FSortBy := ST_NameDesc
+  else if btn_sort_ext_asc.Down then
+    FSortBy := ST_ExtAsc
+  else if btn_sort_ext_desc.Down then
+    FSortBy := ST_ExtDesc;
+  LoadFileNames;
+end;
+
+procedure TForm_ToolTemplate.check_filternameClick(Sender: TObject);
+begin
+  edit_filtername.Enabled := not check_filtername.Checked;
+  LoadFileNames;
+end;
+
+procedure TForm_ToolTemplate.listClick(Sender: TObject);
+var
+  fileid: Integer;
+begin
+  if filelist.ItemIndex > -1 then
+  begin
+    fileid := ConManager.Connection[FConnectionID].ExtractFileIDOfName(
+          filelist.Items.Strings[filelist.ItemIndex]);
+    FSelectedFile := ConManager.Connection[FConnectionID].GetFileInfo(fileid);
+    if Assigned(FOnNewFileSelected) then
+      FOnNewFileSelected(FSelectedFile);
+  end;
+end;
+
+procedure TForm_ToolTemplate.listMouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+var
+  pt: TPoint;
+begin
+  pt.X := x;
+  pt.Y := y;
+  if Shift = [ssRight] then
+  begin
+    filelist.ItemIndex := filelist.ItemAtPos(pt, true);
+    Self.listClick(Self);
+  end;
+end;
+
+
+
+procedure TForm_ToolTemplate.SelectConnection(ConnectionID: Integer);
+begin
+  if FConnectionID <> ConnectionID then
+  begin
+    combo_connection.ItemIndex := ConManager.ConnectionIndexByID[ConnectionID];
+    combo_connectionChange(Self);
+  end;
+end;
+
+procedure TForm_ToolTemplate.SelectFileID(ConnectionID, FileID: Integer);
+var
+  i: Integer;
+begin
+  if FConnectionID <> ConnectionID then
+    SelectConnection(ConnectionID);
+
+  filelist.ItemIndex := -1;
+  if filelist.Items.Count > 0 then
+    for i := 0 to filelist.Items.Count - 1 do
+      if ConManager.Connection[FConnectionID].ExtractFileIDOfName(filelist.Items.Strings[i]) = FileID then
+      begin
+        filelist.ItemIndex := i;
+        Break;
+      end;
+  Self.listClick(Self);
+end;
+
+procedure TForm_ToolTemplate.SelectFileName(ConnectionID: Integer; filename: String);
+var
+  i: Integer;
+begin
+  if FConnectionID <> ConnectionID then
+    SelectConnection(ConnectionID);
+
+  filelist.ItemIndex := -1;
+  if filelist.Items.Count > 0 then
+    for i := 0 to filelist.Items.Count - 1 do
+      if filelist.Items.Strings[i] = filename then
+        filelist.ItemIndex := i;
+  Self.listClick(Self);
+end;
+
+procedure TForm_ToolTemplate.SetAllowedExts(exts: String);
+begin
+  FAllowedExts := exts;
+  RecreateExtList;
+end;
+
+procedure TForm_ToolTemplate.SetFileFilters(pattern, extension: String;
+  zerobytes: Boolean);
+var
+  i: Integer;
+begin
+  if Length(pattern) > 0 then
+    Self.edit_filtername.Text := pattern;
+  Self.check_filtername.Checked := Length(pattern) > 0;
+  if Length(extension) > 0 then
+  begin
+    for i := 0 to Self.combo_extension.Items.Count - 1 do
+      if Pos(extension, Self.combo_extension.Items.Strings[i]) > 0 then
+        Break;
+    if i < Self.combo_extension.Items.Count then
+      Self.combo_extension.ItemIndex := i
+    else
+      Self.combo_extension.ItemIndex := -1;
+  end;
+  Self.check_zerobyte.Checked := zerobytes;
+  Self.LoadFileNames;
+end;
+
+procedure TForm_ToolTemplate.SetMultiSelect(allow: Boolean);
+begin
+  FAllowMultiSelect := allow;
+  filelist.MultiSelect := allow;
+end;
+
+
+function TForm_ToolTemplate.GetToolCloseable: Boolean;
+begin
+  if Assigned(FOnCheckCloseable) then
+    Result := FOnCheckCloseable
+  else
+    Result := True;
+end;
+
+procedure TForm_ToolTemplate.FormActivate(Sender: TObject);
+begin
+  if edit_filtername.CanFocus then
+    edit_filtername.SetFocus
+  else
+    if content.CanFocus then
+      content.SetFocus;
+end;
+
+procedure TForm_ToolTemplate.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+  Action := caFree;
+end;
+
+
+procedure AddToolListEntryExt(context, ext: String);
+var
+  i: Integer;
+begin
+  for i := 0 to High(ToolList) do
+    if ToolList[i].context = context then
+    begin
+      if Pos(ext, ToolList[i].exts) = 0 then
+      begin
+        if Length(ToolList[i].exts) = 0 then
+          ToolList[i].exts := ext
+        else
+          ToolList[i].exts := ToolList[i].exts + ',' + ext;
+      end;
+      Exit;
+    end;
+end;
+
+procedure AddToolListEntry(context, name, exts: String);
+var
+  i: Integer;
+begin
+  if Length(ToolList) > 0 then
+  begin
+    for i := 0 to High(ToolList) do
+      if ToolList[i].context = context then
+      begin
+        if (Length(ToolList[i].name) = 0) and (Length(name) > 0) then
+          ToolList[i].name := name;
+        if Length(exts) > 0 then
+          AddToolListEntryExt(context, exts);
+        Exit;
+      end;
+  end;
+  SetLength(ToolList, Length(ToolList) + 1);
+  for i := High(ToolList) downto 1 do
+    if ToolList[i - 1].name > name then
+      ToolList[i] := ToolList[i - 1]
+    else
+      Break;
+  ToolList[i].context := context;
+  ToolList[i].name := name;
+  ToolList[i].exts := exts;
+end;
+
+end.
Index: oup/releases/0.34a/Tools/TxmpReplace.dfm
===================================================================
--- oup/releases/0.34a/Tools/TxmpReplace.dfm	(revision 200)
+++ oup/releases/0.34a/Tools/TxmpReplace.dfm	(revision 200)
@@ -0,0 +1,166 @@
+inherited Form_TxmpReplace: TForm_TxmpReplace
+  Caption = 'TxmpReplace'
+  OnCreate = FormCreate
+  ExplicitWidth = 500
+  ExplicitHeight = 450
+  PixelsPerInch = 96
+  TextHeight = 13
+  inherited Splitter1: TSplitter
+    Height = 344
+    OnMoved = Splitter1Moved
+    ExplicitHeight = 344
+  end
+  inherited panel_files: TPanel
+    Height = 344
+    ExplicitHeight = 344
+    object image_txmppreview: TImage [0]
+      Left = 0
+      Top = 307
+      Width = 200
+      Height = 7
+      Align = alClient
+      ExplicitTop = 111
+      ExplicitHeight = 211
+    end
+    object splitter_txmp: TSplitter [1]
+      Left = 0
+      Top = 299
+      Width = 200
+      Height = 8
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 60
+      ExplicitLeft = -6
+      ExplicitTop = 314
+    end
+    inherited filelist: TListBox
+      Height = 146
+      Align = alTop
+      ExplicitHeight = 146
+    end
+    inherited panel_extension: TPanel
+      inherited label_ext: TLabel
+        Visible = False
+      end
+      inherited combo_extension: TComboBox
+        Visible = False
+      end
+      inherited check_zerobyte: TCheckBox
+        Visible = False
+      end
+    end
+    object panel_txmppreview: TPanel
+      Left = 0
+      Top = 314
+      Width = 200
+      Height = 30
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 2
+      object btn_save: TButton
+        Left = 2
+        Top = 2
+        Width = 111
+        Height = 25
+        Caption = 'Save TXMP-Picture'
+        TabOrder = 0
+        OnClick = btn_saveClick
+      end
+    end
+  end
+  inherited content: TPanel
+    Height = 344
+    ExplicitHeight = 344
+    object group_bmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 283
+      Height = 344
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 0
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 279
+        Height = 297
+        Align = alClient
+        ExplicitWidth = 182
+        ExplicitHeight = 302
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 279
+        Height = 30
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_load: TButton
+          Left = 2
+          Top = 2
+          Width = 121
+          Height = 25
+          Caption = 'Load image...'
+          TabOrder = 0
+          OnClick = btn_loadClick
+        end
+      end
+    end
+  end
+  object group_options: TGroupBox [3]
+    Left = 0
+    Top = 344
+    Width = 492
+    Height = 79
+    Align = alBottom
+    Caption = '3. Options && Replace'
+    Enabled = False
+    TabOrder = 2
+    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'
+      Enabled = False
+      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 [4]
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 352
+    Top = 16
+  end
+  object saved: TSaveDialog [5]
+    DefaultExt = 'bmp'
+    Filter = 
+      'All supported files (*.bmp, *.dds, *.tga, *.jpg, *.jpeg, *.png)|' +
+      '*.bmp;*.dds;*.tga;*.jpg;*.jpeg;*.png|Windows Bitmap (*.bmp)|*.bm' +
+      'p|DirectDraw Surface (*.dds)|*.dds|Targa (*.tga)|*.tga|JPEG (*.j' +
+      'pg, *.jpeg)|*.jpg;*.jpeg|PNG (*.png)|*.png|All files (*.*)|*'
+    Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofEnableSizing]
+    Left = 104
+    Top = 320
+  end
+end
Index: oup/releases/0.34a/Tools/TxmpReplace.pas
===================================================================
--- oup/releases/0.34a/Tools/TxmpReplace.pas	(revision 200)
+++ oup/releases/0.34a/Tools/TxmpReplace.pas	(revision 200)
@@ -0,0 +1,226 @@
+unit TxmpReplace;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Template, StdCtrls, ExtCtrls,
+  Functions, Data, OniImgClass, Menus, Buttons, TypeDefs;
+
+type
+  TForm_TxmpReplace = class(TForm_ToolTemplate)
+    group_options: TGroupBox;
+    btn_replace: TButton;
+    check_transparency: TCheckBox;
+    check_fading: TCheckBox;
+    panel_txmppreview: TPanel;
+    btn_save: TButton;
+    image_txmppreview: TImage;
+    splitter_txmp: TSplitter;
+    group_bmpselect: TGroupBox;
+    image_bmppreview: TImage;
+    panel_load: TPanel;
+    btn_load: TButton;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    procedure SelectFile(fileinfo: TFileInfo);
+    procedure FormCreate(Sender: TObject);
+    procedure FormClose(Sender: TObject; var Action: TCloseAction);
+    procedure btn_saveClick(Sender: TObject);
+    procedure btn_loadClick(Sender: TObject);
+    procedure btn_replaceClick(Sender: TObject);
+    procedure Splitter1Moved(Sender: TObject);
+  private
+    OniImage_Old: TOniImage;
+    OniImage_New: TOniImage;
+    old_size: Integer;
+    fileid: Integer;
+  public
+  end;
+
+var
+  Form_TxmpReplace: TForm_TxmpReplace;
+
+implementation
+{$R *.dfm}
+uses Main, ConnectionManager, ImagingTypes;
+
+
+
+procedure TForm_TxmpReplace.SelectFile(fileinfo: TFileInfo);
+var
+  mem:  TMemoryStream;
+  fadingbyte, depthbyte, storebyte: Byte;
+begin
+  fileid := fileinfo.ID;
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, SizeOf(fadingbyte), @fadingbyte);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $89, SizeOf(depthbyte), @depthbyte);
+  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(storebyte), @storebyte);
+
+  OniImage_Old.LoadFromTXMP(ConnectionID, fileid);
+  old_size := OniImage_Old.GetImageSize(True);
+  OniImage_Old.DrawOnCanvas(image_txmppreview.Canvas, 1);
+
+  check_fading.Checked := OniImage_Old.HasMipMaps;
+//  check_transparency.Checked := (depthbyte and $04) > 0;
+  check_transparency.Checked := storebyte in [0, 2, 7];
+
+  group_bmpselect.Enabled := True;
+end;
+
+
+procedure TForm_TxmpReplace.Splitter1Moved(Sender: TObject);
+begin
+  inherited;
+  image_txmppreview.Picture.Assign(nil);
+  image_bmppreview.Picture.Assign(nil);
+  if Length(OniImage_Old.Images) > 0 then
+    OniImage_Old.DrawOnCanvas(image_txmppreview.Canvas, 1);
+  if Length(OniImage_New.Images) > 0 then
+    OniImage_New.DrawOnCanvas(image_bmppreview.Canvas, 1);
+end;
+
+procedure TForm_TxmpReplace.btn_loadClick(Sender: TObject);
+var
+  mem:   TMemoryStream;
+begin
+  if opend.Execute then
+  begin
+    OniImage_New.LoadFromFile(opend.FileName);
+    OniImage_New.DrawOnCanvas(image_bmppreview.Canvas, 1);
+    group_options.Enabled := True;
+  end;
+end;
+
+
+
+
+procedure TForm_TxmpReplace.btn_replaceClick(Sender: TObject);
+var
+  newsize: Integer;
+  old_rawaddr, new_rawaddr: Integer;
+  oldfading: Byte;
+  datbyte: Word;
+  mem: TMemoryStream;
+  new_storetype: Byte;
+  formatinfo: TImageFormatInfo;
+begin
+  if filelist.ItemIndex >= 0 then
+  begin
+    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, 1, @oldfading);
+    if not (ConManager.Connection[ConnectionID].DataOS = DOS_WIN) then
+      ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, 4, @old_rawaddr)
+    else
+      ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, 4, @old_rawaddr);
+
+    if (OniImage_Old.Width[1] <> OniImage_New.Width[1]) or
+      (OniImage_Old.Height[1] <> OniImage_New.Height[1]) then
+    begin
+      if MessageBox(Self.Handle,
+            PChar(
+              'Current image and new image have different size' + CrLf +
+              '(Current: ' + IntToStr(OniImage_Old.Width[1]) + 'x' +
+              IntToStr(OniImage_Old.Height[1]) + ' - New: ' +
+              IntToStr(OniImage_New.Width[1]) + 'x' +
+              IntToStr(OniImage_New.Height[1]) +
+              ')' + CrLf + 'Replace anyway?'),
+            PChar(filelist.Items.Strings[filelist.ItemIndex]), MB_YESNO) = idNo then
+        Exit;
+    end;
+
+    mem := TMemoryStream.Create;
+
+    case OniImage_New.Format of
+      ifX1R5G5B5: new_storetype := 1;
+      ifA1R5G5B5: new_storetype := 2;
+      ifA4R4G4B4: new_storetype := 0;
+      ifA8R8G8B8:
+        begin
+          new_storetype := 8;
+          OniImage_New.Format := ifX8R8G8B8;
+        end;
+      ifX8R8G8B8: new_storetype := 8;
+      ifDXT1: new_storetype := 9;
+    else
+      if OniImage_New.FormatInfo.HasAlphaChannel then
+        ShowMessage('Loaded image has an alpha-channel.' + #13#10 +
+                    'Because the format is neither ARGB1555' +#13#10 +
+                    'nor ARGB4444 it can not be imported without conversion.' + #13#10 +
+                    'It is converted to RGB888, so alpha gets dropped.' + #13#10 +
+                    'If you need alpha you have to save your image in' + #13#10 +
+                    'one of the previously named formats.');  
+      OniImage_New.Format := ifX8R8G8B8;
+      new_storetype := 8;
+    end;
+
+    OniImage_New.SaveDataToStream(check_fading.Checked, TStream(mem));
+
+    newsize := mem.Size;
+    mem.Seek(0, soFromBeginning);
+
+    if (newsize > old_size) and (ConManager.Connection[ConnectionID].Backend = DB_ONI) then
+      new_rawaddr := ConManager.Connection[ConnectionID].AppendRawFile(
+        not (ConManager.Connection[ConnectionID].DataOS = DOS_WIN), mem)
+    else
+    begin
+      new_rawaddr := old_rawaddr;
+      ConManager.Connection[ConnectionID].UpdateRawFile(fileid, $9C, mem);
+    end;
+
+    if check_fading.Checked then
+      oldfading := oldfading or $01
+    else
+      oldfading := oldfading and (not Byte($01));
+    ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $88, 1, @datbyte);
+    datbyte := $10;
+//    if check_transparency.Checked then
+//      datbyte := datbyte or $04;
+    ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $89, 1, @datbyte);
+    datbyte := OniImage_New.Width[1];
+    ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $8C, 2, @datbyte);
+    datbyte := OniImage_New.Height[1];
+    ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $8E, 2, @datbyte);
+    ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $90, 1, @new_storetype);
+    if not (ConManager.Connection[ConnectionID].DataOS = DOS_WIN) then
+      ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $A0, 4, @new_rawaddr)
+    else
+      ConManager.Connection[ConnectionID].UpdateDatFilePart(fileid, $9C, 4, @new_rawaddr);
+
+    ShowMessage('TXMP-image replaced');
+    Self.listClick(Self);
+  end;
+end;
+
+
+
+
+procedure TForm_TxmpReplace.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+  OniImage_Old.Free;
+  OniImage_New.Free;
+  inherited;
+end;
+
+
+
+
+procedure TForm_TxmpReplace.FormCreate(Sender: TObject);
+begin
+  inherited;
+  OniImage_Old := TOniImage.Create;
+  OniImage_New := TOniImage.Create;
+  Self.AllowedExts := 'TXMP';
+  Self.OnNewFileSelected := SelectFile;
+  opend.Filter := saved.Filter;
+end;
+
+
+
+
+procedure TForm_TxmpReplace.btn_saveClick(Sender: TObject);
+begin
+  if saved.Execute then
+    OniImage_Old.WriteToFile(saved.FileName);
+end;
+
+begin
+  AddToolListEntry('txmpreplace', 'TXMP Replacer', 'TXMP');
+end.
