lazarus-ccr/wst/trunk/binary_streamer.pas
inoussa 2e55ad976d UnicodeString Fix
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1482 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2011-02-02 15:34:13 +00:00

696 lines
17 KiB
ObjectPascal

{
This file is part of the Web Service Toolkit
Copyright (c) 2006 by Inoussa OUEDRAOGO
This file is provide under modified LGPL licence
( the files COPYING.modifiedLGPL and COPYING.LGPL).
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
{$INCLUDE wst_global.inc}
{$RANGECHECKS OFF}
unit binary_streamer;
interface
uses
Classes, SysUtils, Types, wst_types;
Const
MAX_ARRAY_LENGTH = 1024*1024;
Type
TInt8U = Byte; TInt8S = ShortInt;
TInt16U = Word; TInt16S = SmallInt;
TInt32U = LongWord; TInt32S = LongInt;
TInt64S = Int64; TInt64U = QWord;
TBoolData = Boolean;
TEnumData = Int64;
TAnsiStringData = TBinaryString;
TWideStringData = WideString;
{$IFDEF WST_UNICODESTRING}
TUnicodeStringData = UnicodeString;
{$ELSE WST_UNICODESTRING}
UnicodeString = WideString;
TUnicodeStringData = UnicodeString;
UnicodeChar = WideChar;
{$ENDIF WST_UNICODESTRING}
TAnsiCharacter = AnsiChar;
TWideCharacter = WideChar;
TByteDynArray = wst_types.TByteDynArray;
TFloat_Single_4 = Single;
TFloat_Double_8 = Double;
TFloat_Extended_10 = Extended;
TFloat_Currency_8 = Currency;
IDataStore = Interface
['{CA767A0E-7660-4765-9959-6960A69B1660}']
procedure WriteInt8U(Const AData : TInt8U);
procedure WriteInt8S(Const AData : TInt8S);
procedure WriteInt16U(Const AData : TInt16U);
procedure WriteInt16S(Const AData : TInt16S);
procedure WriteInt32U(Const AData : TInt32U);
procedure WriteInt32S(Const AData : TInt32S);
procedure WriteInt64U(Const AData : TInt64U);
procedure WriteInt64S(Const AData : TInt64S);
procedure WriteBool(Const AData : TBoolData);
procedure WriteAnsiChar(const AData : TAnsiCharacter);
procedure WriteWideChar(const AData : TWideCharacter);
procedure WriteEnum(Const AData : TEnumData);
procedure WriteAnsiStr(Const AData : TAnsiStringData);
procedure WriteWideStr(Const AData : TWideStringData);
{ $IFDEF WST_UNICODESTRING}
procedure WriteUnicodeStr(Const AData : TUnicodeStringData);
{ $ENDIF WST_UNICODESTRING}
procedure WriteBinary(const AData : TByteDynArray);
procedure WriteSingle(Const AData : TFloat_Single_4);
procedure WriteDouble(Const AData : TFloat_Double_8);
procedure WriteExtended(Const AData : TFloat_Extended_10);
procedure WriteCurrency(Const AData : TFloat_Currency_8);
End;
IDataStoreReader = Interface
['{AF50317E-6DD6-40C5-A2F6-3ED5F478564F}']
function IsAtEof():Boolean;
function ReadInt8U():TInt8U;
function ReadInt8S():TInt8S;
function ReadInt16U():TInt16U;
function ReadInt16S():TInt16S;
function ReadInt32U():TInt32U;
function ReadInt32S():TInt32S;
function ReadInt64U():TInt64U;
function ReadInt64S():TInt64S;
function ReadBool():TBoolData;
function ReadAnsiChar() : TAnsiCharacter;
function ReadWideChar() : TWideCharacter;
function ReadEnum():TEnumData;
function ReadAnsiStr():TAnsiStringData;
function ReadWideStr():TWideStringData;
{ $IFDEF WST_UNICODESTRING}
function ReadUnicodeStr():TUnicodeStringData;
{ $ENDIF WST_UNICODESTRING}
function ReadBinary() : TByteDynArray;
function ReadSingle():TFloat_Single_4;
function ReadDouble():TFloat_Double_8;
function ReadExtended():TFloat_Extended_10;
function ReadCurrency():TFloat_Currency_8;
End;
function CreateBinaryReader(AStream : TStream):IDataStoreReader;
function CreateBinaryWriter(AStream : TStream):IDataStore;
{These routines transform their argument to "Big Endian" alignment}
procedure ReverseBytes(var AData; const ALength : Integer);{$IFDEF USE_INLINE}{$IFDEF ENDIAN_BIG}inline;{$ENDIF}{$ENDIF}
function Reverse_16(const AValue:Word):Word;{$IFDEF USE_INLINE}inline;{$ENDIF}
function Reverse_32(const AValue:DWord):DWord;{$IFDEF USE_INLINE}inline;{$ENDIF}
function Reverse_64(const AValue:QWord):QWord;{$IFDEF USE_INLINE}inline;{$ENDIF}
function Reverse_Single(const AValue:Single):Single;{$IFDEF USE_INLINE}inline;{$ENDIF}
function Reverse_Double(const AValue:Double):Double;{$IFDEF USE_INLINE}inline;{$ENDIF}
function Reverse_Extended(const AValue:Extended):Extended;{$IFDEF USE_INLINE}inline;{$ENDIF}
function Reverse_Currency(const AValue:Currency):Currency;{$IFDEF USE_INLINE}inline;{$ENDIF}
implementation
{$IFDEF ENDIAN_BIG}
procedure ReverseBytes(var AData; const ALength : Integer); {$IFDEF USE_INLINE}inline;{$ENDIF}
begin
end;
{$ELSE} // assume ENDIAN_LITTLE
procedure ReverseBytes(var AData; const ALength : Integer);
Var
i,j : PtrInt;
c : Byte;
pDt : {$IFDEF FPC}^Byte{$ELSE}PByteArray{$ENDIF};
begin
pDt := @AData;
j := ALength div 2;
For i := 0 To Pred(j) Do Begin
c := pDt{$IFNDEF FPC}^{$ENDIF}[i];
pDt[i] := pDt[(ALength - 1 ) - i];
pDt[(ALength - 1 ) - i] := c;
End;
end;
{$ENDIF}
function Reverse_16(const AValue:Word):Word;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,2)
end;
function Reverse_32(const AValue:DWord):DWord;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,4)
end;
function Reverse_64(const AValue:QWord):QWord;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,8)
end;
function Reverse_Single(const AValue:Single):Single;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,4)
end;
function Reverse_Double(const AValue:Double):Double;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,8)
end;
function Reverse_Extended(const AValue:Extended):Extended;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,10);
end;
function Reverse_Currency(const AValue:Currency):Currency;{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AValue;
ReverseBytes(Result,8);
end;
{$IFDEF ENDIAN_BIG}
procedure Reverse_Array(var AValue; const AArrayLength, AItemSize : PtrInt);{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
end;
{$ELSE ENDIAN_BIG}
procedure Reverse_Array(var AValue; const AArrayLength, AItemSize : PtrInt);
var
p : PByte;
i : PtrInt;
begin
if ( AArrayLength > 0 ) and ( AItemSize > 1 ) then begin
p := @AValue;
for i := 0 to Pred(AArrayLength) do begin
ReverseBytes(p^,AItemSize);
Inc(p,AItemSize);
end;
end;
end;
{$ENDIF ENDIAN_BIG}
Type
{ TDataStore }
TDataStore = class(TInterfacedObject,IDataStore)
Private
FStream : TStream;
Protected
procedure WriteInt8U(Const AData : TInt8U);
procedure WriteInt8S(Const AData : TInt8S);
procedure WriteInt16U(Const AData : TInt16U);
procedure WriteInt16S(Const AData : TInt16S);
procedure WriteInt32U(Const AData : TInt32U);
procedure WriteInt32S(Const AData : TInt32S);
procedure WriteInt64U(Const AData : TInt64U);
procedure WriteInt64S(Const AData : TInt64S);
procedure WriteBool(Const AData : TBoolData);
procedure WriteAnsiChar(const AData : TAnsiCharacter);
procedure WriteWideChar(const AData : TWideCharacter);
procedure WriteEnum(Const AData : TEnumData);
procedure WriteAnsiStr(Const AData : TAnsiStringData);
procedure WriteWideStr(Const AData : TWideStringData);
{ $IFDEF WST_UNICODESTRING}
procedure WriteUnicodeStr(Const AData : TUnicodeStringData);
{ $ENDIF WST_UNICODESTRING}
procedure WriteBinary(const AData : TByteDynArray);
procedure WriteSingle(Const AData : TFloat_Single_4);
procedure WriteDouble(Const AData : TFloat_Double_8);
procedure WriteExtended(Const AData : TFloat_Extended_10);
procedure WriteCurrency(Const AData : TFloat_Currency_8);
Public
constructor Create(AStream : TStream);
End;
{ TDataStoreReader }
TDataStoreReader = class(TInterfacedObject,IDataStoreReader)
Private
FStream : TStream;
Protected
function IsAtEof():Boolean;
function ReadInt8U():TInt8U;
function ReadInt8S():TInt8S;
function ReadInt16U():TInt16U;
function ReadInt16S():TInt16S;
function ReadInt32U():TInt32U;
function ReadInt32S():TInt32S;
function ReadInt64U():TInt64U;
function ReadInt64S():TInt64S;
function ReadBool():TBoolData;
function ReadAnsiChar() : TAnsiCharacter;
function ReadWideChar() : TWideCharacter;
function ReadEnum():TEnumData;
function ReadAnsiStr():TAnsiStringData;
function ReadWideStr():TWideStringData;
{ $IFDEF WST_UNICODESTRING}
function ReadUnicodeStr():TUnicodeStringData;
{ $ENDIF WST_UNICODESTRING}
function ReadBinary() : TByteDynArray;
function ReadSingle():TFloat_Single_4;
function ReadDouble():TFloat_Double_8;
function ReadExtended():TFloat_Extended_10;
function ReadCurrency():TFloat_Currency_8;
Public
constructor Create(AStream : TStream);
End;
function CreateBinaryWriter(AStream : TStream):IDataStore;
begin
Result := TDataStore.Create(AStream) As IDataStore;
end;
function CreateBinaryReader(AStream : TStream):IDataStoreReader;
begin
Result := TDataStoreReader.Create(AStream) As IDataStoreReader;
end;
{ TDataStore }
procedure TDataStore.WriteInt8U(const AData: TInt8U);
begin
FStream.Write(AData,SizeOf(AData));
end;
procedure TDataStore.WriteInt8S(const AData: TInt8S);
begin
FStream.Write(AData,SizeOf(AData));
end;
{$IFDEF FPC}
procedure TDataStore.WriteInt16U(const AData: TInt16U);
begin
FStream.Write(Reverse_16(AData),SizeOf(AData));
end;
procedure TDataStore.WriteInt16S(const AData: TInt16S);
begin
FStream.Write(Reverse_16(AData),SizeOf(AData));
end;
procedure TDataStore.WriteInt32U(const AData: TInt32U);
begin
FStream.Write(Reverse_32(AData),SizeOf(AData));
end;
procedure TDataStore.WriteInt32S(const AData: TInt32S);
begin
FStream.Write(Reverse_32(AData),SizeOf(AData));
end;
procedure TDataStore.WriteInt64U(const AData: TInt64U);
begin
FStream.Write(Reverse_64(AData),SizeOf(AData));
end;
procedure TDataStore.WriteInt64S(const AData: TInt64S);
begin
FStream.Write(Reverse_64(AData),SizeOf(AData));
end;
{$ELSE}
procedure TDataStore.WriteInt16U(const AData: TInt16U);
var
bffr : TInt16U;
begin
bffr := Reverse_16(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteInt16S(const AData: TInt16S);
var
bffr : TInt16U;
begin
bffr := Reverse_16(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteInt32U(const AData: TInt32U);
var
bffr : TInt32U;
begin
bffr := Reverse_32(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteInt32S(const AData: TInt32S);
var
bffr : TInt32U;
begin
bffr := Reverse_32(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteInt64U(const AData: TInt64U);
var
bffr : TInt64U;
begin
bffr := Reverse_64(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteInt64S(const AData: TInt64S);
var
bffr : TInt64U;
begin
bffr := Reverse_64(AData);
FStream.Write(bffr,SizeOf(AData));
end;
{$ENDIF}
procedure TDataStore.WriteBool(const AData: TBoolData);
Var
i : TInt8U;
begin
If AData Then
i := 1
Else
i := 0;
WriteInt8U(i);
end;
procedure TDataStore.WriteAnsiChar(const AData: TAnsiCharacter);
begin
WriteInt8U(Ord(AData));
end;
procedure TDataStore.WriteWideChar(const AData: TWideCharacter);
begin
WriteInt16U(Ord(AData));
end;
procedure TDataStore.WriteEnum(const AData: TEnumData);
begin
WriteInt64S(AData);
end;
procedure TDataStore.WriteAnsiStr(const AData: TAnsiStringData);
Var
i : TInt32S;
begin
i := Length(AData);
WriteInt32S(i);
If ( i > 0 ) Then
FStream.Write(AData[1],i);
end;
procedure TDataStore.WriteWideStr(const AData: TWideStringData);
procedure LocalWrite();
var
locData : TWideStringData;
begin
locData := AData;
UniqueString(locData);
Reverse_Array(Pointer(locData)^,Length(locData),SizeOf(WideChar));
FStream.Write(Pointer(locData)^, ( Length(locData) * SizeOf(WideChar) ) );
end;
var
i : TInt32S;
begin
i := Length(AData);
WriteInt32S(i);
if ( i > 0 ) then begin
LocalWrite();
end;
end;
procedure TDataStore.WriteBinary(const AData : TByteDynArray);
var
i : TInt32S;
begin
i := Length(AData);
WriteInt32S(i);
if ( i > 0 ) then
FStream.Write(AData[0],i);
end;
{ $IFDEF WST_UNICODESTRING}
procedure TDataStore.WriteUnicodeStr(const AData: TUnicodeStringData);
procedure LocalWrite();
var
locData : TUnicodeStringData;
begin
locData := AData;
UniqueString(locData);
Reverse_Array(Pointer(locData)^,Length(locData),SizeOf(UnicodeChar));
FStream.Write(Pointer(locData)^, ( Length(locData) * SizeOf(UnicodeChar) ) );
end;
var
i : TInt32S;
begin
i := Length(AData);
WriteInt32S(i);
if ( i > 0 ) then begin
LocalWrite();
end;
end;
{ $ENDIF WST_UNICODESTRING}
{
procedure TDataStore.WriteSingle(const AData: TFloat_Single_4);
begin
FStream.Write(Reverse_Single(AData),SizeOf(AData));
end;
procedure TDataStore.WriteDouble(const AData: TFloat_Double_8);
begin
FStream.Write(Reverse_Double(AData),SizeOf(AData));
end;
procedure TDataStore.WriteExtended(const AData: TFloat_Extended_10);
begin
FStream.Write(Reverse_Extended(AData),SizeOf(AData));
end;
procedure TDataStore.WriteCurrency(const AData: TFloat_Currency_8);
begin
FStream.Write(Reverse_Currency(AData),SizeOf(AData));
end;
}
procedure TDataStore.WriteSingle(const AData: TFloat_Single_4);
var
bffr : TFloat_Single_4;
begin
bffr := Reverse_Single(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteDouble(const AData: TFloat_Double_8);
var
bffr : TFloat_Double_8;
begin
bffr := Reverse_Double(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteExtended(const AData: TFloat_Extended_10);
var
bffr : TFloat_Extended_10;
begin
bffr := Reverse_Extended(AData);
FStream.Write(bffr,SizeOf(AData));
end;
procedure TDataStore.WriteCurrency(const AData: TFloat_Currency_8);
var
bffr : TFloat_Currency_8;
begin
bffr := Reverse_Currency(AData);
FStream.Write(bffr,SizeOf(AData));
end;
constructor TDataStore.Create(AStream: TStream);
begin
Assert(Assigned(AStream));
FStream := AStream;
end;
{ TDataStoreReader }
function TDataStoreReader.IsAtEof(): Boolean;
begin
Result := ( FStream.Position >= FStream.Size );
end;
{$HINTS OFF}
function TDataStoreReader.ReadInt8U(): TInt8U;
begin
FStream.Read(Result,SizeOf(Result));
end;
function TDataStoreReader.ReadInt8S(): TInt8S;
begin
FStream.Read(Result,SizeOf(Result));
end;
function TDataStoreReader.ReadInt16U(): TInt16U;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_16(Result);
end;
function TDataStoreReader.ReadInt16S(): TInt16S;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_16(Result);
end;
function TDataStoreReader.ReadInt32U(): TInt32U;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_32(Result);
end;
function TDataStoreReader.ReadInt32S(): TInt32S;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_32(Result);
end;
function TDataStoreReader.ReadInt64U(): TInt64U;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_64(Result);
end;
function TDataStoreReader.ReadInt64S(): TInt64S;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_64(Result);
end;
{$HINTS ON}
function TDataStoreReader.ReadBool(): TBoolData;
begin
Result := ( ReadInt8U() > 0 );
end;
function TDataStoreReader.ReadAnsiChar(): TAnsiCharacter;
begin
Result := TAnsiCharacter(ReadInt8U());
end;
function TDataStoreReader.ReadWideChar(): TWideCharacter;
begin
Result := TWideCharacter(ReadInt16U());
end;
function TDataStoreReader.ReadEnum(): TEnumData;
begin
Result := ReadInt64S();
end;
function TDataStoreReader.ReadAnsiStr(): TAnsiStringData;
Var
i : TInt32S;
begin
i := ReadInt32S();
SetLength(Result,i);
If ( i > 0 ) Then
FStream.ReadBuffer(Result[1],i);
end;
function TDataStoreReader.ReadWideStr(): TWideStringData;
var
i : TInt32S;
begin
i := ReadInt32S();
SetLength(Result,i);
if ( i > 0 ) then begin
FStream.ReadBuffer(Pointer(Result)^, ( i * SizeOf(WideChar) ) );
Reverse_Array(Pointer(Result)^,i,SizeOf(WideChar));
end;
end;
function TDataStoreReader.ReadBinary() : TByteDynArray;
var
i : TInt32S;
begin
i := ReadInt32S();
SetLength(Result,i);
if ( i > 0 ) then
FStream.ReadBuffer(Result[0],i);
end;
{ $IFDEF WST_UNICODESTRING}
function TDataStoreReader.ReadUnicodeStr(): TUnicodeStringData;
var
i : TInt32S;
begin
i := ReadInt32S();
SetLength(Result,i);
if ( i > 0 ) then begin
FStream.ReadBuffer(Pointer(Result)^, ( i * SizeOf(UnicodeChar) ) );
Reverse_Array(Pointer(Result)^,i,SizeOf(UnicodeChar));
end;
end;
{ $ENDIF WST_UNICODESTRING}
{$HINTS OFF}
function TDataStoreReader.ReadSingle(): TFloat_Single_4;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_Single(Result);
end;
function TDataStoreReader.ReadDouble(): TFloat_Double_8;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_Double(Result);
end;
function TDataStoreReader.ReadExtended(): TFloat_Extended_10;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_Extended(Result);
end;
function TDataStoreReader.ReadCurrency(): TFloat_Currency_8;
begin
FStream.Read(Result,SizeOf(Result));
Result := Reverse_Currency(Result);
end;
{$HINTS ON}
constructor TDataStoreReader.Create(AStream: TStream);
begin
Assert(Assigned(AStream));
FStream := AStream;
end;
end.