Many new features! Have to be used.
This commit is contained in:
BIN
PROGRAMICON.ico
Normal file
BIN
PROGRAMICON.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
65
tim2view.dpr
Normal file
65
tim2view.dpr
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
program tim2view;
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows,
|
||||||
|
Vcl.Forms,
|
||||||
|
Vcl.Themes,
|
||||||
|
Vcl.Styles,
|
||||||
|
ecc in 'units\ecc.pas',
|
||||||
|
edc in 'units\edc.pas',
|
||||||
|
uCDIMAGE in 'units\uCDIMAGE.pas',
|
||||||
|
uCommon in 'Units\uCommon.pas',
|
||||||
|
uMain in 'Units\uMain.pas' {frmMain},
|
||||||
|
uScanThread in 'Units\uScanThread.pas',
|
||||||
|
uTIM in 'units\uTIM.pas',
|
||||||
|
uDrawTIM in 'units\uDrawTIM.pas',
|
||||||
|
uEventWaitThread in 'units\uEventWaitThread.pas',
|
||||||
|
uBrowseForFolder in 'units\uBrowseForFolder.pas';
|
||||||
|
|
||||||
|
{$R *.res}
|
||||||
|
|
||||||
|
const
|
||||||
|
cMailslot = '\\.\mailslot\t2v_slot';
|
||||||
|
cEventNname = 't2v_open_event';
|
||||||
|
|
||||||
|
var
|
||||||
|
ClientMailSlot: THandle;
|
||||||
|
path: string;
|
||||||
|
BytesWritten: DWORD;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ServerMailSlot := CreateMailslot(cMailslot, 0, MAILSLOT_WAIT_FOREVER, nil);
|
||||||
|
|
||||||
|
if ServerMailSlot = INVALID_HANDLE_VALUE then
|
||||||
|
begin
|
||||||
|
if GetLastError = ERROR_ALREADY_EXISTS then
|
||||||
|
begin
|
||||||
|
ClientMailSlot := CreateFile(cMailslot, GENERIC_WRITE, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
|
||||||
|
if ParamCount > 0 then
|
||||||
|
path := ParamStr(1)
|
||||||
|
else
|
||||||
|
path := '';
|
||||||
|
|
||||||
|
WriteFile(ClientMailSlot, path[1], Length(path) * SizeOf(Char), BytesWritten, nil);
|
||||||
|
|
||||||
|
CommandEvent := OpenEvent(EVENT_MODIFY_STATE, False, cEventNname);
|
||||||
|
SetEvent(CommandEvent);
|
||||||
|
|
||||||
|
CloseHandle(CommandEvent);
|
||||||
|
CloseHandle(ClientMailSlot);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
CommandEvent := CreateEvent(nil, False, False, cEventNname);
|
||||||
|
|
||||||
|
Application.Initialize;
|
||||||
|
Application.MainFormOnTaskbar := True;
|
||||||
|
Application.CreateForm(TfrmMainT2V, frmMain);
|
||||||
|
Application.Run;
|
||||||
|
|
||||||
|
CloseHandle(ServerMailSlot);
|
||||||
|
CloseHandle(CommandEvent);
|
||||||
|
end;
|
||||||
|
end.
|
||||||
193
tim2view.dproj
Normal file
193
tim2view.dproj
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectGuid>{20D93FC8-189B-40E7-8CB2-DBD3BD57B0B5}</ProjectGuid>
|
||||||
|
<ProjectVersion>14.6</ProjectVersion>
|
||||||
|
<FrameworkType>VCL</FrameworkType>
|
||||||
|
<MainSource>tim2view.dpr</MainSource>
|
||||||
|
<Base>True</Base>
|
||||||
|
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||||
|
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||||
|
<TargetedPlatforms>1</TargetedPlatforms>
|
||||||
|
<AppType>Application</AppType>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
|
||||||
|
<Base_Win32>true</Base_Win32>
|
||||||
|
<CfgParent>Base</CfgParent>
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
|
||||||
|
<Base_Win64>true</Base_Win64>
|
||||||
|
<CfgParent>Base</CfgParent>
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||||
|
<Cfg_1>true</Cfg_1>
|
||||||
|
<CfgParent>Base</CfgParent>
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
|
||||||
|
<Cfg_1_Win32>true</Cfg_1_Win32>
|
||||||
|
<CfgParent>Cfg_1</CfgParent>
|
||||||
|
<Cfg_1>true</Cfg_1>
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||||
|
<Cfg_2>true</Cfg_2>
|
||||||
|
<CfgParent>Base</CfgParent>
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
|
||||||
|
<Cfg_2_Win32>true</Cfg_2_Win32>
|
||||||
|
<CfgParent>Cfg_2</CfgParent>
|
||||||
|
<Cfg_2>true</Cfg_2>
|
||||||
|
<Base>true</Base>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Base)'!=''">
|
||||||
|
<DCC_UsePackage>bindcompfmx;fmx;rtl;dbrtl;DbxClientDriver;IndySystem;bindcomp;inetdb;DataSnapClient;DataSnapServer;DataSnapCommon;DBXInterBaseDriver;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;dbxcds;DBXMySQLDriver;bindengine;soaprtl;DBXOracleDriver;CustomIPTransport;dsnap;DBXInformixDriver;IndyCore;fmxase;DBXFirebirdDriver;inet;fmxobj;inetdbxpress;DBXSybaseASADriver;fmxdae;IPIndyImpl;dbexpress;DataSnapIndy10ServerTransport;$(DCC_UsePackage)</DCC_UsePackage>
|
||||||
|
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
|
||||||
|
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
|
||||||
|
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
|
||||||
|
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
|
||||||
|
<DCC_E>false</DCC_E>
|
||||||
|
<DCC_N>false</DCC_N>
|
||||||
|
<DCC_S>false</DCC_S>
|
||||||
|
<DCC_F>false</DCC_F>
|
||||||
|
<DCC_K>false</DCC_K>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Base_Win32)'!=''">
|
||||||
|
<DCC_UnitSearchPath>.\units;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
|
||||||
|
<DCC_UsePackage>vcldbx;TeeDB;inetdbbde;vclib;DBXOdbcDriver;Tee;DBXSybaseASEDriver;ibxpress;svnui;vclimg;fmi;intrawebdb_120_160;vclactnband;vcldb;FMXTee;vcldsnap;bindcompvcl;TeeUI;vclie;DBXDb2Driver;Intraweb_120_160;vcltouch;websnap;vclribbon;VclSmp;vcl;DataSnapConnectors;CloudService;DBXMSSQLDriver;FmxTeeUI;dsnapcon;vclx;webdsnap;svn;bdertl;adortl;$(DCC_UsePackage)</DCC_UsePackage>
|
||||||
|
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||||
|
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
|
||||||
|
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||||
|
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
|
||||||
|
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Base_Win64)'!=''">
|
||||||
|
<DCC_UsePackage>DBXOdbcDriver;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;vcldsnap;bindcompvcl;vclie;DBXDb2Driver;vcltouch;websnap;VclSmp;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;adortl;$(DCC_UsePackage)</DCC_UsePackage>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||||
|
<Manifest_File>None</Manifest_File>
|
||||||
|
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||||
|
<VerInfo_Locale>1049</VerInfo_Locale>
|
||||||
|
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
|
||||||
|
<DCC_Optimize>false</DCC_Optimize>
|
||||||
|
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
|
||||||
|
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||||
|
<DCC_RemoteDebug>true</DCC_RemoteDebug>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
|
||||||
|
<DCC_SUSPICIOUS_TYPECAST>false</DCC_SUSPICIOUS_TYPECAST>
|
||||||
|
<DCC_MapFile>3</DCC_MapFile>
|
||||||
|
<DCC_Optimize>true</DCC_Optimize>
|
||||||
|
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.435;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||||
|
<VerInfo_Build>435</VerInfo_Build>
|
||||||
|
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
|
||||||
|
<DCC_IOChecking>false</DCC_IOChecking>
|
||||||
|
<DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck>
|
||||||
|
<VerInfo_AutoIncVersion>true</VerInfo_AutoIncVersion>
|
||||||
|
<DCC_RangeChecking>true</DCC_RangeChecking>
|
||||||
|
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||||
|
<Icon_MainIcon>PROGRAMICON.ico</Icon_MainIcon>
|
||||||
|
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||||
|
<DCC_RemoteDebug>false</DCC_RemoteDebug>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||||
|
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
|
||||||
|
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
|
||||||
|
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
|
||||||
|
<DCC_DebugInformation>false</DCC_DebugInformation>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||||
|
<DCC_MapFile>3</DCC_MapFile>
|
||||||
|
<DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols>
|
||||||
|
<DCC_Define>madExcept;LeakChecking;$(DCC_Define)</DCC_Define>
|
||||||
|
<DCC_DebugInformation>true</DCC_DebugInformation>
|
||||||
|
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||||
|
<DCC_IOChecking>false</DCC_IOChecking>
|
||||||
|
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<DelphiCompile Include="$(MainSource)">
|
||||||
|
<MainSource>MainSource</MainSource>
|
||||||
|
</DelphiCompile>
|
||||||
|
<DCCReference Include="units\ecc.pas"/>
|
||||||
|
<DCCReference Include="units\edc.pas"/>
|
||||||
|
<DCCReference Include="units\uCDIMAGE.pas"/>
|
||||||
|
<DCCReference Include="Units\uCommon.pas"/>
|
||||||
|
<DCCReference Include="Units\uMain.pas">
|
||||||
|
<Form>frmMain</Form>
|
||||||
|
</DCCReference>
|
||||||
|
<DCCReference Include="Units\uScanThread.pas"/>
|
||||||
|
<DCCReference Include="units\uTIM.pas"/>
|
||||||
|
<DCCReference Include="units\uDrawTIM.pas"/>
|
||||||
|
<DCCReference Include="units\uEventWaitThread.pas"/>
|
||||||
|
<DCCReference Include="units\uBrowseForFolder.pas"/>
|
||||||
|
<BuildConfiguration Include="Release">
|
||||||
|
<Key>Cfg_2</Key>
|
||||||
|
<CfgParent>Base</CfgParent>
|
||||||
|
</BuildConfiguration>
|
||||||
|
<BuildConfiguration Include="Base">
|
||||||
|
<Key>Base</Key>
|
||||||
|
</BuildConfiguration>
|
||||||
|
<BuildConfiguration Include="Debug">
|
||||||
|
<Key>Cfg_1</Key>
|
||||||
|
<CfgParent>Base</CfgParent>
|
||||||
|
</BuildConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ProjectExtensions>
|
||||||
|
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
|
||||||
|
<Borland.ProjectType/>
|
||||||
|
<BorlandProject>
|
||||||
|
<Delphi.Personality>
|
||||||
|
<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">1049</VersionInfo>
|
||||||
|
<VersionInfo Name="CodePage">1251</VersionInfo>
|
||||||
|
</VersionInfo>
|
||||||
|
<VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="CompanyName"/>
|
||||||
|
<VersionInfoKeys Name="FileDescription"/>
|
||||||
|
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="InternalName"/>
|
||||||
|
<VersionInfoKeys Name="LegalCopyright"/>
|
||||||
|
<VersionInfoKeys Name="LegalTrademarks"/>
|
||||||
|
<VersionInfoKeys Name="OriginalFilename"/>
|
||||||
|
<VersionInfoKeys Name="ProductName"/>
|
||||||
|
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
|
||||||
|
<VersionInfoKeys Name="Comments"/>
|
||||||
|
</VersionInfoKeys>
|
||||||
|
<Source>
|
||||||
|
<Source Name="MainSource">tim2view.dpr</Source>
|
||||||
|
</Source>
|
||||||
|
<Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k170.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp170.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k170.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||||
|
<Excluded_Packages Name="$(BDSBIN)\dclofficexp170.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||||
|
</Excluded_Packages>
|
||||||
|
</Delphi.Personality>
|
||||||
|
<Deployment/>
|
||||||
|
<Platforms>
|
||||||
|
<Platform value="Win32">True</Platform>
|
||||||
|
<Platform value="Win64">False</Platform>
|
||||||
|
</Platforms>
|
||||||
|
</BorlandProject>
|
||||||
|
<ProjectFileVersion>12</ProjectFileVersion>
|
||||||
|
</ProjectExtensions>
|
||||||
|
<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
|
||||||
|
<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
|
||||||
|
</Project>
|
||||||
10
tim2view.dproj.local
Normal file
10
tim2view.dproj.local
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<BorlandProject>
|
||||||
|
<Transactions>
|
||||||
|
<Transaction>1899.12.30 00:00:00.000.267,D:\Tim2View\units\uTIMClass.pas=</Transaction>
|
||||||
|
<Transaction>2014.02.18 01:41:36.622,=D:\TimView2\units\EventWaitThread.pas</Transaction>
|
||||||
|
<Transaction>2014.02.18 02:21:20.250,D:\TimView2\units\BrowseForFolderU.pas=</Transaction>
|
||||||
|
<Transaction>2014.02.18 02:21:57.121,=D:\TimView2\units\uEventWaitThread.pas</Transaction>
|
||||||
|
<Transaction>2014.02.18 02:22:03.673,=D:\TimView2\units\uBrowseForFolder.pas</Transaction>
|
||||||
|
</Transactions>
|
||||||
|
</BorlandProject>
|
||||||
BIN
tim2view.identcache
Normal file
BIN
tim2view.identcache
Normal file
Binary file not shown.
10011
units/NativeXml.pas
Normal file
10011
units/NativeXml.pas
Normal file
File diff suppressed because it is too large
Load Diff
104
units/ecc.pas
Normal file
104
units/ecc.pas
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
unit ecc;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
uCommon;
|
||||||
|
|
||||||
|
const
|
||||||
|
L1_RAW = 24;
|
||||||
|
L1_Q = 4;
|
||||||
|
L1_P = 4;
|
||||||
|
|
||||||
|
L2_RAW = (1024 * 2);
|
||||||
|
L2_Q = (26 * 2 * 2);
|
||||||
|
L2_P = (43 * 2 * 2);
|
||||||
|
|
||||||
|
Procedure encode_L2_Q(Data: PBytesArray);
|
||||||
|
Procedure encode_L2_P(Data: PBytesArray);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$INCLUDE l2sq_table.pas}
|
||||||
|
|
||||||
|
Procedure encode_L2_Q(Data: PBytesArray);
|
||||||
|
var
|
||||||
|
i, j, PQ, PD, PD_S, PD_P: Integer;
|
||||||
|
a, b: Word;
|
||||||
|
begin
|
||||||
|
// unsigned char inout[4 + L2_RAW + 4 + 8 + L2_P + L2_Q];
|
||||||
|
|
||||||
|
PD := 0;
|
||||||
|
PQ := PD + 4 + L2_RAW + 4 + 8 + L2_P;
|
||||||
|
// Q := Pointer(LongWord(Data) + 4 + L2_RAW + 4 + 8 + L2_P);
|
||||||
|
PD_S := PD;
|
||||||
|
For j := 0 To 26 - 1 do
|
||||||
|
begin
|
||||||
|
a := 0;
|
||||||
|
b := 0;
|
||||||
|
PD_P := PD_S;
|
||||||
|
For i := 0 To 43 - 1 do
|
||||||
|
begin
|
||||||
|
(* LSB *)
|
||||||
|
a := a XOR L2sq[i][Data^[PD_P]];
|
||||||
|
Inc(PD_P);
|
||||||
|
|
||||||
|
(* MSB *)
|
||||||
|
b := b XOR L2sq[i][Data^[PD_P]];
|
||||||
|
|
||||||
|
Inc(PD_P, 2 * 44 - 1);
|
||||||
|
if PD_P >= PD + (4 + L2_RAW + 4 + 8 + L2_P) Then
|
||||||
|
Dec(PD_P, (4 + L2_RAW + 4 + 8 + L2_P));
|
||||||
|
end;
|
||||||
|
Data^[PQ + 0] := a SHR 8;
|
||||||
|
Move(a, Data^[PQ + 26 * 2], 1);
|
||||||
|
// Q^[26*2] := a;
|
||||||
|
Data^[PQ + 1] := b SHR 8;
|
||||||
|
Move(b, Data^[PQ + 26 * 2 + 1], 1);
|
||||||
|
// Q^[26*2+1] := b;
|
||||||
|
|
||||||
|
Inc(PQ, 2);
|
||||||
|
Inc(PD_S, 2 * 43);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Procedure encode_L2_P(Data: PBytesArray);
|
||||||
|
// unsigned char inout[4 + L2_RAW + 4 + 8 + L2_P];
|
||||||
|
var
|
||||||
|
i, j, PD, PD_PP, PD_P: Integer;
|
||||||
|
a, b: Word;
|
||||||
|
begin
|
||||||
|
|
||||||
|
PD := 0;
|
||||||
|
PD_PP := PD + 4 + L2_RAW + 4 + 8;
|
||||||
|
// LongWord(P) := PD + 4 + L2_RAW + 4 + 8;
|
||||||
|
|
||||||
|
For j := 0 To 43 - 1 do
|
||||||
|
begin
|
||||||
|
a := 0;
|
||||||
|
b := 0;
|
||||||
|
PD_P := PD;
|
||||||
|
For i := 19 to 43 - 1 do
|
||||||
|
begin
|
||||||
|
(* LSB *)
|
||||||
|
a := a xor L2sq[i][Data^[PD_P]];
|
||||||
|
Inc(PD_P);
|
||||||
|
|
||||||
|
(* MSB *)
|
||||||
|
b := b xor L2sq[i][Data^[PD_P]];
|
||||||
|
|
||||||
|
Inc(PD_P, 2 * 43 - 1);
|
||||||
|
end;
|
||||||
|
Data^[PD_PP + 0] := a SHR 8;
|
||||||
|
Move(a, Data^[PD_PP + 43 * 2], SizeOf(a));
|
||||||
|
// P^[43*2] := a;
|
||||||
|
Data^[PD_PP + 1] := b SHR 8;
|
||||||
|
Move(b, Data^[PD_PP + 43 * 2 + 1], SizeOf(b));
|
||||||
|
// P^[43*2+1] := b;
|
||||||
|
|
||||||
|
Inc(PD_PP, 2);
|
||||||
|
Inc(PD, 2);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
73
units/edc.pas
Normal file
73
units/edc.pas
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
unit edc;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
const
|
||||||
|
EDC_crctable: Array [Byte] of LongWord = ($00000000, $90910101, $91210201,
|
||||||
|
$01B00300, $92410401, $02D00500, $03600600, $93F10701, $94810801, $04100900,
|
||||||
|
$05A00A00, $95310B01, $06C00C00, $96510D01, $97E10E01, $07700F00, $99011001,
|
||||||
|
$09901100, $08201200, $98B11301, $0B401400, $9BD11501, $9A611601, $0AF01700,
|
||||||
|
$0D801800, $9D111901, $9CA11A01, $0C301B00, $9FC11C01, $0F501D00, $0EE01E00,
|
||||||
|
$9E711F01, $82012001, $12902100, $13202200, $83B12301, $10402400, $80D12501,
|
||||||
|
$81612601, $11F02700, $16802800, $86112901, $87A12A01, $17302B00, $84C12C01,
|
||||||
|
$14502D00, $15E02E00, $85712F01, $1B003000, $8B913101, $8A213201, $1AB03300,
|
||||||
|
$89413401, $19D03500, $18603600, $88F13701, $8F813801, $1F103900, $1EA03A00,
|
||||||
|
$8E313B01, $1DC03C00, $8D513D01, $8CE13E01, $1C703F00, $B4014001, $24904100,
|
||||||
|
$25204200, $B5B14301, $26404400, $B6D14501, $B7614601, $27F04700, $20804800,
|
||||||
|
$B0114901, $B1A14A01, $21304B00, $B2C14C01, $22504D00, $23E04E00, $B3714F01,
|
||||||
|
$2D005000, $BD915101, $BC215201, $2CB05300, $BF415401, $2FD05500, $2E605600,
|
||||||
|
$BEF15701, $B9815801, $29105900, $28A05A00, $B8315B01, $2BC05C00, $BB515D01,
|
||||||
|
$BAE15E01, $2A705F00, $36006000, $A6916101, $A7216201, $37B06300, $A4416401,
|
||||||
|
$34D06500, $35606600, $A5F16701, $A2816801, $32106900, $33A06A00, $A3316B01,
|
||||||
|
$30C06C00, $A0516D01, $A1E16E01, $31706F00, $AF017001, $3F907100, $3E207200,
|
||||||
|
$AEB17301, $3D407400, $ADD17501, $AC617601, $3CF07700, $3B807800, $AB117901,
|
||||||
|
$AAA17A01, $3A307B00, $A9C17C01, $39507D00, $38E07E00, $A8717F01, $D8018001,
|
||||||
|
$48908100, $49208200, $D9B18301, $4A408400, $DAD18501, $DB618601, $4BF08700,
|
||||||
|
$4C808800, $DC118901, $DDA18A01, $4D308B00, $DEC18C01, $4E508D00, $4FE08E00,
|
||||||
|
$DF718F01, $41009000, $D1919101, $D0219201, $40B09300, $D3419401, $43D09500,
|
||||||
|
$42609600, $D2F19701, $D5819801, $45109900, $44A09A00, $D4319B01, $47C09C00,
|
||||||
|
$D7519D01, $D6E19E01, $46709F00, $5A00A000, $CA91A101, $CB21A201, $5BB0A300,
|
||||||
|
$C841A401, $58D0A500, $5960A600, $C9F1A701, $CE81A801, $5E10A900, $5FA0AA00,
|
||||||
|
$CF31AB01, $5CC0AC00, $CC51AD01, $CDE1AE01, $5D70AF00, $C301B001, $5390B100,
|
||||||
|
$5220B200, $C2B1B301, $5140B400, $C1D1B501, $C061B601, $50F0B700, $5780B800,
|
||||||
|
$C711B901, $C6A1BA01, $5630BB00, $C5C1BC01, $5550BD00, $54E0BE00, $C471BF01,
|
||||||
|
$6C00C000, $FC91C101, $FD21C201, $6DB0C300, $FE41C401, $6ED0C500, $6F60C600,
|
||||||
|
$FFF1C701, $F881C801, $6810C900, $69A0CA00, $F931CB01, $6AC0CC00, $FA51CD01,
|
||||||
|
$FBE1CE01, $6B70CF00, $F501D001, $6590D100, $6420D200, $F4B1D301, $6740D400,
|
||||||
|
$F7D1D501, $F661D601, $66F0D700, $6180D800, $F111D901, $F0A1DA01, $6030DB00,
|
||||||
|
$F3C1DC01, $6350DD00, $62E0DE00, $F271DF01, $EE01E001, $7E90E100, $7F20E200,
|
||||||
|
$EFB1E301, $7C40E400, $ECD1E501, $ED61E601, $7DF0E700, $7A80E800, $EA11E901,
|
||||||
|
$EBA1EA01, $7B30EB00, $E8C1EC01, $7850ED00, $79E0EE00, $E971EF01, $7700F000,
|
||||||
|
$E791F101, $E621F201, $76B0F300, $E541F401, $75D0F500, $7460F600, $E4F1F701,
|
||||||
|
$E381F801, $7310F900, $72A0FA00, $E231FB01, $71C0FC00, $E151FD01, $E0E1FE01,
|
||||||
|
$7070FF00);
|
||||||
|
|
||||||
|
Function build_edc(Data: Pointer; Size: Integer): LongWord;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
Function build_edc(Data: Pointer; Size: Integer): LongWord;
|
||||||
|
var
|
||||||
|
P: PByte;
|
||||||
|
begin
|
||||||
|
P := Data;
|
||||||
|
Result := 0;
|
||||||
|
Size := Size div 4;
|
||||||
|
while (Size > 0) do
|
||||||
|
begin
|
||||||
|
Dec(Size);
|
||||||
|
// result = EDC_crctable[(result ^ *p++) & 0xffL] ^ (result >> 8);
|
||||||
|
If Result = $2D5E3B78 Then
|
||||||
|
ReadLn;
|
||||||
|
Result := EDC_crctable[(Result xor P^) and $FF] xor (Result SHR 8);
|
||||||
|
Inc(P);
|
||||||
|
Result := EDC_crctable[(Result xor P^) and $FF] xor (Result SHR 8);
|
||||||
|
Inc(P);
|
||||||
|
Result := EDC_crctable[(Result xor P^) and $FF] xor (Result SHR 8);
|
||||||
|
Inc(P);
|
||||||
|
Result := EDC_crctable[(Result xor P^) and $FF] xor (Result SHR 8);
|
||||||
|
Inc(P);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
1164
units/l2sq_table.pas
Normal file
1164
units/l2sq_table.pas
Normal file
File diff suppressed because it is too large
Load Diff
219
units/sdDebug.pas
Normal file
219
units/sdDebug.pas
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
{ unit sdDebug
|
||||||
|
|
||||||
|
universal method for debugging
|
||||||
|
|
||||||
|
Exceptions often are a hindrance, so instead use these classes
|
||||||
|
to give important info to the application or user with these
|
||||||
|
three basic classes
|
||||||
|
|
||||||
|
Besides debug methods, this unit also defines a few compatibility types:
|
||||||
|
The include file simdesign.inc defines $D5UP and after the
|
||||||
|
uses-clause these types for D5 are defined. This way, many simdesign
|
||||||
|
projects are compatible with Delphi 5.
|
||||||
|
fpc: if lazarus + freepascal is defined, Utf8String just reverts to "string".
|
||||||
|
|
||||||
|
Author: Nils Haeck M.Sc.
|
||||||
|
Original Date: 08nov2010
|
||||||
|
copyright (c) SimDesign BV (www.simdesign.nl)
|
||||||
|
}
|
||||||
|
unit sdDebug;
|
||||||
|
|
||||||
|
{$i simdesign.inc}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes;
|
||||||
|
|
||||||
|
{$ifdef D5UP}
|
||||||
|
// D5 compatibility types
|
||||||
|
const
|
||||||
|
MinsPerHour = 60;
|
||||||
|
MinsPerDay = MinsPerHour * 24;
|
||||||
|
soCurrent = soFromCurrent;
|
||||||
|
soBeginning = soFromBeginning;
|
||||||
|
soEnd = soFromEnd;
|
||||||
|
|
||||||
|
type
|
||||||
|
Utf8String = AnsiString;
|
||||||
|
TSeekOrigin = word;
|
||||||
|
|
||||||
|
PIntegerArray = ^TIntegerArray;
|
||||||
|
TIntegerArray = array of Integer;
|
||||||
|
|
||||||
|
PByte = ^Byte;
|
||||||
|
PInteger = ^Integer;
|
||||||
|
PSingle = ^Single;
|
||||||
|
PDouble = ^Double;
|
||||||
|
|
||||||
|
// TFormatSettings stub
|
||||||
|
TFormatSettings = record
|
||||||
|
end;
|
||||||
|
|
||||||
|
PWord = ^Word;
|
||||||
|
|
||||||
|
function StrToFloatDef(S: AnsiString; Default: Double; AFormatSettings: TFormatSettings): Double;
|
||||||
|
function StrToBool(S: AnsiString): Boolean;
|
||||||
|
function StrToBoolDef(S: AnsiString; Default: Boolean): Boolean;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// lazarus compatibility
|
||||||
|
{$ifdef fpc}
|
||||||
|
type
|
||||||
|
Utf8String = string;
|
||||||
|
{$endif fpc}
|
||||||
|
|
||||||
|
// Delphi unicode compatibility
|
||||||
|
{$ifndef UNICODE}
|
||||||
|
type
|
||||||
|
UnicodeString = WideString;
|
||||||
|
RawByteString = AnsiString;
|
||||||
|
{$endif UNICODE}
|
||||||
|
|
||||||
|
type
|
||||||
|
TsdWarnStyle = (wsInfo, wsHint, wsWarn, wsFail);
|
||||||
|
|
||||||
|
const
|
||||||
|
cWarnStyleNames: array[TsdWarnStyle] of Utf8String = ('info', 'hint', 'warn', 'fail');
|
||||||
|
|
||||||
|
type
|
||||||
|
// event with debug data
|
||||||
|
TsdDebugEvent = procedure(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String) of object;
|
||||||
|
|
||||||
|
// simple update event
|
||||||
|
TsdUpdateEvent = procedure(Sender: TObject) of object;
|
||||||
|
|
||||||
|
TDebugComponent = class(TComponent)
|
||||||
|
protected
|
||||||
|
FOnDebugOut: TsdDebugEvent;
|
||||||
|
public
|
||||||
|
procedure DoDebugOut(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String); virtual;
|
||||||
|
// Connect to OnDebugOut to get debug information in the client application
|
||||||
|
property OnDebugOut: TsdDebugEvent read FOnDebugOut write FOnDebugOut;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TDebugObject = class(TObject)
|
||||||
|
protected
|
||||||
|
FOnDebugOut: TsdDebugEvent;
|
||||||
|
procedure DoDebugOut(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String); virtual;
|
||||||
|
public
|
||||||
|
property OnDebugOut: TsdDebugEvent read FOnDebugOut write FOnDebugOut;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TDebugPersistent = class(TPersistent)
|
||||||
|
protected
|
||||||
|
FOwner: TDebugComponent;
|
||||||
|
procedure DoDebugOut(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String); virtual;
|
||||||
|
public
|
||||||
|
constructor CreateDebug(AOwner: TDebugComponent); virtual;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Functions }
|
||||||
|
|
||||||
|
function sdDebugMessageToString(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String): Utf8String;
|
||||||
|
|
||||||
|
function sdClassName(AObject: TObject): Utf8String;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{$ifdef D5UP}
|
||||||
|
// D5 compatibility types
|
||||||
|
uses
|
||||||
|
SysUtils;
|
||||||
|
|
||||||
|
function StrToFloatDef(S: AnsiString; Default: Double; AFormatSettings: TFormatSettings): Double;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Result:= StrToFloat(S);
|
||||||
|
except
|
||||||
|
Result:= Default;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Only basic support
|
||||||
|
function StrToBool(S: AnsiString): Boolean;
|
||||||
|
begin
|
||||||
|
S := LowerCase(S);
|
||||||
|
if (S = 'no') or (S = '0') or (S = 'false') then
|
||||||
|
Result := False
|
||||||
|
else
|
||||||
|
if (S = 'yes') or (S = '1') or (S = 'true') then
|
||||||
|
Result:= True
|
||||||
|
else
|
||||||
|
raise EConvertError.Create('');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function StrToBoolDef(S: AnsiString; Default: Boolean): Boolean;
|
||||||
|
begin
|
||||||
|
try
|
||||||
|
Result := StrToBool(S);
|
||||||
|
except
|
||||||
|
Result := Default;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
{ TDebugComponent }
|
||||||
|
|
||||||
|
procedure TDebugComponent.DoDebugOut(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String);
|
||||||
|
var
|
||||||
|
AOwner: TComponent;
|
||||||
|
begin
|
||||||
|
AOwner := Self;
|
||||||
|
while AOwner is TDebugComponent do
|
||||||
|
begin
|
||||||
|
if assigned(TDebugComponent(AOwner).FOnDebugOut) then
|
||||||
|
begin
|
||||||
|
TDebugComponent(AOwner).FOnDebugOut(Sender, WarnStyle, AMessage);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
AOwner := AOwner.Owner;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDebugObject }
|
||||||
|
|
||||||
|
procedure TDebugObject.DoDebugOut(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String);
|
||||||
|
begin
|
||||||
|
if assigned(FOnDebugOut) then
|
||||||
|
FOnDebugOut(Sender, WarnStyle, AMessage);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TDebugPersistent }
|
||||||
|
|
||||||
|
constructor TDebugPersistent.CreateDebug(AOwner: TDebugComponent);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FOwner := AOwner;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TDebugPersistent.DoDebugOut(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String);
|
||||||
|
begin
|
||||||
|
if FOwner is TDebugComponent then
|
||||||
|
TDebugComponent(FOwner).DoDebugOut(Sender, WarnStyle, AMessage);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Functions }
|
||||||
|
|
||||||
|
function sdDebugMessageToString(Sender: TObject; WarnStyle: TsdWarnStyle; const AMessage: Utf8String): Utf8String;
|
||||||
|
var
|
||||||
|
SenderString: Utf8String;
|
||||||
|
begin
|
||||||
|
if assigned(Sender) then
|
||||||
|
SenderString := Utf8String(Sender.ClassName)
|
||||||
|
else
|
||||||
|
SenderString := '';
|
||||||
|
Result := '[' + cWarnStyleNames[WarnStyle] + '] ' + SenderString + ': ' + AMessage;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function sdClassName(AObject: TObject): Utf8String;
|
||||||
|
begin
|
||||||
|
Result := 'nil';
|
||||||
|
if assigned(AObject) then
|
||||||
|
Result := Utf8String(AObject.ClassName);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
309
units/sdStreams.pas
Normal file
309
units/sdStreams.pas
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
{ sdStreams.pas
|
||||||
|
|
||||||
|
- TsdFastMemStream with improved capacity setting
|
||||||
|
- TsdStringStream
|
||||||
|
- TsdBufferWriter
|
||||||
|
|
||||||
|
Author: Nils Haeck M.Sc.
|
||||||
|
copyright (c) 2002 - 2011 SimDesign BV (www.simdesign.nl)
|
||||||
|
}
|
||||||
|
unit sdStreams;
|
||||||
|
|
||||||
|
{$ifdef lcl}{$MODE Delphi}{$endif}
|
||||||
|
|
||||||
|
{$define simdesign.inc}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, sdDebug;
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
// TsdFastMemStream deals differently with capacity compared to a normal
|
||||||
|
// TMemoryStream; it increases the capacity with the natural growing function
|
||||||
|
// (fibonacci) each time, and has an initial capacity of $1000. The initial
|
||||||
|
// capacity is configurable with the create parameter.
|
||||||
|
TsdFastMemStream = class(TStream)
|
||||||
|
private
|
||||||
|
FMemory: Pointer;
|
||||||
|
FPosition: longint;
|
||||||
|
FFib1: longint;
|
||||||
|
FCapacity: longint;
|
||||||
|
FSize: longint;
|
||||||
|
protected
|
||||||
|
procedure SetCapacity(Value: longint);
|
||||||
|
procedure SetSize(NewSize: Longint); override;
|
||||||
|
public
|
||||||
|
constructor Create(InitialCapacity: longint = $1000);
|
||||||
|
destructor Destroy; override;
|
||||||
|
procedure Clear;
|
||||||
|
function Read(var Buffer; Count: Longint): Longint; override;
|
||||||
|
function Write(const Buffer; Count: Longint): Longint; override;
|
||||||
|
function Seek(Offset: Longint; Origin: Word): Longint; override;
|
||||||
|
procedure LoadFromFile(AFilename: string);
|
||||||
|
procedure LoadFromStream(Stream: TStream);
|
||||||
|
procedure SaveToFile(AFilename: string);
|
||||||
|
procedure SaveToStream(Stream: TStream);
|
||||||
|
property Memory: Pointer read FMemory;
|
||||||
|
property Size: longint read FSize write SetSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Delphi's implementation of TStringStream is severely flawed, it does a SetLength
|
||||||
|
// on each write, which slows down everything to a crawl. This implementation over-
|
||||||
|
// comes this issue.
|
||||||
|
TsdStringStream = class(TsdFastMemStream)
|
||||||
|
public
|
||||||
|
constructor Create(const S: Utf8String);
|
||||||
|
function DataString: Utf8String;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// TsdBufferWriter is a buffered stream that takes another stream (ASource)
|
||||||
|
// and writes only buffer-wise to it, and writes to the stream are first
|
||||||
|
// done to the buffer. This stream type can only support writing.
|
||||||
|
TsdBufferWriter = class(TsdFastMemStream)
|
||||||
|
private
|
||||||
|
FSource: TStream;
|
||||||
|
FChunkSize: integer;
|
||||||
|
FRawBuffer: array of byte;
|
||||||
|
FRawPosition: Integer;
|
||||||
|
protected
|
||||||
|
procedure WriteChunk(Count: integer);
|
||||||
|
public
|
||||||
|
// Create the buffered writer stream by passing the destination stream in ASource,
|
||||||
|
// this destination stream must already be initialized.
|
||||||
|
constructor Create(ASource: TStream; AChunkSize: integer);
|
||||||
|
destructor Destroy; override;
|
||||||
|
function Read(var Buffer; Count: Longint): Longint; override;
|
||||||
|
function Write(const Buffer; Count: Longint): Longint; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
{ TsdFastMemStream }
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.Clear;
|
||||||
|
begin
|
||||||
|
SetCapacity(0);
|
||||||
|
FSize := 0;
|
||||||
|
FPosition := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TsdFastMemStream.Create(InitialCapacity: Integer);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FFib1 := InitialCapacity div 2;
|
||||||
|
FCapacity := InitialCapacity;
|
||||||
|
if FFib1 < 4 then
|
||||||
|
FFib1 := 4;
|
||||||
|
if FCapacity < 4 then
|
||||||
|
FCapacity := 4;
|
||||||
|
ReallocMem(FMemory, FCapacity);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsdFastMemStream.Destroy;
|
||||||
|
begin
|
||||||
|
ReallocMem(FMemory, 0);
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.LoadFromFile(AFilename: string);
|
||||||
|
var
|
||||||
|
Stream: TStream;
|
||||||
|
begin
|
||||||
|
Stream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
|
||||||
|
try
|
||||||
|
LoadFromStream(Stream);
|
||||||
|
finally
|
||||||
|
Stream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.LoadFromStream(Stream: TStream);
|
||||||
|
var
|
||||||
|
Count: Longint;
|
||||||
|
begin
|
||||||
|
Stream.Position := 0;
|
||||||
|
Count := Stream.Size;
|
||||||
|
SetSize(Count);
|
||||||
|
if Count <> 0 then Stream.ReadBuffer(FMemory^, Count);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdFastMemStream.Read(var Buffer; Count: Integer): Longint;
|
||||||
|
begin
|
||||||
|
if (FPosition >= 0) and (Count >= 0) then
|
||||||
|
begin
|
||||||
|
Result := FSize - FPosition;
|
||||||
|
if Result > 0 then
|
||||||
|
begin
|
||||||
|
if Result > Count then
|
||||||
|
Result := Count;
|
||||||
|
Move(Pointer(Longint(FMemory) + FPosition)^, Buffer, Result);
|
||||||
|
Inc(FPosition, Result);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.SaveToFile(AFilename: string);
|
||||||
|
var
|
||||||
|
Stream: TStream;
|
||||||
|
begin
|
||||||
|
Stream := TFileStream.Create(AFileName, fmCreate);
|
||||||
|
try
|
||||||
|
SaveToStream(Stream);
|
||||||
|
finally
|
||||||
|
Stream.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.SaveToStream(Stream: TStream);
|
||||||
|
begin
|
||||||
|
if FSize <> 0 then Stream.WriteBuffer(FMemory^, FSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdFastMemStream.Seek(Offset: Integer; Origin: Word): Longint;
|
||||||
|
begin
|
||||||
|
case Origin of
|
||||||
|
soFromBeginning: FPosition := Offset;
|
||||||
|
soFromCurrent: Inc(FPosition, Offset);
|
||||||
|
soFromEnd: FPosition := FSize + Offset;
|
||||||
|
end;
|
||||||
|
Result := FPosition;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.SetCapacity(Value: longint);
|
||||||
|
// Fibonacci 0,1,1,2,3,5,8,... FCapacity is Fib2.
|
||||||
|
// Fibonacci is a natural growing function where
|
||||||
|
// 0 + 1 = 1; 1 + 1 = 2; 1 + 2 = 3; 2 + 3 = 5; etc
|
||||||
|
var
|
||||||
|
Fib3: longint;
|
||||||
|
begin
|
||||||
|
while FCapacity < Value do
|
||||||
|
begin
|
||||||
|
Fib3 := FFib1 + FCapacity;
|
||||||
|
FFib1 := FCapacity;
|
||||||
|
FCapacity := Fib3;
|
||||||
|
end;
|
||||||
|
ReallocMem(FMemory, FCapacity);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdFastMemStream.SetSize(NewSize: longint);
|
||||||
|
var
|
||||||
|
OldPosition: Longint;
|
||||||
|
begin
|
||||||
|
OldPosition := FPosition;
|
||||||
|
SetCapacity(NewSize);
|
||||||
|
FSize := NewSize;
|
||||||
|
if OldPosition > NewSize then
|
||||||
|
Seek(0, soFromEnd);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdFastMemStream.Write(const Buffer; Count: Integer): Longint;
|
||||||
|
var
|
||||||
|
NewPos: Longint;
|
||||||
|
begin
|
||||||
|
if (FPosition >= 0) and (Count >= 0) then
|
||||||
|
begin
|
||||||
|
NewPos := FPosition + Count;
|
||||||
|
if NewPos > 0 then
|
||||||
|
begin
|
||||||
|
if NewPos > FSize then
|
||||||
|
begin
|
||||||
|
if NewPos > FCapacity then
|
||||||
|
SetCapacity(NewPos);
|
||||||
|
FSize := NewPos;
|
||||||
|
end;
|
||||||
|
System.Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count);
|
||||||
|
FPosition := NewPos;
|
||||||
|
Result := Count;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsdStringStream }
|
||||||
|
|
||||||
|
constructor TsdStringStream.Create(const S: Utf8String);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
SetSize(length(S));
|
||||||
|
if Size > 0 then
|
||||||
|
begin
|
||||||
|
Write(S[1], Size);
|
||||||
|
Position := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdStringStream.DataString: Utf8String;
|
||||||
|
begin
|
||||||
|
SetLength(Result, Size);
|
||||||
|
if Size > 0 then
|
||||||
|
begin
|
||||||
|
Position := 0;
|
||||||
|
Read(Result[1], length(Result));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsdBufferWriter }
|
||||||
|
|
||||||
|
constructor TsdBufferWriter.Create(ASource: TStream; AChunkSize: integer);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FSource := ASource;
|
||||||
|
FChunkSize := AChunkSize;
|
||||||
|
SetLength(FRawBuffer, FChunkSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsdBufferWriter.Destroy;
|
||||||
|
begin
|
||||||
|
// write the last chunk, if any
|
||||||
|
WriteChunk(FRawPosition);
|
||||||
|
// free the rawbuffer
|
||||||
|
SetLength(FRawBuffer, 0);
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdBufferWriter.Read(var Buffer; Count: Integer): Longint;
|
||||||
|
begin
|
||||||
|
// not implemented
|
||||||
|
raise Exception.Create('not implemented');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdBufferWriter.Write(const Buffer; Count: Integer): Longint;
|
||||||
|
var
|
||||||
|
Idx, Siz: integer;
|
||||||
|
begin
|
||||||
|
// index in the source buffer
|
||||||
|
Idx := 0;
|
||||||
|
// remaining size
|
||||||
|
Siz := Count;
|
||||||
|
|
||||||
|
// surplus
|
||||||
|
while FRawPosition + Siz >= FChunkSize do
|
||||||
|
begin
|
||||||
|
Move(TByteArray(Buffer)[Idx], FRawBuffer[FRawPosition], FChunkSize - FRawPosition);
|
||||||
|
WriteChunk(FChunkSize);
|
||||||
|
dec(Siz, FChunkSize - FRawPosition);
|
||||||
|
inc(Idx, FChunkSize - FRawPosition);
|
||||||
|
FRawPosition := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// copy the raw buffer
|
||||||
|
Move(TByteArray(Buffer)[Idx], FRawBuffer[FRawPosition], Siz);
|
||||||
|
inc(FRawPosition, Siz);
|
||||||
|
|
||||||
|
Result := Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdBufferWriter.WriteChunk(Count: integer);
|
||||||
|
begin
|
||||||
|
if Count > 0 then
|
||||||
|
begin
|
||||||
|
FSource.WriteBuffer(FRawBuffer[0], Count);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
765
units/sdStringTable.pas
Normal file
765
units/sdStringTable.pas
Normal file
@@ -0,0 +1,765 @@
|
|||||||
|
{ unit sdStringTable
|
||||||
|
|
||||||
|
An optimized table of *unique* strings, using two separate sorted indices:
|
||||||
|
- by (string) ID
|
||||||
|
- by sdCompareRefString method
|
||||||
|
|
||||||
|
The sdCompareRefString method does not use common alphabetical compare, but
|
||||||
|
rather a comparison from first character, then last character, then 2nd,
|
||||||
|
then before-last, etc. until all characters are compared, or a mismatch is
|
||||||
|
found.
|
||||||
|
|
||||||
|
Since many (programmer) strings have numbers at the end of the string,
|
||||||
|
(e.g. "MyNewNode1", "MyNewNode2", etc), the comparison terminates earlier than
|
||||||
|
with a common alphabetical compare.
|
||||||
|
|
||||||
|
sdStringTable is used by NativeXml but can also be used independently in
|
||||||
|
your projects.
|
||||||
|
|
||||||
|
Author: Nils Haeck M.Sc. (n.haeck@simdesign.nl)
|
||||||
|
Original Date: 28 May 2007
|
||||||
|
|
||||||
|
Modified:
|
||||||
|
05jan2011: enhancement, no longer uses stringrec
|
||||||
|
17jun2011: changed TStringTable ancestor from TDebugPersistent to TDebugComponent
|
||||||
|
24jun2011: "find" fix
|
||||||
|
18jul2011: renamed TsdStringTable to TsdSymbolTable and added TsdSymbolStyle
|
||||||
|
|
||||||
|
It is NOT allowed under ANY circumstances to publish or copy this code
|
||||||
|
without accepting the license conditions in accompanying LICENSE.txt
|
||||||
|
first!
|
||||||
|
|
||||||
|
This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, either express or implied.
|
||||||
|
|
||||||
|
Please visit http://www.simdesign.nl/xml.html for more information.
|
||||||
|
|
||||||
|
Copyright (c) 2007 - 2011 Simdesign BV
|
||||||
|
}
|
||||||
|
unit sdStringTable;
|
||||||
|
|
||||||
|
{$ifdef lcl}{$MODE Delphi}{$endif}
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Contnrs, sdDebug;
|
||||||
|
|
||||||
|
// symbol styles (cardinal)
|
||||||
|
// Default symbol style is ssUnknown, but highlevel code can
|
||||||
|
// distinguish between symbol styles. TsdSymbolTable just stores
|
||||||
|
// the symbol as counted Utf8String.
|
||||||
|
|
||||||
|
const
|
||||||
|
|
||||||
|
ssUnknown = 0; // data not determined yet
|
||||||
|
ssString = 1; // data is a string
|
||||||
|
ssBase64Binary = 2; // data is binary and will be handled by Base64 funcs
|
||||||
|
ssHexBinary = 3; // data is binary and will be handled by BinHex funcs
|
||||||
|
ssBoolean = 4; // boolean (stored in a byte, just 0 and 1 of cardinal)
|
||||||
|
ssCardinal = 5; // cardinal (1..N bytes, see TBinaryXml.ReadCardinal)
|
||||||
|
ssInteger = 6; // integer (1..N bytes)
|
||||||
|
ssDecimal = 7; // decimal value (see TNativeXml.EncodeDecimalSymbol)
|
||||||
|
ssDate = 8; // date (see TNativeXml.EncodeDateSymbol)
|
||||||
|
ssTime = 9; // time (see TNativeXml.EncodeTimeSymbol)
|
||||||
|
ssDateTime = 10; // datetime (see TNativeXml.EncodeDateTimeSymbol)
|
||||||
|
|
||||||
|
// These were the default symbol styles as used by NativeXml. Other units may
|
||||||
|
// define more symbols after the last default symbol
|
||||||
|
|
||||||
|
type
|
||||||
|
// A symbol table, holding a collection of unique strings, sorted in 2 ways
|
||||||
|
// for fast access. Strings can be added with AddString or AddStringRec.
|
||||||
|
// When a string is added or updated, an ID is returned which the application
|
||||||
|
// can use to retrieve the string, using GetString.
|
||||||
|
TsdSymbolTable = class(TDebugComponent)
|
||||||
|
private
|
||||||
|
FByID: TObjectList;
|
||||||
|
FBySymbol: TObjectList;
|
||||||
|
FPluralSymbolCount: integer;
|
||||||
|
function GetSymbolCount: integer;
|
||||||
|
protected
|
||||||
|
public
|
||||||
|
constructor Create(AOwner: TComponent); override;
|
||||||
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
// Clear the string table
|
||||||
|
procedure Clear;
|
||||||
|
|
||||||
|
// Add a potentially new string S to the table, the function
|
||||||
|
// returns its string ID.
|
||||||
|
function AddString(const S: Utf8String): integer;
|
||||||
|
|
||||||
|
// retrieve the string based on its string ID. The string ID is only unique
|
||||||
|
// within this string table, so do not use IDs from other tables.
|
||||||
|
function GetString(ID: integer): Utf8String;
|
||||||
|
|
||||||
|
// total number of symbols in the table
|
||||||
|
property SymbolCount: integer read GetSymbolCount;
|
||||||
|
|
||||||
|
// plural symbols in the table. plural symbols are symbols that have
|
||||||
|
// a frequency > 1. ie the symbol is found more than once in the app.
|
||||||
|
// PluralCount is only valid after method SortByFrequency.
|
||||||
|
property PluralSymbolCount: integer read FPluralSymbolCount;
|
||||||
|
|
||||||
|
|
||||||
|
procedure LoadFromFile(const AFileName: string);
|
||||||
|
procedure LoadFromStream(S: TStream);
|
||||||
|
function LoadSymbol(S: TStream): Cardinal;
|
||||||
|
procedure SaveToFile(const AFileName: string);
|
||||||
|
procedure SaveToStream(S: TStream; ACount: integer);
|
||||||
|
procedure SaveSymbol(S: TStream; ASymbolID: Cardinal);
|
||||||
|
|
||||||
|
procedure ClearFrequency;
|
||||||
|
procedure IncrementFrequency(ID: integer);
|
||||||
|
procedure SortByFrequency(var ANewIDs: array of Cardinal);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{utility functions}
|
||||||
|
|
||||||
|
// compare two bytes
|
||||||
|
function sdCompareByte(Byte1, Byte2: byte): integer;
|
||||||
|
|
||||||
|
// compare two integers
|
||||||
|
function sdCompareInteger(Int1, Int2: integer): integer;
|
||||||
|
|
||||||
|
// unicode UTF8 <> UTF16LE coversion functions
|
||||||
|
function sdUtf16ToUtf8Mem(Src: Pword; Dst: Pbyte; Count: integer): integer;
|
||||||
|
function sdUtf8ToUtf16Mem(var Src: Pbyte; Dst: Pword; Count: integer): integer;
|
||||||
|
|
||||||
|
// stream methods
|
||||||
|
function sdStreamReadCardinal(S: TStream): Cardinal;
|
||||||
|
function sdStreamReadString(S: TStream; ACharCount: Cardinal): Utf8String;
|
||||||
|
procedure sdStreamWriteCardinal(S: TStream; ACardinal: Cardinal);
|
||||||
|
procedure sdStreamWriteString(S: TStream; const AString: Utf8String);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
type
|
||||||
|
|
||||||
|
// A symbol item used in symbol lists (do not use directly)
|
||||||
|
TsdSymbol = class
|
||||||
|
private
|
||||||
|
FID: integer;
|
||||||
|
FFreq: Cardinal;
|
||||||
|
FSymbolStyle: Cardinal;
|
||||||
|
FFirst: Pbyte;
|
||||||
|
FCharCount: integer;
|
||||||
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
|
function AsString: Utf8String;
|
||||||
|
property SymbolStyle: Cardinal read FSymbolStyle;
|
||||||
|
property CharCount: integer read FCharCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// A list of symbols (do not use directly)
|
||||||
|
TsdSymbolList = class(TObjectList)
|
||||||
|
private
|
||||||
|
function GetItems(Index: integer): TsdSymbol;
|
||||||
|
protected
|
||||||
|
// Assumes list is sorted by refstring
|
||||||
|
function Find(ASymbol: TsdSymbol; var Index: integer): boolean;
|
||||||
|
public
|
||||||
|
property Items[Index: integer]: TsdSymbol read GetItems; default;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
// compare two symbols. This is NOT an alphabetic compare. symbols are first
|
||||||
|
// compared by length, then by first byte, then last byte then second, then
|
||||||
|
// N-1, until all bytes are compared.
|
||||||
|
function sdCompareSymbol(Symbol1, Symbol2: TsdSymbol): integer;
|
||||||
|
var
|
||||||
|
CharCount: integer;
|
||||||
|
First1, First2, Last1, Last2: Pbyte;
|
||||||
|
IsEqual: boolean;
|
||||||
|
begin
|
||||||
|
// Compare string length first
|
||||||
|
Result := sdCompareInteger(Symbol1.CharCount, Symbol2.CharCount);
|
||||||
|
if Result <> 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
// Compare FFirst
|
||||||
|
Result := sdCompareByte(Symbol1.FFirst^, Symbol2.FFirst^);
|
||||||
|
if Result <> 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
// CharCount of RS1 (and RS2, since they are equal)
|
||||||
|
CharCount := Symbol1.CharCount;
|
||||||
|
|
||||||
|
// Setup First & Last pointers
|
||||||
|
First1 := Symbol1.FFirst;
|
||||||
|
First2 := Symbol2.FFirst;
|
||||||
|
|
||||||
|
// compare memory (boolean op). CompareMem might have optimized code depending
|
||||||
|
// on memory manager (ASM, MMX, SSE etc) to binary compare the block.
|
||||||
|
// Since sdCompareRefString may be used to compare relatively large blocks of
|
||||||
|
// text, which are often exact copies, using CompareMem before special comparison
|
||||||
|
// is warrented.
|
||||||
|
IsEqual := CompareMem(First1, First2, CharCount);
|
||||||
|
if IsEqual then
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// finally the special conparison: Compare each time last ptrs then first ptrs,
|
||||||
|
// until they meet in the middle
|
||||||
|
Last1 := First1;
|
||||||
|
inc(Last1, CharCount);
|
||||||
|
Last2 := First2;
|
||||||
|
inc(Last2, CharCount);
|
||||||
|
|
||||||
|
repeat
|
||||||
|
|
||||||
|
dec(Last1);
|
||||||
|
dec(Last2);
|
||||||
|
if First1 = Last1 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
Result := sdCompareByte(Last1^, Last2^);
|
||||||
|
if Result <> 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
inc(First1);
|
||||||
|
inc(First2);
|
||||||
|
if First1 = Last1 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
Result := sdCompareByte(First1^, First2^);
|
||||||
|
if Result <> 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
until False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsdSymbol }
|
||||||
|
|
||||||
|
function TsdSymbol.AsString: Utf8String;
|
||||||
|
begin
|
||||||
|
SetString(Result, PAnsiChar(FFirst), FCharCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsdSymbol.Destroy;
|
||||||
|
begin
|
||||||
|
FreeMem(FFirst);
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsdSymbolList }
|
||||||
|
|
||||||
|
function TsdSymbolList.GetItems(Index: integer): TsdSymbol;
|
||||||
|
begin
|
||||||
|
Result := Get(Index);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdSymbolList.Find(ASymbol: TsdSymbol; var Index: integer): boolean;
|
||||||
|
var
|
||||||
|
AMin, AMax: integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
// Find position - binary method
|
||||||
|
AMin := 0;
|
||||||
|
AMax := Count;
|
||||||
|
while AMin < AMax do
|
||||||
|
begin
|
||||||
|
Index := (AMin + AMax) div 2;
|
||||||
|
case sdCompareSymbol(Items[Index], ASymbol) of
|
||||||
|
-1: AMin := Index + 1;
|
||||||
|
0: begin
|
||||||
|
Result := True;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
1: AMax := Index;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Index := AMin;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TsdSymbolTable }
|
||||||
|
|
||||||
|
function TsdSymbolTable.AddString(const S: Utf8String): integer;
|
||||||
|
var
|
||||||
|
Found: boolean;
|
||||||
|
L, BySymbolIndex: integer;
|
||||||
|
ASymbol, Item: TsdSymbol;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
L := length(S);
|
||||||
|
|
||||||
|
// zero-length string
|
||||||
|
if L = 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
ASymbol := TsdSymbol.Create;
|
||||||
|
try
|
||||||
|
ASymbol.FFirst := PByte(@S[1]);
|
||||||
|
ASymbol.FCharCount := L;
|
||||||
|
|
||||||
|
// Try to find the new string
|
||||||
|
Found := TsdSymbolList(FBySymbol).Find(ASymbol, BySymbolIndex);
|
||||||
|
if Found then
|
||||||
|
begin
|
||||||
|
// yes it is found
|
||||||
|
Item := TsdSymbol(FBySymbol[BySymbolIndex]);
|
||||||
|
Result := Item.FID;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Not found.. must make new item
|
||||||
|
Item := TsdSymbol.Create;
|
||||||
|
Item.FCharCount := ASymbol.FCharCount;
|
||||||
|
|
||||||
|
// reallocate memory and copy the string data
|
||||||
|
ReallocMem(Item.FFirst, Item.FCharCount);
|
||||||
|
Move(S[1], Item.FFirst^, Item.FCharCount);
|
||||||
|
|
||||||
|
// add to the ByID objectlist
|
||||||
|
FByID.Add(Item);
|
||||||
|
Item.FID := FByID.Count;
|
||||||
|
Result := Item.FID;
|
||||||
|
|
||||||
|
// insert into the ByRS list
|
||||||
|
FBySymbol.Insert(BySymbolIndex, Item);
|
||||||
|
|
||||||
|
finally
|
||||||
|
// this ensures we do not deallocate the memory that may be in use elsewhere
|
||||||
|
ASymbol.FFirst := nil;
|
||||||
|
ASymbol.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.Clear;
|
||||||
|
begin
|
||||||
|
FByID.Clear;
|
||||||
|
FBySymbol.Clear;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.ClearFrequency;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
for i := 0 to FByID.Count - 1 do
|
||||||
|
TsdSymbol(FByID[i]).FFreq := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TsdSymbolTable.Create(AOwner: TComponent);
|
||||||
|
begin
|
||||||
|
inherited Create(AOwner);
|
||||||
|
FByID := TObjectList.Create(True);
|
||||||
|
FBySymbol := TsdSymbolList.Create(False);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsdSymbolTable.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FBySymbol);
|
||||||
|
FreeAndNil(FByID);
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdSymbolTable.GetSymbolCount: integer;
|
||||||
|
begin
|
||||||
|
Result := FByID.Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdSymbolTable.GetString(ID: integer): Utf8String;
|
||||||
|
begin
|
||||||
|
// Find the ID
|
||||||
|
|
||||||
|
// zero string
|
||||||
|
if ID <= 0 then
|
||||||
|
begin
|
||||||
|
Result := '';
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// out of bounds?
|
||||||
|
if ID > FByID.Count then
|
||||||
|
begin
|
||||||
|
// output warning
|
||||||
|
DoDebugOut(Self, wsWarn, 'string ID not found');
|
||||||
|
Result := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := TsdSymbol(FByID[ID - 1]).AsString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.IncrementFrequency(ID: integer);
|
||||||
|
var
|
||||||
|
RS: TsdSymbol;
|
||||||
|
begin
|
||||||
|
RS := TsdSymbol(FByID[ID - 1]);
|
||||||
|
inc(RS.FFreq);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.LoadFromFile(const AFileName: string);
|
||||||
|
var
|
||||||
|
S: TMemoryStream;
|
||||||
|
begin
|
||||||
|
S := TMemoryStream.Create;
|
||||||
|
try
|
||||||
|
S.LoadFromFile(AFileName);
|
||||||
|
LoadFromStream(S);
|
||||||
|
finally
|
||||||
|
S.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.LoadFromStream(S: TStream);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
TableCount: Cardinal;
|
||||||
|
begin
|
||||||
|
Clear;
|
||||||
|
|
||||||
|
// DoDebugOut(Self, wsInfo, format('stream position: %d', [S.Position]));
|
||||||
|
|
||||||
|
// table count
|
||||||
|
TableCount := sdStreamReadCardinal(S);
|
||||||
|
if TableCount = 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
for i := 0 to TableCount - 1 do
|
||||||
|
begin
|
||||||
|
LoadSymbol(S);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TsdSymbolTable.LoadSymbol(S: TStream): Cardinal;
|
||||||
|
var
|
||||||
|
Symbol: TsdSymbol;
|
||||||
|
BySymbolIndex: integer;
|
||||||
|
Found: boolean;
|
||||||
|
begin
|
||||||
|
Symbol := TsdSymbol.Create;
|
||||||
|
|
||||||
|
// For now, we just use ssString uniquely as symbol style,.
|
||||||
|
// In updates, different symbol styles can be added.
|
||||||
|
Symbol.FSymbolStyle := sdStreamReadCardinal(S);
|
||||||
|
|
||||||
|
Symbol.FCharCount := sdStreamReadCardinal(S);
|
||||||
|
|
||||||
|
if Symbol.FCharCount > 0 then
|
||||||
|
begin
|
||||||
|
// reallocate memory and copy the string data
|
||||||
|
ReallocMem(Symbol.FFirst, Symbol.FCharCount);
|
||||||
|
S.Read(Symbol.FFirst^, Symbol.FCharCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// add to the ByID objectlist
|
||||||
|
FByID.Add(Symbol);
|
||||||
|
Symbol.FID := FByID.Count;
|
||||||
|
Result := Symbol.FID;
|
||||||
|
|
||||||
|
// find the symbol
|
||||||
|
Found := TsdSymbolList(FBySymbol).Find(Symbol, BySymbolIndex);
|
||||||
|
if Found then
|
||||||
|
begin
|
||||||
|
DoDebugOut(Self, wsFail, 'duplicate symbol!');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// insert into the ByRS list
|
||||||
|
FBySymbol.Insert(BySymbolIndex, Symbol);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.SaveToFile(const AFileName: string);
|
||||||
|
var
|
||||||
|
S: TMemoryStream;
|
||||||
|
begin
|
||||||
|
S := TMemoryStream.Create;
|
||||||
|
try
|
||||||
|
SaveToStream(S, SymbolCount);
|
||||||
|
S.SaveToFile(AFileName);
|
||||||
|
finally
|
||||||
|
S.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.SaveToStream(S: TStream; ACount: integer);
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
// write (part of the) symbol table
|
||||||
|
sdStreamWriteCardinal(S, ACount);
|
||||||
|
for i := 0 to ACount - 1 do
|
||||||
|
begin
|
||||||
|
SaveSymbol(S, i + 1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.SaveSymbol(S: TStream; ASymbolID: Cardinal);
|
||||||
|
var
|
||||||
|
RS: TsdSymbol;
|
||||||
|
StringVal: Utf8String;
|
||||||
|
CharCount: Cardinal;
|
||||||
|
begin
|
||||||
|
if ASymbolID <= 0 then
|
||||||
|
DoDebugOut(Self, wsFail, 'symbol ID <= 0');
|
||||||
|
RS := TsdSymbol(FByID[ASymbolID - 1]);
|
||||||
|
|
||||||
|
// For now, we just use ssString uniquely as symbol style.
|
||||||
|
// In updates, different symbol styles can be added.
|
||||||
|
sdStreamWriteCardinal(S, RS.SymbolStyle);
|
||||||
|
|
||||||
|
StringVal := RS.AsString;
|
||||||
|
CharCount := length(StringVal);
|
||||||
|
sdStreamWriteCardinal(S, CharCount);
|
||||||
|
sdStreamWriteString(S, StringVal);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsdSymbolTable.SortByFrequency(var ANewIDs: array of Cardinal);
|
||||||
|
// local
|
||||||
|
function CompareFreq(Pos1, Pos2: integer): integer;
|
||||||
|
var
|
||||||
|
RS1, RS2: TsdSymbol;
|
||||||
|
begin
|
||||||
|
RS1 := TsdSymbol(FByID[Pos1]);
|
||||||
|
RS2 := TsdSymbol(FByID[Pos2]);
|
||||||
|
if RS1.FFreq > RS2.FFreq then
|
||||||
|
Result := -1
|
||||||
|
else
|
||||||
|
if RS1.FFreq < RS2.FFreq then
|
||||||
|
Result := 1
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
// local
|
||||||
|
procedure QuickSort(iLo, iHi: Integer);
|
||||||
|
var
|
||||||
|
Lo, Hi, Mid: longint;
|
||||||
|
begin
|
||||||
|
Lo := iLo;
|
||||||
|
Hi := iHi;
|
||||||
|
Mid:= (Lo + Hi) div 2;
|
||||||
|
repeat
|
||||||
|
while CompareFreq(Lo, Mid) < 0 do
|
||||||
|
Inc(Lo);
|
||||||
|
while CompareFreq(Hi, Mid) > 0 do
|
||||||
|
Dec(Hi);
|
||||||
|
if Lo <= Hi then
|
||||||
|
begin
|
||||||
|
// Swap pointers;
|
||||||
|
FByID.Exchange(Lo, Hi);
|
||||||
|
if Mid = Lo then
|
||||||
|
Mid := Hi
|
||||||
|
else
|
||||||
|
if Mid = Hi then
|
||||||
|
Mid := Lo;
|
||||||
|
Inc(Lo);
|
||||||
|
Dec(Hi);
|
||||||
|
end;
|
||||||
|
until Lo > Hi;
|
||||||
|
|
||||||
|
if Hi > iLo then
|
||||||
|
QuickSort(iLo, Hi);
|
||||||
|
|
||||||
|
if Lo < iHi then
|
||||||
|
QuickSort(Lo, iHi);
|
||||||
|
end;
|
||||||
|
// main
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
// sort by frequency
|
||||||
|
QuickSort(0, FByID.Count - 1);
|
||||||
|
|
||||||
|
// plural count
|
||||||
|
FPluralSymbolCount := 0;
|
||||||
|
i := 0;
|
||||||
|
while i < FByID.Count do
|
||||||
|
begin
|
||||||
|
if TsdSymbol(FByID[i]).FFreq >= 2 then
|
||||||
|
inc(FPluralSymbolCount)
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// tell app about new ID
|
||||||
|
for i := 0 to FByID.Count - 1 do
|
||||||
|
begin
|
||||||
|
ANewIDs[TsdSymbol(FByID[i]).FID] := i + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// then rename IDs
|
||||||
|
for i := 0 to FByID.Count - 1 do
|
||||||
|
begin
|
||||||
|
TsdSymbol(FByID[i]).FID := i + 1;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{utility functions}
|
||||||
|
|
||||||
|
function sdCompareByte(Byte1, Byte2: byte): integer;
|
||||||
|
begin
|
||||||
|
if Byte1 < Byte2 then
|
||||||
|
Result := -1
|
||||||
|
else
|
||||||
|
if Byte1 > Byte2 then
|
||||||
|
Result := 1
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function sdCompareInteger(Int1, Int2: integer): integer;
|
||||||
|
begin
|
||||||
|
if Int1 < Int2 then
|
||||||
|
Result := -1
|
||||||
|
else
|
||||||
|
if Int1 > Int2 then
|
||||||
|
Result := 1
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function sdUtf16ToUtf8Mem(Src: Pword; Dst: Pbyte; Count: integer): integer;
|
||||||
|
// Convert an Unicode (UTF16 LE) memory block to UTF8. This routine will process
|
||||||
|
// Count wide characters (2 bytes size) to Count UTF8 characters (1-3 bytes).
|
||||||
|
// Therefore, the block at Dst must be at least 1.5 the size of the source block.
|
||||||
|
// The function returns the number of *bytes* written.
|
||||||
|
var
|
||||||
|
W: word;
|
||||||
|
DStart: Pbyte;
|
||||||
|
begin
|
||||||
|
DStart := Dst;
|
||||||
|
while Count > 0 do
|
||||||
|
begin
|
||||||
|
W := Src^;
|
||||||
|
inc(Src);
|
||||||
|
if W <= $7F then
|
||||||
|
begin
|
||||||
|
Dst^ := byte(W);
|
||||||
|
inc(Dst);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
if W > $7FF then
|
||||||
|
begin
|
||||||
|
Dst^ := byte($E0 or (W shr 12));
|
||||||
|
inc(Dst);
|
||||||
|
Dst^ := byte($80 or ((W shr 6) and $3F));
|
||||||
|
inc(Dst);
|
||||||
|
Dst^ := byte($80 or (W and $3F));
|
||||||
|
inc(Dst);
|
||||||
|
end else
|
||||||
|
begin // $7F < W <= $7FF
|
||||||
|
Dst^ := byte($C0 or (W shr 6));
|
||||||
|
inc(Dst);
|
||||||
|
Dst^ := byte($80 or (W and $3F));
|
||||||
|
inc(Dst);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
dec(Count);
|
||||||
|
end;
|
||||||
|
Result := integer(Dst) - integer(DStart);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function sdUtf8ToUtf16Mem(var Src: Pbyte; Dst: Pword; Count: integer): integer;
|
||||||
|
// Convert an UTF8 memory block to Unicode (UTF16 LE). This routine will process
|
||||||
|
// Count *bytes* of UTF8 (each character 1-3 bytes) into UTF16 (each char 2 bytes).
|
||||||
|
// Therefore, the block at Dst must be at least 2 times the size of Count, since
|
||||||
|
// many UTF8 characters consist of just one byte, and are mapped to 2 bytes. The
|
||||||
|
// function returns the number of *wide chars* written. Note that the Src block must
|
||||||
|
// have an exact number of UTF8 characters in it, if Count doesn't match then
|
||||||
|
// the last character will be converted anyway (going past the block boundary!)
|
||||||
|
var
|
||||||
|
W: word;
|
||||||
|
C: byte;
|
||||||
|
DStart: Pword;
|
||||||
|
SClose: Pbyte;
|
||||||
|
begin
|
||||||
|
DStart := Dst;
|
||||||
|
SClose := Src;
|
||||||
|
inc(SClose, Count);
|
||||||
|
while integer(Src) < integer(SClose) do
|
||||||
|
begin
|
||||||
|
// 1st byte
|
||||||
|
W := Src^;
|
||||||
|
inc(Src);
|
||||||
|
if W and $80 <> 0 then
|
||||||
|
begin
|
||||||
|
W := W and $3F;
|
||||||
|
if W and $20 <> 0 then
|
||||||
|
begin
|
||||||
|
// 2nd byte
|
||||||
|
C := Src^;
|
||||||
|
inc(Src);
|
||||||
|
if C and $C0 <> $80 then
|
||||||
|
// malformed trail byte or out of range char
|
||||||
|
Continue;
|
||||||
|
W := (W shl 6) or (C and $3F);
|
||||||
|
end;
|
||||||
|
// 2nd or 3rd byte
|
||||||
|
C := Src^;
|
||||||
|
inc(Src);
|
||||||
|
if C and $C0 <> $80 then
|
||||||
|
// malformed trail byte
|
||||||
|
Continue;
|
||||||
|
Dst^ := (W shl 6) or (C and $3F);
|
||||||
|
inc(Dst);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Dst^ := W;
|
||||||
|
inc(Dst);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result := (integer(Dst) - integer(DStart)) div 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ stream methods }
|
||||||
|
|
||||||
|
function sdStreamReadCardinal(S: TStream): Cardinal;
|
||||||
|
var
|
||||||
|
C: byte;
|
||||||
|
Bits: integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
Bits := 0;
|
||||||
|
repeat
|
||||||
|
S.Read(C, 1);
|
||||||
|
if C > 0 then
|
||||||
|
begin
|
||||||
|
inc(Result, (C and $7F) shl Bits);
|
||||||
|
inc(Bits, 7)
|
||||||
|
end;
|
||||||
|
until(C and $80) = 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function sdStreamReadString(S: TStream; ACharCount: Cardinal): Utf8String;
|
||||||
|
begin
|
||||||
|
SetLength(Result, ACharCount);
|
||||||
|
if ACharCount = 0 then
|
||||||
|
exit;
|
||||||
|
S.Read(Result[1], ACharCount);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure sdStreamWriteCardinal(S: TStream; ACardinal: Cardinal);
|
||||||
|
var
|
||||||
|
C: byte;
|
||||||
|
begin
|
||||||
|
repeat
|
||||||
|
if ACardinal <= $7F then
|
||||||
|
begin
|
||||||
|
C := ACardinal;
|
||||||
|
S.Write(C, 1);
|
||||||
|
exit;
|
||||||
|
end else
|
||||||
|
C := (ACardinal and $7F) or $80;
|
||||||
|
S.Write(C, 1);
|
||||||
|
ACardinal := ACardinal shr 7;
|
||||||
|
until ACardinal = 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure sdStreamWriteString(S: TStream; const AString: Utf8String);
|
||||||
|
var
|
||||||
|
L: integer;
|
||||||
|
begin
|
||||||
|
L := Length(AString);
|
||||||
|
if L > 0 then
|
||||||
|
begin
|
||||||
|
S.Write(AString[1], L);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
95
units/simdesign.inc
Normal file
95
units/simdesign.inc
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{ simdesign.inc
|
||||||
|
|
||||||
|
include file for many simdesign projects
|
||||||
|
default path: \simlib\general
|
||||||
|
|
||||||
|
Author: Nils Haeck M.Sc.
|
||||||
|
Copyright (c) 2007 - 2011 Simdesign B.V.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// unicode avoid implicit string cast warning
|
||||||
|
{$ifdef UNICODE}
|
||||||
|
{$WARN IMPLICIT_STRING_CAST OFF}
|
||||||
|
{$endif UNICODE}
|
||||||
|
|
||||||
|
// Delphi and FPC versions
|
||||||
|
|
||||||
|
// Freepascal
|
||||||
|
{$ifdef FPC}
|
||||||
|
{$MODE DELPHI}
|
||||||
|
{$define D7UP}
|
||||||
|
{$endif FPC}
|
||||||
|
|
||||||
|
// Delphi 5
|
||||||
|
{$ifdef VER130}
|
||||||
|
{$define D5UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
//Delphi 6
|
||||||
|
{$ifdef VER140}
|
||||||
|
{$define D5UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
//Delphi 7
|
||||||
|
{$ifdef VER150}
|
||||||
|
{$define D7UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
//Delphi 8
|
||||||
|
{$ifdef VER160}
|
||||||
|
{$define D7UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi 2005 / 9
|
||||||
|
{$ifdef VER170}
|
||||||
|
{$define D7UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi 2006 / 10
|
||||||
|
{$ifdef VER180}
|
||||||
|
{$define D7UP}
|
||||||
|
// D10 publishes OnMouseEnter / OnMouseLeave
|
||||||
|
{$define D10UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi 2007 Rad studio / 11?
|
||||||
|
{$ifdef VER185}
|
||||||
|
{$define D7UP}
|
||||||
|
{$define D10UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi 2007 - NET / 11?
|
||||||
|
{$ifdef VER190}
|
||||||
|
{$define D7UP}
|
||||||
|
{$define D10UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi 2009 / 12
|
||||||
|
// first UNICODE version, so then directive UNICODE is defined, no need for directive D12UP
|
||||||
|
{$ifdef VER200}
|
||||||
|
{$define D7UP}
|
||||||
|
{$define D10UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi 2010 / 14?
|
||||||
|
{$ifdef VER210}
|
||||||
|
{$define D7UP}
|
||||||
|
{$define D10UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi XE / 15
|
||||||
|
{$ifdef VER220}
|
||||||
|
{$define D7UP}
|
||||||
|
{$define D10UP}
|
||||||
|
{$define D15UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
// Delphi XE2 / 16
|
||||||
|
{$ifdef VER230}
|
||||||
|
{$define D7UP}
|
||||||
|
{$define D10UP}
|
||||||
|
{$define D15UP}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
|
||||||
73
units/uBrowseForFolder.pas
Normal file
73
units/uBrowseForFolder.pas
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
unit uBrowseForFolder;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
function BrowseForFolder(const appHWND: THandle; const browseTitle: String;
|
||||||
|
const initialFolder: String = ''): String;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows, shlobj;
|
||||||
|
|
||||||
|
var
|
||||||
|
lg_StartFolder: String;
|
||||||
|
|
||||||
|
/// /////////////////////////////////////////////////////////////////////
|
||||||
|
// Call back function used to set the initial browse directory.
|
||||||
|
/// /////////////////////////////////////////////////////////////////////
|
||||||
|
function BrowseForFolderCallBack(Wnd: HWND; uMsg: UINT; lParam, lpData: lParam)
|
||||||
|
: Integer stdcall;
|
||||||
|
begin
|
||||||
|
if uMsg = BFFM_INITIALIZED then
|
||||||
|
SendMessage(Wnd, BFFM_SETSELECTION, 1, Integer(@lg_StartFolder[1]));
|
||||||
|
result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
/// /////////////////////////////////////////////////////////////////////
|
||||||
|
// This function allows the user to browse for a folder
|
||||||
|
//
|
||||||
|
// Arguments:-
|
||||||
|
// browseTitle : The title to display on the browse dialog.
|
||||||
|
// initialFolder : Optional argument. Use to specify the folder
|
||||||
|
// initially selected when the dialog opens.
|
||||||
|
// mayCreateNewFolder : Flag indicating whether the user can create a
|
||||||
|
// new folder.
|
||||||
|
//
|
||||||
|
// Returns: The empty string if no folder was selected (i.e. if the user
|
||||||
|
// clicked cancel), otherwise the full folder path.
|
||||||
|
/// /////////////////////////////////////////////////////////////////////
|
||||||
|
function BrowseForFolder(const appHWND: THandle; const browseTitle: String;
|
||||||
|
const initialFolder: String = ''): String;
|
||||||
|
var
|
||||||
|
browse_info: TBrowseInfo;
|
||||||
|
folder: array [0 .. MAX_PATH] of char;
|
||||||
|
find_context: PItemIDList;
|
||||||
|
begin
|
||||||
|
// --------------------------
|
||||||
|
// Initialise the structure.
|
||||||
|
// --------------------------
|
||||||
|
FillChar(browse_info, SizeOf(browse_info), #0);
|
||||||
|
lg_StartFolder := initialFolder;
|
||||||
|
browse_info.pszDisplayName := @folder[0];
|
||||||
|
browse_info.lpszTitle := PChar(browseTitle);
|
||||||
|
browse_info.ulFlags := BIF_DONTGOBELOWDOMAIN or BIF_RETURNONLYFSDIRS or
|
||||||
|
BIF_STATUSTEXT or BIF_VALIDATE or BIF_USENEWUI or BIF_NONEWFOLDERBUTTON;
|
||||||
|
|
||||||
|
browse_info.hwndOwner := appHWND;
|
||||||
|
if initialFolder <> '' then
|
||||||
|
browse_info.lpfn := BrowseForFolderCallBack;
|
||||||
|
find_context := SHBrowseForFolder(browse_info);
|
||||||
|
if Assigned(find_context) then
|
||||||
|
begin
|
||||||
|
if SHGetPathFromIDList(find_context, folder) then
|
||||||
|
result := folder
|
||||||
|
else
|
||||||
|
result := '';
|
||||||
|
GlobalFreePtr(find_context);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
result := '';
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
227
units/uCDIMAGE.pas
Normal file
227
units/uCDIMAGE.pas
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
unit uCDIMAGE;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows, uTIM;
|
||||||
|
|
||||||
|
const
|
||||||
|
cSectorHeaderSize = 12;
|
||||||
|
cSectorAddressSize = 3;
|
||||||
|
cSectorModeSize = 1;
|
||||||
|
cSectorSubHeaderSize = 8;
|
||||||
|
cSectorInfoSize = cSectorHeaderSize + cSectorAddressSize + cSectorModeSize +
|
||||||
|
cSectorSubHeaderSize;
|
||||||
|
cSectorDataSize = 2048;
|
||||||
|
cSectorECCSize = 4;
|
||||||
|
cSectorEDCSize = 276;
|
||||||
|
cSectorECCEDCSize = cSectorECCSize + cSectorEDCSize;
|
||||||
|
cSectorSize = cSectorInfoSize + cSectorDataSize + cSectorECCEDCSize;
|
||||||
|
|
||||||
|
type
|
||||||
|
TCDSector = packed record
|
||||||
|
dwHeader: array [0 .. cSectorHeaderSize - 1] of byte;
|
||||||
|
dwAddress: array [0 .. cSectorAddressSize - 1] of byte;
|
||||||
|
bMode: byte;
|
||||||
|
dwSubHeader: array [0 .. cSectorSubHeaderSize - 1] of byte;
|
||||||
|
dwData: array [0 .. cSectorDataSize - 1] of byte;
|
||||||
|
dwECC: array [0 .. cSectorECCSize - 1] of byte;
|
||||||
|
dwEDC: array [0 .. cSectorEDCSize - 1] of byte;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PCDSector = ^TCDSector;
|
||||||
|
|
||||||
|
function GetImageScan(const FileName: string): Boolean;
|
||||||
|
function ReplaceTimInFile(const FileName, TimToInsert: string; InsertTo: DWORD;
|
||||||
|
ImageScan: Boolean): Boolean;
|
||||||
|
procedure ReplaceTimInFileFromMemory(const FileName: string; TIM: PTIM;
|
||||||
|
InsertTo: DWORD; ImageScan: Boolean);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
uCommon, ecc, edc, System.SysUtils, System.Classes;
|
||||||
|
|
||||||
|
function bin2bcd(P: Integer): byte;
|
||||||
|
begin
|
||||||
|
Result := ((P div 10) shl 4) or (P mod 10);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure BuildAdress(LBA: Integer; var Dest);
|
||||||
|
var
|
||||||
|
P: PByte;
|
||||||
|
begin
|
||||||
|
Inc(LBA, 75 * 2); // 2 seconds
|
||||||
|
P := @Dest;
|
||||||
|
P^ := bin2bcd(LBA div (60 * 75));
|
||||||
|
Inc(P);
|
||||||
|
P^ := bin2bcd((LBA div 75) mod 60);
|
||||||
|
Inc(P);
|
||||||
|
P^ := bin2bcd(LBA mod 75);
|
||||||
|
Inc(P);
|
||||||
|
P^ := 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetImageScan(const FileName: string): Boolean;
|
||||||
|
const
|
||||||
|
cSectorHeader: array [0 .. cSectorHeaderSize - 1] of byte = ($00, $FF, $FF,
|
||||||
|
$FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF, $00);
|
||||||
|
var
|
||||||
|
Sz: cardinal;
|
||||||
|
pFile: PBytesArray;
|
||||||
|
tmp: TFileStream;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
Sz := GetFileSizeAPI(FileName);
|
||||||
|
|
||||||
|
if (Sz > cMaxFileSize) or (Sz = 0) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
pFile := GetMemory(cSectorHeaderSize);
|
||||||
|
tmp := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
|
||||||
|
tmp.Read(pFile^[0], cSectorHeaderSize);
|
||||||
|
Result := ((Sz mod cSectorSize) = 0) and
|
||||||
|
(CompareMem(@cSectorHeader, pFile, cSectorHeaderSize));
|
||||||
|
tmp.free;
|
||||||
|
FreeMemory(pFile);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ReplaceTimInFileFromMemory(const FileName: string; TIM: PTIM;
|
||||||
|
InsertTo: DWORD; ImageScan: Boolean);
|
||||||
|
type
|
||||||
|
TSecAddrAndMode = array [0 .. cSectorAddressSize + cSectorModeSize - 1] of byte;
|
||||||
|
var
|
||||||
|
sImageStream: TFileStream;
|
||||||
|
TimOffsetInSector, FirstPartSize, LastPartSize: DWORD;
|
||||||
|
TimSectorNumber, TimStartSectorPos: DWORD;
|
||||||
|
Sector: TCDSector;
|
||||||
|
ecc: DWORD;
|
||||||
|
P, TIM_FULL_SECTORS: DWORD;
|
||||||
|
SecAddrAndMode: TSecAddrAndMode;
|
||||||
|
begin
|
||||||
|
sImageStream := TFileStream.Create(FileName, fmOpenReadWrite or
|
||||||
|
fmShareDenyWrite);
|
||||||
|
|
||||||
|
if not ImageScan then
|
||||||
|
begin
|
||||||
|
sImageStream.Seek(InsertTo, soBeginning);
|
||||||
|
sImageStream.Write(TIM^.DATA^[0], TIM^.dwSIZE);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
P := 0;
|
||||||
|
|
||||||
|
TimSectorNumber := InsertTo div cSectorSize + 1;
|
||||||
|
TimOffsetInSector := InsertTo mod cSectorSize - cSectorInfoSize;
|
||||||
|
TimStartSectorPos := (TimSectorNumber - 1) * cSectorSize;
|
||||||
|
FirstPartSize := cSectorDataSize - TimOffsetInSector;
|
||||||
|
|
||||||
|
if TIM^.dwSIZE < FirstPartSize then
|
||||||
|
FirstPartSize := TIM^.dwSIZE;
|
||||||
|
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
FillChar(Sector, cSectorSize, 0);
|
||||||
|
|
||||||
|
sImageStream.Read(Sector, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos + cSectorHeaderSize, soBeginning);
|
||||||
|
|
||||||
|
Move(Sector.dwAddress[0], SecAddrAndMode[0], cSectorAddressSize + cSectorModeSize);
|
||||||
|
FillChar(Sector.dwAddress[0], cSectorAddressSize + cSectorModeSize, 0);
|
||||||
|
|
||||||
|
Move(TIM^.DATA^[P], Sector.dwData[TimOffsetInSector], FirstPartSize);
|
||||||
|
Inc(P, FirstPartSize);
|
||||||
|
|
||||||
|
ecc := build_edc(@(Sector.dwSubHeader[0]), cSectorSubHeaderSize + cSectorDataSize);
|
||||||
|
Move(ecc, Sector.dwECC, cSectorECCSize);
|
||||||
|
encode_L2_P(@(Sector.dwAddress[0]));
|
||||||
|
encode_L2_Q(@(Sector.dwAddress[0]));
|
||||||
|
BuildAdress(TimSectorNumber, Sector.dwAddress[0]);
|
||||||
|
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
sImageStream.Write(Sector, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos + cSectorHeaderSize, soBeginning);
|
||||||
|
sImageStream.Write(SecAddrAndMode[0], cSectorAddressSize + cSectorModeSize);
|
||||||
|
|
||||||
|
Inc(TimStartSectorPos, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
|
||||||
|
TIM_FULL_SECTORS := (TIM^.dwSIZE - P) div cSectorDataSize;
|
||||||
|
|
||||||
|
while TIM_FULL_SECTORS > 0 do
|
||||||
|
begin
|
||||||
|
Inc(TimSectorNumber);
|
||||||
|
|
||||||
|
sImageStream.Read(Sector, cSectorSize);
|
||||||
|
Move(Sector.dwAddress[0], SecAddrAndMode[0], cSectorAddressSize + cSectorModeSize);
|
||||||
|
FillChar(Sector.dwAddress[0], cSectorAddressSize + cSectorModeSize, 0);
|
||||||
|
|
||||||
|
Move(TIM^.DATA^[P], Sector.dwData[0], cSectorDataSize);
|
||||||
|
Inc(P, cSectorDataSize);
|
||||||
|
|
||||||
|
ecc := build_edc(@(Sector.dwSubHeader[0]), cSectorSubHeaderSize + cSectorDataSize);
|
||||||
|
Move(ecc, Sector.dwECC, cSectorECCSize);
|
||||||
|
encode_L2_P(@(Sector.dwAddress[0]));
|
||||||
|
encode_L2_Q(@(Sector.dwAddress[0]));
|
||||||
|
BuildAdress(TimSectorNumber, Sector.dwAddress[0]);
|
||||||
|
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
sImageStream.Write(Sector, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos + cSectorHeaderSize, soBeginning);
|
||||||
|
sImageStream.Write(SecAddrAndMode[0], cSectorAddressSize + cSectorModeSize);
|
||||||
|
|
||||||
|
Inc(TimStartSectorPos, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
|
||||||
|
Dec(TIM_FULL_SECTORS);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Inc(TimSectorNumber);
|
||||||
|
|
||||||
|
sImageStream.Read(Sector, cSectorSize);
|
||||||
|
Move(Sector.dwAddress[0], SecAddrAndMode[0], cSectorAddressSize + cSectorModeSize);
|
||||||
|
FillChar(Sector.dwAddress[0], cSectorAddressSize + cSectorModeSize, 0);
|
||||||
|
|
||||||
|
if TIM^.dwSIZE > P then
|
||||||
|
begin
|
||||||
|
LastPartSize := TIM^.dwSIZE - P;
|
||||||
|
Move(TIM^.DATA^[P], Sector.dwData[0], LastPartSize);
|
||||||
|
|
||||||
|
ecc := build_edc(@(Sector.dwSubHeader[0]), cSectorSubHeaderSize + cSectorDataSize);
|
||||||
|
Move(ecc, Sector.dwECC, cSectorECCSize);
|
||||||
|
encode_L2_P(@(Sector.dwAddress[0]));
|
||||||
|
encode_L2_Q(@(Sector.dwAddress[0]));
|
||||||
|
BuildAdress(TimSectorNumber, Sector.dwAddress[0]);
|
||||||
|
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
sImageStream.Write(Sector, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos + cSectorHeaderSize, soBeginning);
|
||||||
|
sImageStream.Write(SecAddrAndMode[0], cSectorAddressSize + cSectorModeSize);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
sImageStream.free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ReplaceTimInFile(const FileName, TimToInsert: string; InsertTo: DWORD;
|
||||||
|
ImageScan: Boolean): Boolean;
|
||||||
|
|
||||||
|
var
|
||||||
|
SIZE, P: DWORD;
|
||||||
|
TIM: PTIM;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
SIZE := GetFileSizeAPI(TimToInsert);
|
||||||
|
P := 0;
|
||||||
|
TIM := LoadTimFromFile(TimToInsert, P, False, SIZE);
|
||||||
|
// SaveTimToFile('test.tim', TIM);
|
||||||
|
if TIM = nil then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
ReplaceTimInFileFromMemory(FileName, TIM, InsertTo, ImageScan);
|
||||||
|
|
||||||
|
FreeTIM(TIM);
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
154
units/uCommon.pas
Normal file
154
units/uCommon.pas
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
unit uCommon;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
NativeXML, Windows;
|
||||||
|
|
||||||
|
const
|
||||||
|
cProgramName = 'Tim2View by [Lab 313]';
|
||||||
|
cProgramVersion = '2.0';
|
||||||
|
cMaxFileSize = $2EAEED80;
|
||||||
|
cExtractedTimsDir = 'TIMS';
|
||||||
|
cResRootName = 'TVSCANRESULT';
|
||||||
|
cResInfoNode = 'INFO';
|
||||||
|
cResAttrFile = 'FILENAME';
|
||||||
|
cResAttrVersion = 'VERSION';
|
||||||
|
cResAttrImageFile = 'CDIMAGE';
|
||||||
|
cResAttrTimsCount = 'TIMSCOUNT';
|
||||||
|
cResTimsNode = 'TIMS';
|
||||||
|
cResTimNode = 'TIM';
|
||||||
|
cResTimAttrPos = 'POSITION';
|
||||||
|
cResTimAttrSize = 'SIZE';
|
||||||
|
cResTimAttrWidth = 'WIDTH';
|
||||||
|
cResTimAttrHeight = 'HEIGHT';
|
||||||
|
cResTimAttrBitMode = 'BITMODE';
|
||||||
|
cResTimAttrGood = 'GOODTIM';
|
||||||
|
cAutoExtractionTimFormat = '%s_%.6d_%.2db' + '.tim';
|
||||||
|
cCLUTGridColsCount = 32;
|
||||||
|
|
||||||
|
sStatusBarScanningFile = 'Scanning File...';
|
||||||
|
sStatusBarTimsExtracting = 'TIM''s Extracting...';
|
||||||
|
sStatusBarParsingResult = 'Parsing Result...';
|
||||||
|
sScanResultGood = 'Scan completed!';
|
||||||
|
sSelectDirCaption = 'Please, select directory for scan...';
|
||||||
|
sThisTimHasNoCLUT = 'This TIM has no CLUT';
|
||||||
|
|
||||||
|
type
|
||||||
|
PNativeXML = ^TNativeXML;
|
||||||
|
|
||||||
|
type
|
||||||
|
TBytesArray = array [0 .. cMaxFileSize - 1] of byte;
|
||||||
|
PBytesArray = ^TBytesArray;
|
||||||
|
|
||||||
|
function GetStartDir: string;
|
||||||
|
function GetFileSizeAPI(const FileName: string): Int64;
|
||||||
|
function CheckFileExists(const FileName: string): boolean;
|
||||||
|
// function cHex2Int( const Value : string) : Integer;
|
||||||
|
function ExtractFileNameWOext(const Path: string): string;
|
||||||
|
procedure Text2Clipboard(const S: string);
|
||||||
|
function Min(A, B: Integer): Integer;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
uCDIMAGE, System.SysUtils, System.Classes, Clipbrd;
|
||||||
|
|
||||||
|
function Min(A, B: Integer): Integer;
|
||||||
|
begin
|
||||||
|
if A < B then
|
||||||
|
Result := A
|
||||||
|
else
|
||||||
|
Result := B;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure Text2Clipboard(const S: string);
|
||||||
|
begin
|
||||||
|
Clipboard.AsText := S;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ExtractFileNameWOext(const Path: string): string;
|
||||||
|
begin
|
||||||
|
Result := ExtractFileName(Path);
|
||||||
|
Result := Copy(Result, 1, Length(Result) - Length(ExtractFileExt(Result)));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function Hex2Int(const Value: string): Integer;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
I := 1;
|
||||||
|
if Value = '' then
|
||||||
|
Exit; { >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> }
|
||||||
|
if Value[1] = '$' then
|
||||||
|
Inc(I);
|
||||||
|
while I <= Length(Value) do
|
||||||
|
begin
|
||||||
|
if (Value[I] >= '0') and (Value[I] <= '9') then
|
||||||
|
Result := (Result shl 4) or (Ord(Value[I]) - Ord('0'))
|
||||||
|
else if (Value[I] >= 'A') and (Value[I] <= 'F') then
|
||||||
|
Result := (Result shl 4) or (Ord(Value[I]) - Ord('A') + 10)
|
||||||
|
else if (Value[I] >= 'a') and (Value[I] <= 'f') then
|
||||||
|
Result := (Result shl 4) or (Ord(Value[I]) - Ord('a') + 10)
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
Inc(I);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CopyEnd(const S: string; Idx: Integer): string;
|
||||||
|
begin
|
||||||
|
Result := Copy(S, Idx, MaxInt);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function cHex2Int(const Value: string): Integer;
|
||||||
|
begin
|
||||||
|
if (Length(Value) > 2) and (Value[1] = '0') and
|
||||||
|
((Value[2] = 'x') or (Value[2] = 'X')) then
|
||||||
|
Result := Hex2Int(CopyEnd(Value, 3))
|
||||||
|
else
|
||||||
|
Result := Hex2Int(Value);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckFileExists(const FileName: string): boolean;
|
||||||
|
begin
|
||||||
|
Result := FileExists(FileName);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetFileSizeAPI(const FileName: string): Int64;
|
||||||
|
var
|
||||||
|
FindData: TWin32FindData;
|
||||||
|
hFind: THandle;
|
||||||
|
begin
|
||||||
|
Result := -1;
|
||||||
|
hFind := FindFirstFile(PChar(FileName), FindData);
|
||||||
|
|
||||||
|
if hFind <> INVALID_HANDLE_VALUE then
|
||||||
|
begin
|
||||||
|
|
||||||
|
Windows.FindClose(hFind);
|
||||||
|
if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
|
||||||
|
Result := FindData.nFileSizeLow;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetStartDir: string;
|
||||||
|
const
|
||||||
|
MAX_PATH = 260;
|
||||||
|
var
|
||||||
|
Buffer: array [0 .. MAX_PATH] of Char;
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
I := GetModuleFileName(0, Buffer, MAX_PATH);
|
||||||
|
for I := I downto 0 do
|
||||||
|
if Buffer[I] = '\' then
|
||||||
|
begin
|
||||||
|
Buffer[I + 1] := #0;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
Result := Buffer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
307
units/uDrawTIM.pas
Normal file
307
units/uDrawTIM.pas
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
unit uDrawTIM;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Vcl.Graphics, uTIM, System.Types, Vcl.Imaging.pngimage, Vcl.Grids;
|
||||||
|
|
||||||
|
type
|
||||||
|
PCanvas = ^TCanvas;
|
||||||
|
PPNGImage = ^TPngImage;
|
||||||
|
PDrawGrid = ^TDrawGrid;
|
||||||
|
|
||||||
|
procedure DrawTIM(TIM: PTIM; CLUT_NUM: Integer; ACanvas: PCanvas; Rect: TRect;
|
||||||
|
var PNG: PPNGImage; TranspMode: Byte);
|
||||||
|
procedure TimToPNG(TIM: PTIM; CLUT_NUM: Integer; var PNG: PPNGImage;
|
||||||
|
TranspMode: Byte);
|
||||||
|
procedure DrawPNG(PNG: PPNGImage; ACanvas: PCanvas; Rect: TRect);
|
||||||
|
procedure DrawClutCell(TIM: PTIM; CLUT_NUM: Integer; Grid: PDrawGrid;
|
||||||
|
X, Y: Integer);
|
||||||
|
procedure DrawCLUT(TIM: PTIM; CLUT_NUM: Integer; Grid: PDrawGrid);
|
||||||
|
procedure ClearCanvas(CHandle: THandle; Rect: TRect);
|
||||||
|
procedure ClearGrid(Grid: PDrawGrid);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows, uCommon;
|
||||||
|
|
||||||
|
function PrepareCLUT(TIM: PTIM; CLUT_NUM: Integer): PCLUT_COLORS;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
if (not TIMHasCLUT(TIM)) and (not(TIM^.HEAD^.bBPP in [cTIM4NC, cTIM8NC])) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
New(Result);
|
||||||
|
|
||||||
|
if (TIM^.HEAD^.bBPP in [cTIM4NC, cTIM8NC]) then
|
||||||
|
begin
|
||||||
|
Randomize;
|
||||||
|
for I := 1 to cRandomPaletteSize do
|
||||||
|
Result^[I - 1] := GetCLUTColor(TIM, CLUT_NUM, I - 1);
|
||||||
|
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
for I := 1 to GetTimColorsCount(TIM) do
|
||||||
|
Result^[I - 1] := GetCLUTColor(TIM, CLUT_NUM, I - 1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function PrepareIMAGE(TIM: PTIM): PIMAGE_INDEXES;
|
||||||
|
var
|
||||||
|
I, OFFSET: Integer;
|
||||||
|
RW: Word;
|
||||||
|
P24: DWORD;
|
||||||
|
begin
|
||||||
|
New(Result);
|
||||||
|
OFFSET := cTIMHeadSize + GetTIMCLUTSize(TIM) + cIMAGEHeadSize;
|
||||||
|
RW := GetTimRealWidth(TIM);
|
||||||
|
|
||||||
|
case TIM^.HEAD^.bBPP of
|
||||||
|
cTIM4C, cTIM4NC:
|
||||||
|
for I := 1 to TIM^.IMAGE^.wWidth * TIM^.IMAGE^.wHeight * 2 do
|
||||||
|
begin
|
||||||
|
Result^[(I - 1) * 2] := TIM^.DATA^[OFFSET + I - 1] and $F;
|
||||||
|
Result^[(I - 1) * 2 + 1] := (TIM^.DATA^[OFFSET + I - 1] and $F0) shr 4;
|
||||||
|
end;
|
||||||
|
|
||||||
|
cTIM8C, cTIM8NC:
|
||||||
|
for I := 1 to TIM^.IMAGE^.wWidth * TIM^.IMAGE^.wHeight * 2 do
|
||||||
|
Result^[I - 1] := TIM^.DATA^[OFFSET + I - 1];
|
||||||
|
|
||||||
|
cTIM16C, cTIM16NC:
|
||||||
|
for I := 1 to TIM^.IMAGE^.wWidth * TIM^.IMAGE^.wHeight do
|
||||||
|
Move(TIM^.DATA^[OFFSET + (I - 1) * 2], Result^[I - 1], 2);
|
||||||
|
|
||||||
|
cTIM24C, cTIM24NC:
|
||||||
|
begin
|
||||||
|
I := 1;
|
||||||
|
P24 := 0;
|
||||||
|
|
||||||
|
while I <= (TIM^.IMAGE^.wWidth * TIM^.IMAGE^.wHeight * 2) do
|
||||||
|
begin
|
||||||
|
Result^[P24] := 0;
|
||||||
|
Move(TIM^.DATA^[OFFSET + (I - 1)], Result^[P24], 3);
|
||||||
|
Inc(I, 3);
|
||||||
|
|
||||||
|
if Odd(RW) and (((P24 + 1) mod RW) = 0) then
|
||||||
|
Inc(OFFSET);
|
||||||
|
|
||||||
|
Inc(P24);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TimToPNG(TIM: PTIM; CLUT_NUM: Integer; var PNG: PPNGImage;
|
||||||
|
TranspMode: Byte);
|
||||||
|
var
|
||||||
|
RW, RH, CW: Word;
|
||||||
|
CLUT_DATA: PCLUT_COLORS;
|
||||||
|
IMAGE_DATA: PIMAGE_INDEXES;
|
||||||
|
X, Y, INDEX, IMAGE_DATA_POS: Integer;
|
||||||
|
R, G, B, STP, ALPHA: Byte;
|
||||||
|
COLOR: TCLUT_COLOR;
|
||||||
|
CL: DWORD;
|
||||||
|
Transparent, SemiTransparent: boolean;
|
||||||
|
begin
|
||||||
|
RW := GetTimRealWidth(TIM);
|
||||||
|
RH := GetTimHeight(TIM);
|
||||||
|
|
||||||
|
PNG^ := TPngImage.CreateBlank(COLOR_RGBALPHA, 16, RW, RH);
|
||||||
|
PNG^.CompressionLevel := 9;
|
||||||
|
PNG^.Filters := [];
|
||||||
|
|
||||||
|
CLUT_DATA := PrepareCLUT(TIM, CLUT_NUM);
|
||||||
|
IMAGE_DATA := PrepareIMAGE(TIM);
|
||||||
|
|
||||||
|
IMAGE_DATA_POS := 0;
|
||||||
|
|
||||||
|
R := 0;
|
||||||
|
G := 0;
|
||||||
|
B := 0;
|
||||||
|
STP := 0;
|
||||||
|
|
||||||
|
Transparent := TranspMode in [0, 1];
|
||||||
|
SemiTransparent := TranspMode in [0, 2];
|
||||||
|
|
||||||
|
for Y := 1 to RH do
|
||||||
|
for X := 1 to RW do
|
||||||
|
begin
|
||||||
|
case TIM^.HEAD^.bBPP of
|
||||||
|
cTIM4C, cTIM4NC, cTIM8C, cTIM8NC:
|
||||||
|
begin
|
||||||
|
INDEX := IMAGE_DATA^[IMAGE_DATA_POS];
|
||||||
|
|
||||||
|
R := CLUT_DATA^[INDEX].R;
|
||||||
|
G := CLUT_DATA^[INDEX].G;
|
||||||
|
B := CLUT_DATA^[INDEX].B;
|
||||||
|
STP := CLUT_DATA^[INDEX].STP;
|
||||||
|
end;
|
||||||
|
cTIM16C, cTIM16NC, cTIMMix:
|
||||||
|
begin
|
||||||
|
Move(IMAGE_DATA^[IMAGE_DATA_POS], CW, 2);
|
||||||
|
COLOR := ConvertTIMColor(CW);
|
||||||
|
|
||||||
|
R := COLOR.R;
|
||||||
|
G := COLOR.G;
|
||||||
|
B := COLOR.B;
|
||||||
|
STP := COLOR.STP;
|
||||||
|
end;
|
||||||
|
cTIM24C, cTIM24NC:
|
||||||
|
begin
|
||||||
|
CL := IMAGE_DATA^[IMAGE_DATA_POS];
|
||||||
|
|
||||||
|
R := (CL and $FF);
|
||||||
|
G := ((CL and $FF00) shr 8);
|
||||||
|
B := ((CL and $FF0000) shr 16);
|
||||||
|
STP := 0;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
Break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (TIM^.HEAD^.bBPP in cTIM24) or (not(Transparent or SemiTransparent))
|
||||||
|
then
|
||||||
|
ALPHA := 255
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (R + G + B) = 0 then
|
||||||
|
ALPHA := 0
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if (STP = 0) then
|
||||||
|
ALPHA := 255
|
||||||
|
else
|
||||||
|
ALPHA := 128;
|
||||||
|
|
||||||
|
if (not SemiTransparent) and (ALPHA = 128) then
|
||||||
|
ALPHA := 255;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PNG^.AlphaScanline[Y - 1]^[X - 1] := ALPHA;
|
||||||
|
|
||||||
|
if ALPHA = 0 then
|
||||||
|
begin
|
||||||
|
B := 0;
|
||||||
|
G := 0;
|
||||||
|
R := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
pRGBLine(PNG^.Scanline[Y - 1])^[X - 1].rgbtBlue := B;
|
||||||
|
pRGBLine(PNG^.Scanline[Y - 1])^[X - 1].rgbtGreen := G;
|
||||||
|
pRGBLine(PNG^.Scanline[Y - 1])^[X - 1].rgbtRed := R;
|
||||||
|
|
||||||
|
Inc(IMAGE_DATA_POS);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Dispose(CLUT_DATA);
|
||||||
|
Dispose(IMAGE_DATA);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawTIM(TIM: PTIM; CLUT_NUM: Integer; ACanvas: PCanvas; Rect: TRect;
|
||||||
|
var PNG: PPNGImage; TranspMode: Byte);
|
||||||
|
begin
|
||||||
|
TimToPNG(TIM, CLUT_NUM, PNG, TranspMode);
|
||||||
|
DrawPNG(PNG, ACanvas, Rect);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ClearCanvas(CHandle: THandle; Rect: TRect);
|
||||||
|
begin
|
||||||
|
PatBlt(CHandle, Rect.Left, Rect.Top, Rect.Width, Rect.Height, WHITENESS);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ClearGrid(Grid: PDrawGrid);
|
||||||
|
var
|
||||||
|
X, Y, W, H: Word;
|
||||||
|
begin
|
||||||
|
W := Grid^.ColCount;
|
||||||
|
H := Grid^.RowCount;
|
||||||
|
|
||||||
|
for Y := 1 to H do
|
||||||
|
for X := 1 to W do
|
||||||
|
ClearCanvas(Grid^.Canvas.Handle, Grid^.CellRect(X - 1, Y - 1));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawPNG(PNG: PPNGImage; ACanvas: PCanvas; Rect: TRect);
|
||||||
|
begin
|
||||||
|
if PNG^ = nil then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
Rect.Width := PNG^.Width;
|
||||||
|
Rect.Height := PNG^.Height;
|
||||||
|
|
||||||
|
PNG^.Draw(ACanvas^, Rect);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawClutCell(TIM: PTIM; CLUT_NUM: Integer; Grid: PDrawGrid;
|
||||||
|
X, Y: Integer);
|
||||||
|
var
|
||||||
|
CLUT_COLOR: PCLUT_COLOR;
|
||||||
|
R, G, B, STP, ALPHA: Byte;
|
||||||
|
Rect: TRect;
|
||||||
|
COLS: Integer;
|
||||||
|
begin
|
||||||
|
New(CLUT_COLOR);
|
||||||
|
|
||||||
|
COLS := Min(GetTimColorsCount(TIM), cCLUTGridColsCount);
|
||||||
|
CLUT_COLOR^ := GetCLUTColor(TIM, CLUT_NUM, Y * COLS + X);
|
||||||
|
R := CLUT_COLOR^.R;
|
||||||
|
G := CLUT_COLOR^.G;
|
||||||
|
B := CLUT_COLOR^.B;
|
||||||
|
STP := CLUT_COLOR^.STP;
|
||||||
|
|
||||||
|
Rect := Grid^.CellRect(X, Y);
|
||||||
|
|
||||||
|
ClearCanvas(Grid^.Canvas.Handle, Rect);
|
||||||
|
Grid^.Canvas.Brush.COLOR := RGB(R, G, B);
|
||||||
|
|
||||||
|
Grid^.Canvas.FillRect(Rect);
|
||||||
|
|
||||||
|
if (R + G + B) = 0 then
|
||||||
|
ALPHA := 0
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
if STP = 0 then
|
||||||
|
ALPHA := 255
|
||||||
|
else
|
||||||
|
ALPHA := 128;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ALPHA in [0, 128] then
|
||||||
|
begin
|
||||||
|
Grid^.Canvas.Brush.COLOR := clWhite;
|
||||||
|
if ALPHA = 0 then
|
||||||
|
Rect.Height := Rect.Height div 2
|
||||||
|
else
|
||||||
|
Rect.Width := Rect.Width div 2;
|
||||||
|
|
||||||
|
Grid^.Canvas.FillRect(Rect);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Dispose(CLUT_COLOR);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure DrawCLUT(TIM: PTIM; CLUT_NUM: Integer; Grid: PDrawGrid);
|
||||||
|
var
|
||||||
|
X, Y, ROWS, COLS, COLORS: Integer;
|
||||||
|
begin
|
||||||
|
COLORS := GetTimColorsCount(TIM);
|
||||||
|
COLS := Min(COLORS, cCLUTGridColsCount);
|
||||||
|
Grid^.ColCount := COLS;
|
||||||
|
ROWS := COLORS div COLS;
|
||||||
|
|
||||||
|
Grid^.RowCount := ROWS;
|
||||||
|
|
||||||
|
for Y := 1 to ROWS do
|
||||||
|
for X := 1 to COLS do
|
||||||
|
begin
|
||||||
|
ClearCanvas(Grid^.Canvas.Handle, Grid^.CellRect(X - 1, Y - 1));
|
||||||
|
DrawClutCell(TIM, CLUT_NUM, Grid, X - 1, Y - 1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
48
units/uEventWaitThread.pas
Normal file
48
units/uEventWaitThread.pas
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
unit uEventWaitThread;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows, Classes;
|
||||||
|
|
||||||
|
type
|
||||||
|
TEventWaitThread = class(TThread)
|
||||||
|
private
|
||||||
|
{ Private declarations }
|
||||||
|
protected
|
||||||
|
procedure Execute; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
CommandEvent: THandle;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
uMain;
|
||||||
|
|
||||||
|
{ Important: Methods and properties of objects in VCL can only be used in a
|
||||||
|
method called using Synchronize, for example,
|
||||||
|
|
||||||
|
Synchronize(UpdateCaption);
|
||||||
|
|
||||||
|
and UpdateCaption could look like,
|
||||||
|
|
||||||
|
procedure TEventWaitThread.UpdateCaption;
|
||||||
|
begin
|
||||||
|
Form1.Caption := 'Updated in a thread';
|
||||||
|
end; }
|
||||||
|
|
||||||
|
{ TEventWaitThread }
|
||||||
|
|
||||||
|
procedure TEventWaitThread.Execute;
|
||||||
|
begin
|
||||||
|
while True do
|
||||||
|
begin
|
||||||
|
if WaitForSingleObject(CommandEvent, INFINITE) <> WAIT_OBJECT_0 then
|
||||||
|
Exit;
|
||||||
|
PostMessage(frmMain.Handle, WM_COMMANDARRIVED, 0, 0);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
467
units/uMain.dfm
Normal file
467
units/uMain.dfm
Normal file
@@ -0,0 +1,467 @@
|
|||||||
|
object frmMainT2V: TfrmMainT2V
|
||||||
|
Left = 0
|
||||||
|
Top = 0
|
||||||
|
Width = 754
|
||||||
|
Height = 591
|
||||||
|
AutoScroll = True
|
||||||
|
Color = clBtnFace
|
||||||
|
Font.Charset = DEFAULT_CHARSET
|
||||||
|
Font.Color = clWindowText
|
||||||
|
Font.Height = -11
|
||||||
|
Font.Name = 'Tahoma'
|
||||||
|
Font.Style = []
|
||||||
|
Menu = mmMain
|
||||||
|
OldCreateOrder = False
|
||||||
|
Position = poScreenCenter
|
||||||
|
ScreenSnap = True
|
||||||
|
OnClose = FormClose
|
||||||
|
OnCreate = FormCreate
|
||||||
|
PixelsPerInch = 96
|
||||||
|
TextHeight = 13
|
||||||
|
object pnlStatus: TPanel
|
||||||
|
Left = 0
|
||||||
|
Top = 502
|
||||||
|
Width = 738
|
||||||
|
Height = 30
|
||||||
|
Align = alBottom
|
||||||
|
BevelOuter = bvLowered
|
||||||
|
TabOrder = 2
|
||||||
|
object lblStatus: TLabel
|
||||||
|
Left = 76
|
||||||
|
Top = 1
|
||||||
|
Width = 157
|
||||||
|
Height = 28
|
||||||
|
Align = alClient
|
||||||
|
Alignment = taRightJustify
|
||||||
|
Layout = tlCenter
|
||||||
|
ExplicitLeft = 230
|
||||||
|
ExplicitWidth = 3
|
||||||
|
ExplicitHeight = 13
|
||||||
|
end
|
||||||
|
object pbProgress: TProgressBar
|
||||||
|
Left = 233
|
||||||
|
Top = 1
|
||||||
|
Width = 504
|
||||||
|
Height = 28
|
||||||
|
Align = alRight
|
||||||
|
Smooth = True
|
||||||
|
TabOrder = 1
|
||||||
|
end
|
||||||
|
object btnStopScan: TButton
|
||||||
|
Left = 1
|
||||||
|
Top = 1
|
||||||
|
Width = 75
|
||||||
|
Height = 28
|
||||||
|
Align = alLeft
|
||||||
|
Caption = 'Stop Scan'
|
||||||
|
Enabled = False
|
||||||
|
TabOrder = 0
|
||||||
|
OnClick = btnStopScanClick
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object cbbFiles: TComboBox
|
||||||
|
Left = 0
|
||||||
|
Top = 0
|
||||||
|
Width = 738
|
||||||
|
Height = 21
|
||||||
|
Align = alTop
|
||||||
|
AutoDropDown = True
|
||||||
|
AutoCloseUp = True
|
||||||
|
Style = csDropDownList
|
||||||
|
DropDownCount = 30
|
||||||
|
TabOrder = 0
|
||||||
|
OnChange = cbbFilesChange
|
||||||
|
end
|
||||||
|
object pnlMain: TPanel
|
||||||
|
Left = 0
|
||||||
|
Top = 21
|
||||||
|
Width = 738
|
||||||
|
Height = 481
|
||||||
|
Align = alClient
|
||||||
|
BevelOuter = bvNone
|
||||||
|
TabOrder = 1
|
||||||
|
object splMain: TSplitter
|
||||||
|
Left = 233
|
||||||
|
Top = 0
|
||||||
|
Height = 481
|
||||||
|
ResizeStyle = rsUpdate
|
||||||
|
ExplicitLeft = 201
|
||||||
|
end
|
||||||
|
object pnlList: TPanel
|
||||||
|
Left = 0
|
||||||
|
Top = 0
|
||||||
|
Width = 233
|
||||||
|
Height = 481
|
||||||
|
Align = alLeft
|
||||||
|
BevelOuter = bvNone
|
||||||
|
TabOrder = 0
|
||||||
|
object lvList: TListView
|
||||||
|
Left = 0
|
||||||
|
Top = 0
|
||||||
|
Width = 233
|
||||||
|
Height = 481
|
||||||
|
Align = alClient
|
||||||
|
Columns = <
|
||||||
|
item
|
||||||
|
Caption = '# / 0'
|
||||||
|
Width = 60
|
||||||
|
end
|
||||||
|
item
|
||||||
|
Alignment = taCenter
|
||||||
|
Caption = 'Resolution'
|
||||||
|
Width = 95
|
||||||
|
end
|
||||||
|
item
|
||||||
|
Caption = 'BPP'
|
||||||
|
end>
|
||||||
|
ColumnClick = False
|
||||||
|
DoubleBuffered = True
|
||||||
|
GridLines = True
|
||||||
|
HideSelection = False
|
||||||
|
OwnerData = True
|
||||||
|
ReadOnly = True
|
||||||
|
RowSelect = True
|
||||||
|
ParentDoubleBuffered = False
|
||||||
|
PopupMenu = pmList
|
||||||
|
TabOrder = 0
|
||||||
|
ViewStyle = vsReport
|
||||||
|
OnClick = lvListClick
|
||||||
|
OnData = lvListData
|
||||||
|
OnKeyDown = lvListKeyDown
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object pnlImage: TPanel
|
||||||
|
Left = 236
|
||||||
|
Top = 0
|
||||||
|
Width = 502
|
||||||
|
Height = 481
|
||||||
|
Align = alClient
|
||||||
|
BevelOuter = bvLowered
|
||||||
|
TabOrder = 1
|
||||||
|
object splImageClut: TSplitter
|
||||||
|
Left = 1
|
||||||
|
Top = 1
|
||||||
|
Width = 500
|
||||||
|
Height = 3
|
||||||
|
Cursor = crVSplit
|
||||||
|
Align = alTop
|
||||||
|
Beveled = True
|
||||||
|
ResizeStyle = rsUpdate
|
||||||
|
ExplicitTop = 274
|
||||||
|
end
|
||||||
|
object imgTIM: TImage
|
||||||
|
Left = 1
|
||||||
|
Top = 4
|
||||||
|
Width = 500
|
||||||
|
Height = 296
|
||||||
|
Align = alClient
|
||||||
|
Center = True
|
||||||
|
IncrementalDisplay = True
|
||||||
|
Proportional = True
|
||||||
|
ExplicitLeft = 152
|
||||||
|
ExplicitTop = 112
|
||||||
|
ExplicitWidth = 105
|
||||||
|
ExplicitHeight = 105
|
||||||
|
end
|
||||||
|
object grdCurrCLUT: TDrawGrid
|
||||||
|
Left = 1
|
||||||
|
Top = 330
|
||||||
|
Width = 500
|
||||||
|
Height = 150
|
||||||
|
Align = alBottom
|
||||||
|
ColCount = 1
|
||||||
|
DefaultColWidth = 14
|
||||||
|
DefaultRowHeight = 14
|
||||||
|
DoubleBuffered = True
|
||||||
|
Enabled = False
|
||||||
|
FixedCols = 0
|
||||||
|
RowCount = 1
|
||||||
|
FixedRows = 0
|
||||||
|
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goDrawFocusSelected]
|
||||||
|
ParentDoubleBuffered = False
|
||||||
|
ScrollBars = ssNone
|
||||||
|
TabOrder = 0
|
||||||
|
OnDblClick = grdCurrCLUTDblClick
|
||||||
|
OnDrawCell = grdCurrCLUTDrawCell
|
||||||
|
end
|
||||||
|
object pnlImageOptions: TPanel
|
||||||
|
Left = 1
|
||||||
|
Top = 300
|
||||||
|
Width = 500
|
||||||
|
Height = 30
|
||||||
|
Align = alBottom
|
||||||
|
BevelOuter = bvLowered
|
||||||
|
TabOrder = 1
|
||||||
|
object cbbCLUT: TComboBox
|
||||||
|
AlignWithMargins = True
|
||||||
|
Left = 4
|
||||||
|
Top = 4
|
||||||
|
Width = 152
|
||||||
|
Height = 21
|
||||||
|
Align = alLeft
|
||||||
|
AutoDropDown = True
|
||||||
|
AutoCloseUp = True
|
||||||
|
Style = csDropDownList
|
||||||
|
TabOrder = 0
|
||||||
|
OnChange = cbbCLUTChange
|
||||||
|
end
|
||||||
|
object cbbTransparenceMode: TComboBox
|
||||||
|
AlignWithMargins = True
|
||||||
|
Left = 162
|
||||||
|
Top = 4
|
||||||
|
Width = 145
|
||||||
|
Height = 21
|
||||||
|
Align = alLeft
|
||||||
|
Style = csDropDownList
|
||||||
|
ItemIndex = 0
|
||||||
|
TabOrder = 1
|
||||||
|
Text = 'Full transparence'
|
||||||
|
OnClick = cbbTransparenceModeClick
|
||||||
|
Items.Strings = (
|
||||||
|
'Full transparence'
|
||||||
|
'Black Transparence'
|
||||||
|
'Semi Transparence'
|
||||||
|
'No Transparence')
|
||||||
|
end
|
||||||
|
object cbbBitMode: TComboBox
|
||||||
|
AlignWithMargins = True
|
||||||
|
Left = 313
|
||||||
|
Top = 4
|
||||||
|
Width = 88
|
||||||
|
Height = 21
|
||||||
|
Align = alLeft
|
||||||
|
Style = csDropDownList
|
||||||
|
ItemIndex = 0
|
||||||
|
TabOrder = 2
|
||||||
|
Text = 'Real'
|
||||||
|
OnChange = cbbBitModeChange
|
||||||
|
Items.Strings = (
|
||||||
|
'Real'
|
||||||
|
'4 BPP'
|
||||||
|
'8 BPP'
|
||||||
|
'16 BPP'
|
||||||
|
'24 BPP')
|
||||||
|
end
|
||||||
|
object chkStretch: TCheckBox
|
||||||
|
Left = 404
|
||||||
|
Top = 1
|
||||||
|
Width = 97
|
||||||
|
Height = 28
|
||||||
|
Action = actStretch
|
||||||
|
Align = alLeft
|
||||||
|
TabOrder = 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object dlgOpenFile: TOpenDialog
|
||||||
|
DefaultExt = '.bin'
|
||||||
|
Filter = 'All Files (*.*)|*.*'
|
||||||
|
Options = [ofHideReadOnly, ofNoChangeDir, ofAllowMultiSelect, ofFileMustExist, ofNoNetworkButton, ofEnableSizing, ofForceShowHidden]
|
||||||
|
Title = 'Please, select File...'
|
||||||
|
Left = 668
|
||||||
|
Top = 502
|
||||||
|
end
|
||||||
|
object mmMain: TMainMenu
|
||||||
|
Left = 608
|
||||||
|
Top = 504
|
||||||
|
object mnFile: TMenuItem
|
||||||
|
Caption = '&File'
|
||||||
|
object mnScanFile: TMenuItem
|
||||||
|
Action = actScanFile
|
||||||
|
end
|
||||||
|
object mnScanDir: TMenuItem
|
||||||
|
Action = actScanDir
|
||||||
|
end
|
||||||
|
object N1: TMenuItem
|
||||||
|
Caption = '-'
|
||||||
|
end
|
||||||
|
object mnCloseFile: TMenuItem
|
||||||
|
Action = actCloseFile
|
||||||
|
end
|
||||||
|
object mnCloseAllFiles: TMenuItem
|
||||||
|
Action = actCloseFiles
|
||||||
|
end
|
||||||
|
object mnExit: TMenuItem
|
||||||
|
Action = actExit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object mnTIM: TMenuItem
|
||||||
|
Caption = '&TIM'
|
||||||
|
object mnSaveTIM: TMenuItem
|
||||||
|
Action = actExtractTim
|
||||||
|
end
|
||||||
|
object mnReplaceIn: TMenuItem
|
||||||
|
Action = actReplaceTim
|
||||||
|
end
|
||||||
|
object mnSaveToPNG: TMenuItem
|
||||||
|
Action = actTim2Png
|
||||||
|
end
|
||||||
|
object N4: TMenuItem
|
||||||
|
Caption = '-'
|
||||||
|
end
|
||||||
|
object IMInfo1: TMenuItem
|
||||||
|
Action = actTimInfo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object mnConfig: TMenuItem
|
||||||
|
Caption = '&Options'
|
||||||
|
object mnAutoExtract: TMenuItem
|
||||||
|
AutoCheck = True
|
||||||
|
Caption = '&Auto Extraction'
|
||||||
|
end
|
||||||
|
object Stretch1: TMenuItem
|
||||||
|
Action = actStretch
|
||||||
|
AutoCheck = True
|
||||||
|
end
|
||||||
|
object mnViewMode: TMenuItem
|
||||||
|
Caption = '&View Mode'
|
||||||
|
object mnSimpleMode: TMenuItem
|
||||||
|
AutoCheck = True
|
||||||
|
Caption = '&Simple Mode'
|
||||||
|
RadioItem = True
|
||||||
|
OnClick = mnSimpleModeClick
|
||||||
|
end
|
||||||
|
object mnAdvancedMode: TMenuItem
|
||||||
|
AutoCheck = True
|
||||||
|
Caption = '&Advanced Mode'
|
||||||
|
Checked = True
|
||||||
|
RadioItem = True
|
||||||
|
OnClick = mnAdvancedModeClick
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object N5: TMenuItem
|
||||||
|
Caption = '-'
|
||||||
|
end
|
||||||
|
object mnAssociate: TMenuItem
|
||||||
|
Action = actAssocTims
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object mnHelp: TMenuItem
|
||||||
|
Caption = '&Help'
|
||||||
|
object mnSVN: TMenuItem
|
||||||
|
Action = actOpenRepo
|
||||||
|
end
|
||||||
|
object mnSite: TMenuItem
|
||||||
|
Action = actOpenLab
|
||||||
|
end
|
||||||
|
object N3: TMenuItem
|
||||||
|
Caption = '-'
|
||||||
|
end
|
||||||
|
object mnAbout: TMenuItem
|
||||||
|
Action = actAbout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object dlgSavePNG: TSavePictureDialog
|
||||||
|
DefaultExt = 'png'
|
||||||
|
Filter = 'Portable Network Graphics (*.png)|*.png'
|
||||||
|
Options = [ofHideReadOnly, ofNoChangeDir, ofNoNetworkButton, ofEnableSizing]
|
||||||
|
Title = 'Please, select filename for PNG...'
|
||||||
|
Left = 704
|
||||||
|
Top = 504
|
||||||
|
end
|
||||||
|
object dlgSaveTIM: TSaveDialog
|
||||||
|
DefaultExt = 'tim'
|
||||||
|
Filter = 'PSX TIM Files (*.tim)|*.tim|All Files (*.*)|*.*'
|
||||||
|
Options = [ofOverwritePrompt, ofHideReadOnly, ofNoChangeDir, ofNoNetworkButton, ofEnableSizing]
|
||||||
|
Title = 'Please, select where to save TIM file...'
|
||||||
|
Left = 576
|
||||||
|
Top = 504
|
||||||
|
end
|
||||||
|
object dlgColor: TColorDialog
|
||||||
|
Options = [cdFullOpen]
|
||||||
|
Left = 544
|
||||||
|
Top = 502
|
||||||
|
end
|
||||||
|
object actList: TActionList
|
||||||
|
Left = 512
|
||||||
|
Top = 502
|
||||||
|
object actScanFile: TAction
|
||||||
|
Caption = 'Scan &File...'
|
||||||
|
ShortCut = 116
|
||||||
|
OnExecute = actScanFileExecute
|
||||||
|
end
|
||||||
|
object actScanDir: TAction
|
||||||
|
Caption = 'Scan &Directory...'
|
||||||
|
ShortCut = 117
|
||||||
|
OnExecute = actScanDirExecute
|
||||||
|
end
|
||||||
|
object actCloseFile: TAction
|
||||||
|
Caption = 'Close &this File'
|
||||||
|
ShortCut = 119
|
||||||
|
OnExecute = actCloseFileExecute
|
||||||
|
end
|
||||||
|
object actCloseFiles: TAction
|
||||||
|
Caption = 'Close &all Files'
|
||||||
|
ShortCut = 120
|
||||||
|
OnExecute = actCloseFilesExecute
|
||||||
|
end
|
||||||
|
object actExit: TAction
|
||||||
|
Caption = '&Exit...'
|
||||||
|
ShortCut = 121
|
||||||
|
OnExecute = actExitExecute
|
||||||
|
end
|
||||||
|
object actExtractTim: TAction
|
||||||
|
Caption = '&Extract TIM...'
|
||||||
|
ShortCut = 113
|
||||||
|
OnExecute = actExtractTimExecute
|
||||||
|
end
|
||||||
|
object actReplaceTim: TAction
|
||||||
|
Caption = '&Replace TIM...'
|
||||||
|
ShortCut = 114
|
||||||
|
OnExecute = actReplaceTimExecute
|
||||||
|
end
|
||||||
|
object actTim2Png: TAction
|
||||||
|
Caption = 'Save as &PNG...'
|
||||||
|
ShortCut = 115
|
||||||
|
OnExecute = actTim2PngExecute
|
||||||
|
end
|
||||||
|
object actOpenRepo: TAction
|
||||||
|
Caption = 'Tim2Vew &SVN Repo'
|
||||||
|
OnExecute = actOpenRepoExecute
|
||||||
|
end
|
||||||
|
object actOpenLab: TAction
|
||||||
|
Caption = '[&Lab313] Forum'
|
||||||
|
OnExecute = actOpenLabExecute
|
||||||
|
end
|
||||||
|
object actAbout: TAction
|
||||||
|
Caption = 'About...'
|
||||||
|
ShortCut = 112
|
||||||
|
OnExecute = actAboutExecute
|
||||||
|
end
|
||||||
|
object actStretch: TAction
|
||||||
|
AutoCheck = True
|
||||||
|
Caption = '&Stretch'
|
||||||
|
OnExecute = actStretchExecute
|
||||||
|
end
|
||||||
|
object actTimInfo: TAction
|
||||||
|
Caption = 'TIM Info'
|
||||||
|
Enabled = False
|
||||||
|
OnExecute = actTimInfoExecute
|
||||||
|
end
|
||||||
|
object actAssocTims: TAction
|
||||||
|
Caption = 'Open TIMs with T2V'
|
||||||
|
OnExecute = actAssocTimsExecute
|
||||||
|
end
|
||||||
|
end
|
||||||
|
object pmList: TPopupMenu
|
||||||
|
Left = 640
|
||||||
|
Top = 502
|
||||||
|
object ExtractTIM1: TMenuItem
|
||||||
|
Action = actExtractTim
|
||||||
|
end
|
||||||
|
object ReplaceTIM1: TMenuItem
|
||||||
|
Action = actReplaceTim
|
||||||
|
end
|
||||||
|
object SaveasPNG1: TMenuItem
|
||||||
|
Action = actTim2Png
|
||||||
|
end
|
||||||
|
object N2: TMenuItem
|
||||||
|
Caption = '-'
|
||||||
|
end
|
||||||
|
object mnTIMInfo: TMenuItem
|
||||||
|
Action = actTimInfo
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
1129
units/uMain.pas
Normal file
1129
units/uMain.pas
Normal file
File diff suppressed because it is too large
Load Diff
217
units/uScanThread.pas
Normal file
217
units/uScanThread.pas
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
unit uScanThread;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Classes, Windows, uCommon, uTIM;
|
||||||
|
|
||||||
|
type
|
||||||
|
PScanThread = ^TScanThread;
|
||||||
|
|
||||||
|
TScanThread = class(Classes.TThread)
|
||||||
|
private
|
||||||
|
{ Private declarations }
|
||||||
|
pTims: Integer;
|
||||||
|
pFileToScan: string;
|
||||||
|
pImageScan: boolean;
|
||||||
|
pResult: PNativeXml;
|
||||||
|
pFileSize: DWORD;
|
||||||
|
pFilePos: DWORD;
|
||||||
|
pStatusText: string;
|
||||||
|
pClearBufferPosition: DWORD;
|
||||||
|
pClearBufferSize: DWORD;
|
||||||
|
pSectorBufferSize: DWORD;
|
||||||
|
pSrcFileStream: TFileStream;
|
||||||
|
pStopScan: boolean;
|
||||||
|
procedure SetStatusText;
|
||||||
|
procedure UpdateProgressBar;
|
||||||
|
procedure AddResult(TIM: PTIM);
|
||||||
|
procedure ClearSectorBuffer(SectorBuffer, ClearBuffer: PBytesArray);
|
||||||
|
protected
|
||||||
|
procedure Execute; override;
|
||||||
|
public
|
||||||
|
constructor Create(const FileToScan: string; fResult: pointer;
|
||||||
|
ImageScan: boolean);
|
||||||
|
property Terminated;
|
||||||
|
property StopScan: boolean write pStopScan;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
uMain, uCDIMAGE, System.SysUtils, NativeXml;
|
||||||
|
|
||||||
|
const
|
||||||
|
cClearBufferSize = ((cTIMMaxSize div cSectorDataSize) + 1) *
|
||||||
|
cSectorDataSize * 2;
|
||||||
|
cSectorBufferSize = (cClearBufferSize div cSectorDataSize) * cSectorSize;
|
||||||
|
|
||||||
|
{ TScanThread }
|
||||||
|
|
||||||
|
constructor TScanThread.Create(const FileToScan: string; fResult: pointer;
|
||||||
|
ImageScan: boolean);
|
||||||
|
var
|
||||||
|
Node: TXmlNode;
|
||||||
|
begin
|
||||||
|
inherited Create(True);
|
||||||
|
FreeOnTerminate := True;
|
||||||
|
pClearBufferPosition := 0;
|
||||||
|
pFilePos := 0;
|
||||||
|
pTims := 0;
|
||||||
|
pFileToScan := FileToScan;
|
||||||
|
pFileSize := GetFileSizeAPI(pFileToScan);
|
||||||
|
pStatusText := '';
|
||||||
|
pStopScan := False;
|
||||||
|
pImageScan := ImageScan;
|
||||||
|
|
||||||
|
pResult := fResult;
|
||||||
|
Node := pResult^.Root.NodeNew(cResInfoNode);
|
||||||
|
Node.WriteAttributeUnicodeString(cResAttrFile, pFileToScan);
|
||||||
|
Node.WriteAttributeBool(cResAttrImageFile, ImageScan);
|
||||||
|
Node.WriteAttributeInteger(cResAttrTimsCount, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TScanThread.AddResult(TIM: PTIM);
|
||||||
|
var
|
||||||
|
Node, AddedNode: TXmlNode;
|
||||||
|
begin
|
||||||
|
Node := pResult^.Root.NodeFindOrCreate(cResInfoNode);
|
||||||
|
Node.WriteAttributeInteger(cResAttrTimsCount, TIM^.dwTimNumber);
|
||||||
|
|
||||||
|
Node := pResult^.Root.NodeFindOrCreate(cResTimsNode);
|
||||||
|
|
||||||
|
AddedNode := Node.NodeNew(cResTimNode);
|
||||||
|
AddedNode.WriteAttributeInteger(cResTimAttrPos, TIM^.dwTimPosition);
|
||||||
|
AddedNode.WriteAttributeInteger(cResTimAttrSize, TIM^.dwSIZE);
|
||||||
|
AddedNode.WriteAttributeInteger(cResTimAttrWidth, GetTimRealWidth(TIM));
|
||||||
|
AddedNode.WriteAttributeInteger(cResTimAttrHeight, GetTimHeight(TIM));
|
||||||
|
AddedNode.WriteAttributeInteger(cResTimAttrBitMode, BppToBitMode(TIM));
|
||||||
|
AddedNode.WriteAttributeBool(cResTimAttrGood, TIMIsGood(TIM));
|
||||||
|
|
||||||
|
Inc(pTims);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TScanThread.Execute;
|
||||||
|
var
|
||||||
|
SectorBuffer, ClearBuffer: PBytesArray;
|
||||||
|
TIM: PTIM;
|
||||||
|
pScanFinished: boolean;
|
||||||
|
pRealBufSize, pTimPosition, pTIMNumber: DWORD;
|
||||||
|
begin
|
||||||
|
pSrcFileStream := TFileStream.Create(pFileToScan, fmOpenRead or
|
||||||
|
fmShareDenyWrite);
|
||||||
|
pSrcFileStream.Position := 0;
|
||||||
|
|
||||||
|
if pImageScan then
|
||||||
|
pSectorBufferSize := cSectorBufferSize
|
||||||
|
else
|
||||||
|
pSectorBufferSize := cClearBufferSize;
|
||||||
|
|
||||||
|
pClearBufferSize := cClearBufferSize;
|
||||||
|
|
||||||
|
SectorBuffer := GetMemory(pSectorBufferSize);
|
||||||
|
ClearBuffer := GetMemory(pClearBufferSize);
|
||||||
|
|
||||||
|
TIM := CreateTIM;
|
||||||
|
|
||||||
|
pStatusText := sStatusBarScanningFile;
|
||||||
|
Synchronize(SetStatusText);
|
||||||
|
|
||||||
|
pRealBufSize := pSrcFileStream.Read(SectorBuffer^[0], pSectorBufferSize);
|
||||||
|
Inc(pFilePos, pRealBufSize);
|
||||||
|
ClearSectorBuffer(SectorBuffer, ClearBuffer);
|
||||||
|
|
||||||
|
pScanFinished := False;
|
||||||
|
pTIMNumber := 0;
|
||||||
|
|
||||||
|
repeat
|
||||||
|
if LoadTimFromBuf(ClearBuffer, TIM, pClearBufferPosition) then
|
||||||
|
begin
|
||||||
|
if pImageScan then
|
||||||
|
pTimPosition := pFilePos - pRealBufSize +
|
||||||
|
((pClearBufferPosition - 1) div cSectorDataSize) * cSectorSize +
|
||||||
|
((pClearBufferPosition - 1) mod cSectorDataSize) + cSectorInfoSize
|
||||||
|
else
|
||||||
|
pTimPosition := pFilePos - pRealBufSize + (pClearBufferPosition - 1);
|
||||||
|
|
||||||
|
if pTimPosition >= pFileSize then
|
||||||
|
Break;
|
||||||
|
|
||||||
|
TIM^.dwTimPosition := pTimPosition;
|
||||||
|
Inc(pTIMNumber);
|
||||||
|
TIM^.dwTimNumber := pTIMNumber;
|
||||||
|
AddResult(TIM);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if pClearBufferPosition = (pClearBufferSize div 2) then
|
||||||
|
begin
|
||||||
|
if pScanFinished then
|
||||||
|
Break;
|
||||||
|
|
||||||
|
pScanFinished := (pFilePos = pFileSize);
|
||||||
|
pClearBufferPosition := 0;
|
||||||
|
Move(SectorBuffer^[pSectorBufferSize div 2], SectorBuffer^[0],
|
||||||
|
pSectorBufferSize div 2);
|
||||||
|
|
||||||
|
if pScanFinished then
|
||||||
|
begin
|
||||||
|
if pRealBufSize >= (pSectorBufferSize div 2) then
|
||||||
|
// Need to check file size
|
||||||
|
pRealBufSize := pRealBufSize - (pSectorBufferSize div 2);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
pRealBufSize := pSrcFileStream.
|
||||||
|
Read(SectorBuffer^[pSectorBufferSize div 2], pSectorBufferSize div 2);
|
||||||
|
Inc(pFilePos, pRealBufSize);
|
||||||
|
pRealBufSize := pRealBufSize + (pSectorBufferSize div 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Synchronize(UpdateProgressBar);
|
||||||
|
|
||||||
|
ClearSectorBuffer(SectorBuffer, ClearBuffer);
|
||||||
|
end;
|
||||||
|
until pStopScan;
|
||||||
|
FreeTIM(TIM);
|
||||||
|
FreeMemory(SectorBuffer);
|
||||||
|
FreeMemory(ClearBuffer);
|
||||||
|
|
||||||
|
Synchronize(UpdateProgressBar);
|
||||||
|
|
||||||
|
pSrcFileStream.Free;
|
||||||
|
pFilePos := 0;
|
||||||
|
|
||||||
|
Synchronize(UpdateProgressBar);
|
||||||
|
pStatusText := '';
|
||||||
|
Synchronize(SetStatusText);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TScanThread.SetStatusText;
|
||||||
|
begin
|
||||||
|
frmMain.lblStatus.Caption := pStatusText;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TScanThread.UpdateProgressBar;
|
||||||
|
begin
|
||||||
|
frmMain.pbProgress.Position := pFilePos;
|
||||||
|
frmMain.lvList.Column[0].Caption := Format('# / %d', [pTims]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TScanThread.ClearSectorBuffer(SectorBuffer, ClearBuffer: PBytesArray);
|
||||||
|
var
|
||||||
|
i: DWORD;
|
||||||
|
begin
|
||||||
|
FillChar(ClearBuffer^[0], pClearBufferSize, 0);
|
||||||
|
if not pImageScan then
|
||||||
|
begin
|
||||||
|
Move(SectorBuffer^[0], ClearBuffer^[0], pClearBufferSize);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
for i := 1 to (pSectorBufferSize div cSectorSize) do
|
||||||
|
begin
|
||||||
|
Move(SectorBuffer^[(i - 1) * cSectorSize + cSectorInfoSize],
|
||||||
|
ClearBuffer^[(i - 1) * cSectorDataSize], cSectorDataSize);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
598
units/uTIM.pas
Normal file
598
units/uTIM.pas
Normal file
@@ -0,0 +1,598 @@
|
|||||||
|
unit uTIM;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
Windows, uCommon, System.Classes;
|
||||||
|
|
||||||
|
const
|
||||||
|
cTIMMagic = $10;
|
||||||
|
cTIM4C = $08;
|
||||||
|
cTIM4NC = $00;
|
||||||
|
cTIM4 = [cTIM4C, cTIM4NC];
|
||||||
|
cTIM8C = $09;
|
||||||
|
cTIM8NC = $01;
|
||||||
|
cTIM8 = [cTIM8C, cTIM8NC];
|
||||||
|
cTIM16C = $0A;
|
||||||
|
cTIM16NC = $02;
|
||||||
|
cTIM16 = [cTIM16C, cTIM16NC];
|
||||||
|
cTIM24C = $0B;
|
||||||
|
cTIM24NC = $03;
|
||||||
|
cTIM24 = [cTIM24C, cTIM24NC];
|
||||||
|
cTIMMix = $04;
|
||||||
|
cTIMVersions = [$00, $01];
|
||||||
|
cTIMWrongBads = [cTIM4NC, cTIM8NC, cTIMMix];
|
||||||
|
cTIMCLUT = [cTIM4C, cTIM8C, cTIM16C, cTIM24C];
|
||||||
|
cTIMNOCLUT = [cTIM4NC, cTIM8NC, cTIM16NC, cTIM24NC, cTIMMix];
|
||||||
|
cTIMBpp = [cTIM4C, cTIM8C, cTIM16C, cTIM24C, cTIM4NC, cTIM8NC, cTIM16NC,
|
||||||
|
cTIM24NC, cTIMMix];
|
||||||
|
|
||||||
|
cCLUTColorsMax = 1024;
|
||||||
|
cCLUTCountMax = 512;
|
||||||
|
cIMAGEWidthMax = 1024;
|
||||||
|
cIMAGEHeightMax = 1024;
|
||||||
|
cCLUTHeadSize = $0C;
|
||||||
|
cIMAGEHeadSize = $0C;
|
||||||
|
cTIMHeadSize = 8;
|
||||||
|
cRandomPaletteSize = $100;
|
||||||
|
cTIMMaxSize = cTIMHeadSize + cCLUTColorsMax * cCLUTCountMax * 2 +
|
||||||
|
cCLUTHeadSize + cIMAGEWidthMax * cIMAGEHeightMax * 2 + cIMAGEHeadSize;
|
||||||
|
|
||||||
|
type
|
||||||
|
TTIMHeader = packed record // TIM Header (8 bytes)
|
||||||
|
bMagic: byte; // $10 (1 byte)
|
||||||
|
bVersion: byte; // Any? (1 byte)
|
||||||
|
bReserved1: byte; // Reserved byte 1 (1 byte)
|
||||||
|
bReserved2: byte; // Reserved byte 2 (1 byte)
|
||||||
|
bBPP: DWORD; // Bit per Pixel (4 bytes)
|
||||||
|
// variants:
|
||||||
|
// [$08, $09, $0A, $0B, $02, $03, $00, $01]
|
||||||
|
end;
|
||||||
|
|
||||||
|
PTIMHeader = ^TTIMHeader;
|
||||||
|
|
||||||
|
type
|
||||||
|
TCLUTHeader = packed record // CLUT header (12+ bytes)
|
||||||
|
dwSize: DWORD; // Length of CLUT (4 bytes)
|
||||||
|
wVRAMX: word; // Palette coordinates in VRAM (by X) (2 bytes)
|
||||||
|
wVRAMY: word; // Palette coordinates in VRAM (by Y) (2 bytes)
|
||||||
|
wColorsCount: word; // Number of CLUT Colors (2 bytes)
|
||||||
|
wClutsCount: word; // Count of Palettes (2 bytes)
|
||||||
|
end;
|
||||||
|
|
||||||
|
PCLUTHeader = ^TCLUTHeader;
|
||||||
|
|
||||||
|
type
|
||||||
|
TIMAGEHeader = packed record // IMAGE Block Header (12+ bytes)
|
||||||
|
dwSize: DWORD; // Length of Image Block (4 bytes)
|
||||||
|
wVRAMX: word; // Image Block Coordinates in VRAM (by X) (2 bytes)
|
||||||
|
wVRAMY: word; // Image Block Coordinates in VRAM (by Y) (2 bytes)
|
||||||
|
wWidth: word; // Image Width (not Real) (2 bytes)
|
||||||
|
wHeight: word; // Image Height (Real) (2 bytes)
|
||||||
|
end;
|
||||||
|
|
||||||
|
PIMAGEHeader = ^TIMAGEHeader;
|
||||||
|
|
||||||
|
type
|
||||||
|
TTIMDataArray = array [0 .. cTIMMaxSize - 1] of byte;
|
||||||
|
PTIMDataArray = ^TTIMDataArray;
|
||||||
|
|
||||||
|
type
|
||||||
|
TCLUT_COLOR = record
|
||||||
|
// stp (special transparency processing) D=[0,1]
|
||||||
|
STP: byte;
|
||||||
|
// r,g,b D=[0,31]
|
||||||
|
R: byte;
|
||||||
|
G: byte;
|
||||||
|
B: byte;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PCLUT_COLOR = ^TCLUT_COLOR;
|
||||||
|
TCLUT_COLORS = array [0 .. cCLUTColorsMax * cCLUTCountMax - 1] of TCLUT_COLOR;
|
||||||
|
PCLUT_COLORS = ^TCLUT_COLORS;
|
||||||
|
|
||||||
|
type
|
||||||
|
TIMAGE_INDEXES = array [0 .. cIMAGEWidthMax * cIMAGEHeightMax * 4 -
|
||||||
|
1] of DWORD;
|
||||||
|
PIMAGE_INDEXES = ^TIMAGE_INDEXES;
|
||||||
|
|
||||||
|
type
|
||||||
|
TTIM = record
|
||||||
|
dwTimNumber: DWORD;
|
||||||
|
dwTimPosition: DWORD;
|
||||||
|
HEAD: PTIMHeader;
|
||||||
|
CLUT: PCLUTHeader;
|
||||||
|
IMAGE: PIMAGEHeader;
|
||||||
|
dwSize: DWORD;
|
||||||
|
DATA: PTIMDataArray;
|
||||||
|
bGOOD: Boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
PTIM = ^TTIM;
|
||||||
|
|
||||||
|
function TIMHasCLUT(TIM: PTIM): Boolean;
|
||||||
|
function GetTIMCLUTSize(TIM: PTIM): DWORD;
|
||||||
|
function GetTIMSize(TIM: PTIM): DWORD;
|
||||||
|
function GetTimWidth(TIM: PTIM): word;
|
||||||
|
function GetTimRealWidth(TIM: PTIM): word;
|
||||||
|
function GetTimHeight(TIM: PTIM): word;
|
||||||
|
function TIMIsGood(TIM: PTIM): Boolean;
|
||||||
|
function LoadTimFromBuf(BUFFER: pointer; var TIM: PTIM;
|
||||||
|
var Position: DWORD): Boolean;
|
||||||
|
function LoadTimFromFile(const FileName: string; var Position: DWORD;
|
||||||
|
ImageScan: Boolean; dwSize: DWORD): PTIM;
|
||||||
|
procedure SaveTimToFile(const FileName: string; TIM: PTIM);
|
||||||
|
function CreateTIM: PTIM;
|
||||||
|
procedure FreeTIM(TIM: PTIM);
|
||||||
|
function BppToBitMode(TIM: PTIM): byte;
|
||||||
|
function GetTimColorsCount(TIM: PTIM): word;
|
||||||
|
function GetTimClutsCount(TIM: PTIM): word;
|
||||||
|
function GetTimVersion(TIM: PTIM): byte;
|
||||||
|
function GetTimBPP(TIM: PTIM): DWORD;
|
||||||
|
function GetTimClutSizeHeader(TIM: PTIM): DWORD;
|
||||||
|
function GetTimClutVRAMX(TIM: PTIM): word;
|
||||||
|
function GetTimClutVRAMY(TIM: PTIM): word;
|
||||||
|
function GetTimImageSizeHeader(TIM: PTIM): DWORD;
|
||||||
|
function GetTimImageVRAMX(TIM: PTIM): word;
|
||||||
|
function GetTimImageVRAMY(TIM: PTIM): word;
|
||||||
|
function GetTIMIMAGESize(TIM: PTIM): DWORD;
|
||||||
|
function GetCLUTColor(TIM: PTIM; CLUT_NUM, COLOR_NUM: Integer): TCLUT_COLOR;
|
||||||
|
procedure WriteCLUTColor(TIM: PTIM; CLUT_NUM, COLOR_NUM: Integer;
|
||||||
|
COLOR: TCLUT_COLOR);
|
||||||
|
function ConvertTIMColor(COLOR: word): TCLUT_COLOR;
|
||||||
|
function ConvertCLUTColor(COLOR: TCLUT_COLOR): word;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.SysUtils, uCDIMAGE;
|
||||||
|
|
||||||
|
function ConvertTIMColor(COLOR: word): TCLUT_COLOR;
|
||||||
|
begin
|
||||||
|
Result.R := (COLOR and $1F) * 8;
|
||||||
|
Result.G := ((COLOR and $3E0) shr 5) * 8;
|
||||||
|
Result.B := ((COLOR and $7C00) shr 10) * 8;
|
||||||
|
Result.STP := ((COLOR and $8000) shr 15);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ConvertCLUTColor(COLOR: TCLUT_COLOR): word;
|
||||||
|
begin
|
||||||
|
Result := (COLOR.STP shl 15) or ((COLOR.B div 8) shl 10) or
|
||||||
|
((COLOR.G div 8) shl 5) or (COLOR.R div 8);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetCLUTColor(TIM: PTIM; CLUT_NUM, COLOR_NUM: Integer): TCLUT_COLOR;
|
||||||
|
var
|
||||||
|
CLUT_OFFSET: Integer;
|
||||||
|
COLOR: word;
|
||||||
|
begin
|
||||||
|
if (TIM^.HEAD^.bBPP in [cTIM4NC, cTIM8NC]) then
|
||||||
|
begin
|
||||||
|
Result.R := random($20) * 8;
|
||||||
|
Result.G := random($20) * 8;
|
||||||
|
Result.B := random($20) * 8;
|
||||||
|
Result.STP := 1;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
CLUT_OFFSET := CLUT_NUM * GetTimColorsCount(TIM) * 2;
|
||||||
|
|
||||||
|
Move(TIM^.DATA^[cTIMHeadSize + cCLUTHeadSize + COLOR_NUM * 2 + CLUT_OFFSET],
|
||||||
|
COLOR, 2);
|
||||||
|
|
||||||
|
Result := ConvertTIMColor(COLOR);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure WriteCLUTColor(TIM: PTIM; CLUT_NUM, COLOR_NUM: Integer;
|
||||||
|
COLOR: TCLUT_COLOR);
|
||||||
|
var
|
||||||
|
CLUT_OFFSET: Integer;
|
||||||
|
COLOR_TO_WRITE: word;
|
||||||
|
begin
|
||||||
|
CLUT_OFFSET := CLUT_NUM * GetTimColorsCount(TIM) * 2;
|
||||||
|
|
||||||
|
COLOR_TO_WRITE := ConvertCLUTColor(COLOR);
|
||||||
|
Move(COLOR_TO_WRITE, TIM^.DATA^[cTIMHeadSize + cCLUTHeadSize + COLOR_NUM * 2 +
|
||||||
|
CLUT_OFFSET], 2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimHeight(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.IMAGE^.wHeight;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTIMCLUTSize(TIM: PTIM): DWORD;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
|
||||||
|
if not TIMHasCLUT(TIM) then
|
||||||
|
Exit;
|
||||||
|
Result := TIM^.CLUT^.wColorsCount * TIM^.CLUT^.wClutsCount * 2 +
|
||||||
|
cCLUTHeadSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTIMIMAGESize(TIM: PTIM): DWORD;
|
||||||
|
begin
|
||||||
|
Result := TIM^.IMAGE^.wWidth * TIM^.IMAGE^.wHeight * 2 + cIMAGEHeadSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTIMSize(TIM: PTIM): DWORD;
|
||||||
|
begin
|
||||||
|
Result := GetTIMCLUTSize(TIM) + GetTIMIMAGESize(TIM) + cTIMHeadSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckVersion(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.HEAD^.bVersion in cTIMVersions);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckMagic(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.HEAD^.bMagic = cTIMMagic);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckBpp(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.HEAD^.bBPP in cTIMBpp);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckReserved(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.HEAD^.bReserved1 = 0) and (TIM^.HEAD^.bReserved2 = 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TIMHasCLUT(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.HEAD^.bBPP in cTIMCLUT);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckCLUTColors(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.CLUT^.wColorsCount >= 1) and
|
||||||
|
(TIM^.CLUT^.wColorsCount <= cCLUTColorsMax);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckCLUTCount(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.CLUT^.wClutsCount >= 1) and
|
||||||
|
(TIM^.CLUT^.wClutsCount <= cCLUTCountMax);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IWidthToRWidth(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
case TIM^.HEAD^.bBPP of
|
||||||
|
cTIM4C, cTIM4NC:
|
||||||
|
Result := (TIM^.IMAGE^.wWidth * 4) and $FFFF;
|
||||||
|
cTIM8C, cTIM8NC:
|
||||||
|
Result := (TIM^.IMAGE^.wWidth * 2) and $FFFF;
|
||||||
|
cTIM16C, cTIM16NC, cTIMMix:
|
||||||
|
Result := TIM^.IMAGE^.wWidth;
|
||||||
|
cTIM24C, cTIM24NC:
|
||||||
|
Result := (Round(TIM^.IMAGE^.wWidth * 2 / 3)) and $FFFF;
|
||||||
|
else
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckHEAD(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (CheckMagic(TIM) and CheckVersion(TIM) and CheckBpp(TIM) and
|
||||||
|
CheckReserved(TIM))
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckCLUT(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (CheckCLUTColors(TIM) and CheckCLUTCount(TIM)
|
||||||
|
// Need to Check CLUT^.dwSize
|
||||||
|
);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckTIMSize(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (GetTIMSize(TIM) <= cTIMMaxSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TIMIsGood(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (TIM^.IMAGE^.dwSize = GetTIMIMAGESize(TIM));
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CheckIMAGE(TIM: PTIM): Boolean;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
if (TIM^.IMAGE^.wWidth = 0) or (TIM^.IMAGE^.wHeight = 0) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
if (TIM^.IMAGE^.wWidth > cIMAGEWidthMax) or
|
||||||
|
(TIM^.IMAGE^.wHeight > cIMAGEHeightMax) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
Result := (not(TIM^.HEAD^.bBPP in cTIMWrongBads)) or TIMIsGood(TIM);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure ClearTIM(TIM: PTIM);
|
||||||
|
begin
|
||||||
|
FillChar(TIM^.HEAD^, cTIMHeadSize, 0);
|
||||||
|
FillChar(TIM^.CLUT^, cCLUTHeadSize, 0);
|
||||||
|
FillChar(TIM^.IMAGE^, cIMAGEHeadSize, 0);
|
||||||
|
FillChar(TIM^.DATA^, cTIMMaxSize, 0);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LoadTimFromBuf(BUFFER: pointer; var TIM: PTIM;
|
||||||
|
var Position: DWORD): Boolean;
|
||||||
|
var
|
||||||
|
P: DWORD;
|
||||||
|
TIM_POS: DWORD;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
P := Position;
|
||||||
|
Inc(Position);
|
||||||
|
TIM_POS := P;
|
||||||
|
|
||||||
|
if TIM = nil then
|
||||||
|
TIM := CreateTIM;
|
||||||
|
|
||||||
|
Move(PBytesArray(BUFFER)^[P], TIM^.HEAD^, cTIMHeadSize);
|
||||||
|
if not CheckHEAD(TIM) then
|
||||||
|
Exit;
|
||||||
|
Inc(P, cTIMHeadSize);
|
||||||
|
|
||||||
|
if TIMHasCLUT(TIM) then
|
||||||
|
begin
|
||||||
|
Move(PBytesArray(BUFFER)^[P], TIM^.CLUT^, cCLUTHeadSize);
|
||||||
|
if not CheckCLUT(TIM) then
|
||||||
|
Exit;
|
||||||
|
Inc(P, GetTIMCLUTSize(TIM));
|
||||||
|
end;
|
||||||
|
|
||||||
|
Move(PBytesArray(BUFFER)^[P], TIM^.IMAGE^, cIMAGEHeadSize);
|
||||||
|
|
||||||
|
if not CheckIMAGE(TIM) then
|
||||||
|
Exit;
|
||||||
|
if not CheckTIMSize(TIM) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
TIM^.dwSize := GetTIMSize(TIM);
|
||||||
|
TIM^.bGOOD := TIMIsGood(TIM);
|
||||||
|
|
||||||
|
Move(PBytesArray(BUFFER)^[TIM_POS], TIM^.DATA^[0], TIM^.dwSize);
|
||||||
|
|
||||||
|
Result := True;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LoadTimFromCDFile(const FileName: string; var Position: DWORD;
|
||||||
|
SIZE: DWORD): PTIM;
|
||||||
|
var
|
||||||
|
TimOffsetInSector, FirstPartSize, LastPartSize: DWORD;
|
||||||
|
TimSectorNumber, TimStartSectorPos: DWORD;
|
||||||
|
TIM_BUF: PTIMDataArray;
|
||||||
|
sImageStream: TFileStream;
|
||||||
|
Sector: TCDSector;
|
||||||
|
P, TIM_FULL_SECTORS: DWORD;
|
||||||
|
begin
|
||||||
|
sImageStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
|
||||||
|
|
||||||
|
TimSectorNumber := Position div cSectorSize + 1;
|
||||||
|
TimOffsetInSector := Position mod cSectorSize - cSectorInfoSize;
|
||||||
|
TimStartSectorPos := (TimSectorNumber - 1) * cSectorSize;
|
||||||
|
FirstPartSize := cSectorDataSize - TimOffsetInSector;
|
||||||
|
|
||||||
|
New(TIM_BUF);
|
||||||
|
P := 0;
|
||||||
|
|
||||||
|
if SIZE < FirstPartSize then
|
||||||
|
FirstPartSize := SIZE;
|
||||||
|
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
sImageStream.Read(Sector, cSectorSize);
|
||||||
|
|
||||||
|
Move(Sector.dwData[TimOffsetInSector], TIM_BUF^[P], FirstPartSize);
|
||||||
|
Inc(P, FirstPartSize);
|
||||||
|
|
||||||
|
Inc(TimStartSectorPos, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
|
||||||
|
TIM_FULL_SECTORS := (SIZE - P) div cSectorDataSize;
|
||||||
|
|
||||||
|
while TIM_FULL_SECTORS > 0 do
|
||||||
|
begin
|
||||||
|
sImageStream.Read(Sector, cSectorSize);
|
||||||
|
|
||||||
|
Move(Sector.dwData[0], TIM_BUF^[P], cSectorDataSize);
|
||||||
|
Inc(P, cSectorDataSize);
|
||||||
|
|
||||||
|
Inc(TimStartSectorPos, cSectorSize);
|
||||||
|
sImageStream.Seek(TimStartSectorPos, soBeginning);
|
||||||
|
|
||||||
|
Dec(TIM_FULL_SECTORS);
|
||||||
|
end;
|
||||||
|
|
||||||
|
sImageStream.Read(Sector, cSectorSize);
|
||||||
|
|
||||||
|
if SIZE > P then
|
||||||
|
begin
|
||||||
|
LastPartSize := SIZE - P;
|
||||||
|
Move(Sector.dwData[0], TIM_BUF^[P], LastPartSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
P := 0;
|
||||||
|
Result := nil;
|
||||||
|
LoadTimFromBuf(TIM_BUF, Result, P);
|
||||||
|
sImageStream.Free;
|
||||||
|
Dispose(TIM_BUF);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LoadTimFromStream(Stream: TStream; var Position: DWORD;
|
||||||
|
dwSize: DWORD): PTIM;
|
||||||
|
var
|
||||||
|
BUF: PTIMDataArray;
|
||||||
|
P: DWORD;
|
||||||
|
begin
|
||||||
|
Result := nil;
|
||||||
|
|
||||||
|
if dwSize > cTIMMaxSize then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
New(BUF);
|
||||||
|
Result := CreateTIM;
|
||||||
|
|
||||||
|
Stream.Seek(Position, soBeginning);
|
||||||
|
Stream.Read(BUF^[0], dwSize);
|
||||||
|
|
||||||
|
P := 0;
|
||||||
|
if not LoadTimFromBuf(BUF, Result, P) then
|
||||||
|
FreeTIM(Result);
|
||||||
|
|
||||||
|
Dispose(BUF);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function LoadTimFromFile(const FileName: string; var Position: DWORD;
|
||||||
|
ImageScan: Boolean; dwSize: DWORD): PTIM;
|
||||||
|
var
|
||||||
|
sTIM: TFileStream;
|
||||||
|
begin
|
||||||
|
if not ImageScan then
|
||||||
|
begin
|
||||||
|
sTIM := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
|
||||||
|
Result := LoadTimFromStream(sTIM, Position, dwSize);
|
||||||
|
sTIM.Free;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Result := LoadTimFromCDFile(FileName, Position, dwSize);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure SaveTimToFile(const FileName: string; TIM: PTIM);
|
||||||
|
var
|
||||||
|
tmp: TMemoryStream;
|
||||||
|
begin
|
||||||
|
if TIM = nil then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
tmp := TMemoryStream.Create;
|
||||||
|
tmp.Write(TIM^.DATA^[0], TIM^.dwSize);
|
||||||
|
tmp.SaveToFile(FileName);
|
||||||
|
tmp.Free;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CreateTIM: PTIM;
|
||||||
|
begin
|
||||||
|
New(Result);
|
||||||
|
|
||||||
|
New(Result^.HEAD);
|
||||||
|
New(Result^.CLUT);
|
||||||
|
New(Result^.IMAGE);
|
||||||
|
Result^.dwSize := 0;
|
||||||
|
Result^.dwTimPosition := 0;
|
||||||
|
Result^.dwTimNumber := 0;
|
||||||
|
Result^.bGOOD := False;
|
||||||
|
New(Result^.DATA);
|
||||||
|
ClearTIM(Result);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure FreeTIM(TIM: PTIM);
|
||||||
|
begin
|
||||||
|
Dispose(TIM^.HEAD);
|
||||||
|
TIM^.HEAD := nil;
|
||||||
|
Dispose(TIM^.CLUT);
|
||||||
|
TIM^.CLUT := nil;
|
||||||
|
Dispose(TIM^.IMAGE);
|
||||||
|
TIM^.IMAGE := nil;
|
||||||
|
Dispose(TIM^.DATA);
|
||||||
|
TIM^.DATA := nil;
|
||||||
|
Dispose(TIM);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function BppToBitMode(TIM: PTIM): byte;
|
||||||
|
begin
|
||||||
|
Result := 4;
|
||||||
|
if (TIM^.HEAD^.bBPP in cTIM4) then
|
||||||
|
begin
|
||||||
|
Result := 4;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
if (TIM^.HEAD^.bBPP in cTIM8) then
|
||||||
|
begin
|
||||||
|
Result := 8;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
if (TIM^.HEAD^.bBPP in cTIM16) then
|
||||||
|
begin
|
||||||
|
Result := 16;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
if (TIM^.HEAD^.bBPP in cTIM24) then
|
||||||
|
begin
|
||||||
|
Result := 24;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
if (TIM^.HEAD^.bBPP = cTIMMix) then
|
||||||
|
begin
|
||||||
|
Result := 16;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimVersion(TIM: PTIM): byte;
|
||||||
|
begin
|
||||||
|
Result := TIM^.HEAD^.bVersion;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimWidth(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.IMAGE^.wWidth;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimRealWidth(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := IWidthToRWidth(TIM);
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimColorsCount(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.CLUT^.wColorsCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimClutsCount(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.CLUT^.wClutsCount;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimBPP(TIM: PTIM): DWORD;
|
||||||
|
begin
|
||||||
|
Result := TIM^.HEAD^.bBPP;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimClutSizeHeader(TIM: PTIM): DWORD;
|
||||||
|
begin
|
||||||
|
Result := TIM^.CLUT^.dwSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimClutVRAMX(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.CLUT^.wVRAMX;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimClutVRAMY(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.CLUT^.wVRAMY;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimImageSizeHeader(TIM: PTIM): DWORD;
|
||||||
|
begin
|
||||||
|
Result := TIM^.IMAGE^.dwSize;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimImageVRAMX(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.IMAGE^.wVRAMX;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetTimImageVRAMY(TIM: PTIM): word;
|
||||||
|
begin
|
||||||
|
Result := TIM^.IMAGE^.wVRAMY;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
Reference in New Issue
Block a user