499 lines
11 KiB
Plaintext
499 lines
11 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.Serializer }
|
|
{ }
|
|
{ Copyright (C) 2022 sunk }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.Serializer;
|
|
|
|
interface
|
|
|
|
uses
|
|
Tocsg.Obj, System.Classes, System.SysUtils, Winapi.Windows,
|
|
Tocsg.Exception;
|
|
|
|
const
|
|
SER_SIG: AnsiString = 'KzSer.';
|
|
SER_VER = 1;
|
|
|
|
type
|
|
TTgSerHeader = packed record
|
|
sSig: array [0..11] of AnsiChar;
|
|
nVer: Integer;
|
|
end;
|
|
|
|
ETgSerializer = class(ETgException);
|
|
TTgSerializerBase = class(TTgObject)
|
|
private
|
|
bStreamFree_: Boolean;
|
|
protected
|
|
Header_: TTgSerHeader;
|
|
Stream_: TStream;
|
|
function GetPosition: LONGLONG;
|
|
function GetSize: LONGLONG;
|
|
public
|
|
Constructor Create(aStream: TStream; bAutoStreamFree: Boolean = false); overload;
|
|
Constructor Create; overload;
|
|
Destructor Destroy; override;
|
|
|
|
procedure SeekFront;
|
|
procedure SeekEnd;
|
|
|
|
property Stream: TStream read Stream_;
|
|
property Header: TTgSerHeader read Header_;
|
|
end;
|
|
|
|
TTgSerializerSave = class(TTgSerializerBase)
|
|
public
|
|
procedure SaveHeader(nVer: Integer = SER_VER);
|
|
procedure S_WideString(sVal: WideString);
|
|
procedure S_AnsiString(sVal: AnsiString);
|
|
procedure S_UTF8String(sVal: UTF8String);
|
|
|
|
procedure S_Integer(nVal: Integer);
|
|
procedure S_DWORD(dwVal: DWORD);
|
|
procedure S_WORD(wVal: WORD);
|
|
procedure S_LONGLONG(llVal: LONGLONG);
|
|
procedure S_ULONGLONG(ullVal: ULONGLONG);
|
|
procedure S_DateTime(dtVal: TDateTime);
|
|
procedure S_Strings(aList: TStrings);
|
|
procedure S_Boolean(bVal: Boolean);
|
|
procedure S_Stream(aStream: TStream);
|
|
|
|
procedure SaveToFile(sPath: String);
|
|
end;
|
|
|
|
TTgSerializerLoad = class(TTgSerializerSave)
|
|
public
|
|
function LoadHeader: Boolean;
|
|
function L_WideString: WideString;
|
|
function L_AnsiString: AnsiString;
|
|
function L_UTF8String: UTF8String;
|
|
|
|
function L_Integer: Integer;
|
|
function L_DWORD: DWORD;
|
|
function L_WORD: WORD;
|
|
function L_LONGLONG: LONGLONG;
|
|
function L_ULONGLONG: ULONGLONG;
|
|
function L_DateTime: TDateTime;
|
|
function L_Strings(aList: TStrings): Integer;
|
|
function L_Boolean: Boolean;
|
|
function L_Stream(aStream: TStream): LONGLONG;
|
|
|
|
function IsEndOfFile: Boolean;
|
|
function GetRemainSize: LONGLONG;
|
|
function GetReadPercent: WORD;
|
|
|
|
procedure LoadFromFile(sPath: String);
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TTgSerializerBase }
|
|
|
|
Constructor TTgSerializerBase.Create(aStream: TStream; bAutoStreamFree: Boolean = false);
|
|
begin
|
|
Inherited Create;
|
|
ZeroMemory(@Header_, SizeOf(Header_));
|
|
bStreamFree_ := bAutoStreamFree;
|
|
Stream_ := aStream;
|
|
if Stream_ = nil then
|
|
raise ETgSerializer.Create('스트림이 지정되지 않았습니다.');
|
|
end;
|
|
|
|
Constructor TTgSerializerBase.Create;
|
|
begin
|
|
Inherited Create;
|
|
ZeroMemory(@Header_, SizeOf(Header_));
|
|
Stream_ := TMemoryStream.Create;
|
|
bStreamFree_ := true;
|
|
end;
|
|
|
|
Destructor TTgSerializerBase.Destroy;
|
|
begin
|
|
if (Stream_ <> nil) and bStreamFree_ then
|
|
FreeAndNil(Stream_);
|
|
Inherited;
|
|
end;
|
|
|
|
function TTgSerializerBase.GetPosition: LONGLONG;
|
|
begin
|
|
Result := Stream_.Position;
|
|
end;
|
|
|
|
function TTgSerializerBase.GetSize: LONGLONG;
|
|
begin
|
|
Result := Stream_.Size;
|
|
end;
|
|
|
|
procedure TTgSerializerBase.SeekFront;
|
|
begin
|
|
Stream_.Seek(0, soBeginning);
|
|
end;
|
|
|
|
procedure TTgSerializerBase.SeekEnd;
|
|
begin
|
|
Stream_.Seek(0, soEnd)
|
|
end;
|
|
|
|
{ TTgSerializerSave }
|
|
|
|
procedure TTgSerializerSave.SaveHeader(nVer: Integer = SER_VER);
|
|
begin
|
|
if Stream_.Position > 0 then
|
|
raise Exception.Create('offset 값이 0보다 큽니다.');
|
|
|
|
if Length(SER_SIG) > SizeOf(Header_.sSig) then
|
|
raise Exception.Create('시그너처 길이가 너무 큽니다.');
|
|
|
|
ZeroMemory(@Header_.sSig, SizeOf(Header_.sSig));
|
|
CopyMemory(@Header_.sSig[0], @SER_SIG[1], Length(SER_SIG));
|
|
Header_.nVer := nVer;
|
|
|
|
Stream_.Write(Header_, SizeOf(Header_));
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_WideString(sVal: WideString);
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
nLen := Length(sVal) * 2;
|
|
S_Integer(nLen);
|
|
Stream_.Write(PWideChar(sVal)^, nLen);
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_AnsiString(sVal: AnsiString);
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
nLen := Length(sVal);
|
|
S_Integer(nLen);
|
|
Stream_.Write(PAnsiChar(sVal)^, nLen);
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_UTF8String(sVal: UTF8String);
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
nLen := Length(sVal);
|
|
S_Integer(nLen);
|
|
Stream_.Write(PUTF8String(sVal)^, nLen);
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_Integer(nVal: Integer);
|
|
begin
|
|
try
|
|
Stream_.Write(nVal, SizeOf(nVal));
|
|
except
|
|
_Trace('Fail .. S_Integer()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_DWORD(dwVal: DWORD);
|
|
begin
|
|
try
|
|
Stream_.Write(dwVal, SizeOf(dwVal));
|
|
except
|
|
_Trace('Fail .. S_DWORD()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_WORD(wVal: WORD);
|
|
begin
|
|
try
|
|
Stream_.Write(wVal, SizeOf(wVal));
|
|
except
|
|
_Trace('Fail .. S_WORD()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_LONGLONG(llVal: LONGLONG);
|
|
begin
|
|
try
|
|
Stream_.Write(llVal, SizeOf(llVal));
|
|
except
|
|
_Trace('Fail .. S_LONGLONG()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_ULONGLONG(ullVal: ULONGLONG);
|
|
begin
|
|
try
|
|
Stream_.Write(ullVal, SizeOf(ullVal));
|
|
except
|
|
_Trace('Fail .. S_ULONGLONG()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_DateTime(dtVal: TDateTime);
|
|
begin
|
|
try
|
|
Stream_.Write(dtVal, SizeOf(dtVal));
|
|
except
|
|
_Trace('Fail .. S_DateTime()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_Strings(aList: TStrings);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
try
|
|
S_Integer(aList.Count);
|
|
for i := 0 to aList.Count - 1 do
|
|
S_UTF8String(aList[i]);
|
|
except
|
|
_Trace('Fail .. S_Strings()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_Boolean(bVal: Boolean);
|
|
begin
|
|
try
|
|
Stream_.Write(bVal, SizeOf(bVal));
|
|
except
|
|
_Trace('Fail .. S_Boolean()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.S_Stream(aStream: TStream);
|
|
begin
|
|
try
|
|
aStream.Position := 0;
|
|
S_LONGLONG(aStream.Size);
|
|
Stream_.CopyFrom(aStream, aStream.Size);
|
|
except
|
|
_Trace('Fail .. S_Stream()');
|
|
end;
|
|
end;
|
|
|
|
procedure TTgSerializerSave.SaveToFile(sPath: String);
|
|
begin
|
|
if not (Stream_ is TMemoryStream) then
|
|
raise ETgSerializer.Create('Stream이 TMemoryStream가 아닙니다.');
|
|
|
|
try
|
|
TMemoryStream(Stream_).SaveToFile(sPath);
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(Self, E, 'Fail .. SaveToFile()');
|
|
end;
|
|
end;
|
|
|
|
{ TTgSerializerLoad }
|
|
|
|
function TTgSerializerLoad.LoadHeader: Boolean;
|
|
begin
|
|
Result := false;
|
|
|
|
ZeroMemory(@Header_, SizeOf(Header_));
|
|
|
|
if Stream_.Position > 0 then
|
|
raise Exception.Create('offset 값이 0보다 큽니다.');
|
|
|
|
try
|
|
if Stream_.Read(Header_, SizeOf(Header_)) <> SizeOf(Header_) then
|
|
exit;
|
|
|
|
// 크기 체크 추가 19_0710 17:01:52 kku
|
|
Result := (Stream_.Size > Stream_.Position) and
|
|
CompareMem(@Header_.sSig[0], @SER_SIG[1], Length(SER_SIG));
|
|
finally
|
|
if not Result then
|
|
Stream_.Position := 0;
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_WideString: WideString;
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
Result := '';
|
|
try
|
|
nLen := L_Integer;
|
|
if nLen = 0 then
|
|
exit;
|
|
|
|
if nLen > GetRemainSize then
|
|
exit;
|
|
// raise ETgSerializer.Create('남은 데이터가 부족합니다.');
|
|
|
|
SetLength(Result, nLen div 2);
|
|
Stream_.Read(Result[1], nLen);
|
|
except
|
|
_Trace('Fail .. L_WideString()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_AnsiString: AnsiString;
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
Result := '';
|
|
try
|
|
nLen := L_Integer;
|
|
if nLen = 0 then
|
|
exit;
|
|
|
|
if nLen > GetRemainSize then
|
|
exit;
|
|
// raise ETgSerializer.Create('남은 데이터가 부족합니다.');
|
|
|
|
SetLength(Result, nLen);
|
|
Stream_.Read(Result[1], nLen);
|
|
except
|
|
_Trace('Fail .. L_AnsiString()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_UTF8String: UTF8String;
|
|
var
|
|
nLen: Integer;
|
|
begin
|
|
Result := '';
|
|
try
|
|
nLen := L_Integer;
|
|
if nLen = 0 then
|
|
exit;
|
|
|
|
if nLen > GetRemainSize then
|
|
exit;
|
|
// raise ETgSerializer.Create('남은 데이터가 부족합니다.');
|
|
|
|
SetLength(Result, nLen);
|
|
Stream_.Read(Result[1], nLen);
|
|
except
|
|
_Trace('Fail .. L_UTF8String()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_Integer: Integer;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_Integer()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_DWORD: DWORD;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_DWORD()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_WORD: WORD;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_WORD()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_LONGLONG: LONGLONG;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_LONGLONG()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_ULONGLONG: ULONGLONG;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_ULONGLONG()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_DateTime: TDateTime;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_DateTime()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_Strings(aList: TStrings): Integer;
|
|
var
|
|
i, nCnt: Integer;
|
|
begin
|
|
try
|
|
nCnt := L_Integer;
|
|
for i := 0 to nCnt - 1 do
|
|
aList.Add(L_UTF8String);
|
|
except
|
|
_Trace('Fail .. L_Strings()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_Boolean: Boolean;
|
|
begin
|
|
try
|
|
Stream_.Read(Result, SizeOf(Result));
|
|
except
|
|
_Trace('Fail .. L_Boolean()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.L_Stream(aStream: TStream): LONGLONG;
|
|
var
|
|
llSize: LONGLONG;
|
|
begin
|
|
try
|
|
llSize := L_LONGLONG;
|
|
if llSize > 0 then
|
|
begin
|
|
Result := aStream.CopyFrom(Stream_, llSize);
|
|
if Result <> llSize then
|
|
raise ETgSerializer.Create('남은 데이터가 부족합니다.');
|
|
end else
|
|
Result := 0;
|
|
except
|
|
_Trace('Fail .. L_Stream()');
|
|
end;
|
|
end;
|
|
|
|
function TTgSerializerLoad.IsEndOfFile: Boolean;
|
|
begin
|
|
Result := Stream_.Position >= Stream_.Size;
|
|
end;
|
|
|
|
function TTgSerializerLoad.GetRemainSize: LONGLONG;
|
|
begin
|
|
Result := Stream_.Size - Stream_.Position;
|
|
end;
|
|
|
|
function TTgSerializerLoad.GetReadPercent: WORD;
|
|
begin
|
|
if Stream_.Size > 0 then
|
|
Result := (Stream_.Position * 100) div Stream_.Size
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TTgSerializerLoad.LoadFromFile(sPath: String);
|
|
begin
|
|
if not (Stream_ is TMemoryStream) then
|
|
raise ETgSerializer.Create('Stream이 TMemoryStream가 아닙니다.');
|
|
|
|
try
|
|
TMemoryStream(Stream_).LoadFromFile(sPath);
|
|
Stream_.Position := 0;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(Self, E, 'Fail .. LoadFromFile()');
|
|
end;
|
|
end;
|
|
|
|
end.
|