source: trunk/Packages/TemplateGenerics/Additional/UBinarySerializer.pas

Last change on this file was 30, checked in by chronos, 12 years ago
  • Updated: Component versions.
  • Added: Missing forms.
File size: 9.3 KB
Line 
1unit UBinarySerializer;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, DateUtils, SpecializedList, SpecializedStream;
9
10type
11 TEndianness = (enBig, enLittle);
12
13 { TBinarySerializer }
14
15 TBinarySerializer = class
16 private
17 FGrow: Boolean;
18 FList: TListByte;
19 FEndianness: TEndianness;
20 SwapData: Boolean;
21 procedure SetList(const AValue: TListByte);
22 procedure SetEndianness(const AValue: TEndianness);
23 procedure ReverseByteOrder(var Buffer; Count: Integer);
24 public
25 Position: Integer;
26 OwnsList: Boolean;
27 procedure Write(var Buffer; Count: Integer); inline;
28 procedure Read(var Buffer; Count: Integer); inline;
29
30 procedure Assign(Source: TBinarySerializer);
31 procedure WriteByte(Data: Byte);
32 procedure WriteWord(Data: Word);
33 procedure WriteCardinal(Data: Cardinal);
34 procedure WriteInt64(Data: Int64);
35 procedure WriteString(Data: string);
36 procedure WriteShortString(Data: ShortString);
37 procedure WriteAnsiString(Data: string);
38 procedure WriteUnixTime(Data: TDateTime);
39 procedure WriteDouble(Value: Double);
40 procedure WriteSingle(Value: Single);
41 procedure WriteStream(AStream: TStreamByte; Count: Integer);
42 procedure WriteStreamPart(AStream: TStreamByte; Count: Integer);
43 procedure WriteList(List: TListByte; StartIndex, Count: Integer);
44 function ReadByte: Byte;
45 function ReadWord: Word;
46 function ReadCardinal: Cardinal;
47 function ReadInt64: Int64;
48 function ReadString(Length: Integer): string;
49 function ReadShortString: string;
50 function ReadAnsiString: string;
51 function ReadStringTerminated(Terminator: string = #0): string;
52 function ReadUnixTime: TDateTime;
53 function ReadDouble: Double;
54 function ReadSingle: Single;
55 procedure ReadStream(AStream: TStream; Count: Integer);
56 procedure ReadStreamPart(AStream: TStream; Count: Integer);
57 procedure ReadList(List: TListByte; StartIndex, Count: Integer);
58 constructor Create; overload;
59 procedure Clear;
60 destructor Destroy; override;
61 property Endianness: TEndianness read FEndianness write SetEndianness;
62 property List: TListByte read FList write SetList;
63 property Grow: Boolean read FGrow write FGrow;
64 end;
65
66
67implementation
68
69{ TBinarySerializer }
70
71function TBinarySerializer.ReadAnsiString: string;
72var
73 StringLength: Longint;
74begin
75 FList.ReadBuffer(StringLength, SizeOf(StringLength));
76 Result := ReadString(StringLength);
77end;
78
79function TBinarySerializer.ReadStringTerminated(Terminator: string = #0): string;
80var
81 Data: Char;
82 I: Integer;
83 OldPosition: Integer;
84begin
85 OldPosition := Position;
86 Result := '';
87 I := 1;
88 repeat
89 if Position >= FList.Count then Break;
90 Data := Chr(ReadByte);
91 if Data <> Terminator[I] then begin
92 Result := Result + Data;
93 I := 1;
94 end else Inc(I);
95 until I > Length(Terminator);
96 if not (I > Length(Terminator)) then begin
97 Result := '';
98 Position := OldPosition;
99 end;
100end;
101
102function TBinarySerializer.ReadByte: Byte;
103begin
104 Read(Result, SizeOf(Byte));
105end;
106
107function TBinarySerializer.ReadCardinal: Cardinal;
108begin
109 Read(Result, SizeOf(Cardinal));
110 if SwapData then Result := SwapEndian(Result);
111end;
112
113function TBinarySerializer.ReadInt64: Int64;
114begin
115 Read(Result, SizeOf(Int64));
116 if SwapData then Result := SwapEndian(Result);
117end;
118
119function TBinarySerializer.ReadString(Length: Integer): string;
120begin
121 if Length > 0 then begin
122 SetLength(Result, Length);
123 Read(Result[1], Length);
124 end else Result := '';
125end;
126
127function TBinarySerializer.ReadShortString: string;
128var
129 Count: Byte;
130begin
131 Read(Count, 1);
132 Result := ReadString(Count);
133end;
134
135procedure TBinarySerializer.ReadStream(AStream: TStream; Count: Integer);
136var
137 Buffer: array of Byte;
138begin
139 if Count > 0 then begin
140 SetLength(Buffer, Count);
141 Read(Buffer[0], Count);
142 AStream.Size := Count;
143 AStream.Position := 0;
144 AStream.Write(Buffer[0], Count);
145 end;
146end;
147
148procedure TBinarySerializer.ReadStreamPart(AStream: TStream; Count: Integer);
149var
150 Buffer: array of Byte;
151begin
152 if Count > 0 then begin
153 SetLength(Buffer, Count);
154 Read(Buffer[0], Count);
155 if AStream.Size < (AStream.Position + Count) then
156 AStream.Size := AStream.Position + Count;
157 Write(Buffer[0], Count);
158 end;
159end;
160
161procedure TBinarySerializer.ReadList(List: TListByte; StartIndex, Count: Integer
162 );
163var
164 Buffer: array of Byte;
165begin
166 if Count > (List.Count - StartIndex) then Count := (List.Count - StartIndex); // Limit max. stream size
167 if Count > 0 then begin
168 SetLength(Buffer, Count);
169 Read(Pointer(Buffer)^, Count);
170 List.ReplaceBuffer(StartIndex, Pointer(Buffer)^, Count);
171 end;
172end;
173
174procedure TBinarySerializer.WriteStreamPart(AStream: TStreamByte; Count: Integer);
175var
176 Buffer: array of Byte;
177begin
178 if Count > AStream.Size then Count := AStream.Size; // Limit max. stream size
179 if Count > 0 then begin
180 SetLength(Buffer, Count);
181 AStream.ReadBuffer(Pointer(Buffer)^, Count);
182 Write(Pointer(Buffer)^, Count);
183 end;
184end;
185
186procedure TBinarySerializer.WriteList(List: TListByte; StartIndex, Count: Integer);
187var
188 Buffer: array of Byte;
189begin
190// if Count > (List.Count - StartIndex) then Count := (List.Count - StartIndex); // Limit max. stream size
191 if Count > 0 then begin
192 SetLength(Buffer, Count);
193 List.GetBuffer(StartIndex, PByte(Buffer)^, Count);
194 Write(Pointer(Buffer)^, Count);
195 end;
196end;
197
198constructor TBinarySerializer.Create;
199begin
200 inherited;
201 Endianness := enLittle;
202 FList := nil;
203 FGrow := True;
204end;
205
206procedure TBinarySerializer.Clear;
207begin
208 FList.Count := 0;
209 Position := 0;
210end;
211
212destructor TBinarySerializer.Destroy;
213begin
214 if OwnsList then FList.Free;
215 inherited Destroy;
216end;
217
218function TBinarySerializer.ReadUnixTime: TDateTime;
219begin
220 Result := UnixToDateTime(ReadCardinal);
221end;
222
223function TBinarySerializer.ReadDouble: Double;
224begin
225 Read(Result, SizeOf(Double));
226end;
227
228function TBinarySerializer.ReadSingle: Single;
229begin
230 Read(Result, SizeOf(Single));
231end;
232
233function TBinarySerializer.ReadWord: Word;
234begin
235 Read(Result, SizeOf(Word));
236 if SwapData then Result := SwapEndian(Result);
237end;
238
239procedure TBinarySerializer.SetList(const AValue: TListByte);
240begin
241 if OwnsList then FList.Free;
242 FList := AValue;
243end;
244
245procedure TBinarySerializer.SetEndianness(const AValue: TEndianness);
246begin
247 FEndianness := AValue;
248 {$if defined(FPC_LITTLE_ENDIAN)}
249 SwapData := FEndianness = enBig;
250 {$elseif defined(FPC_BIG_ENDIAN)}
251 SwapData := FEndianness = enLittle;
252 {$endif}
253end;
254
255procedure TBinarySerializer.ReverseByteOrder(var Buffer; Count: Integer);
256var
257 I: Integer;
258 Temp: Byte;
259type
260 TBytes = array of Byte;
261begin
262 I := 0;
263 while I < (Count div 2) do begin
264 Temp := TBytes(Buffer)[Count - 1 - I];
265 TBytes(Buffer)[Count - 1 - I] := TBytes(Buffer)[I];
266 TBytes(Buffer)[I] := Temp;
267 I := I + 1;
268 end;
269end;
270
271procedure TBinarySerializer.Write(var Buffer; Count: Integer);
272var
273 NewCount: Integer;
274begin
275 if FGrow then begin
276 NewCount := Position + Count;
277 if FList.Count < NewCount then
278 FList.Count := NewCount;
279 end;
280 FList.ReplaceBuffer(Position, Buffer, Count);
281 Inc(Position, Count);
282end;
283
284procedure TBinarySerializer.Read(var Buffer; Count: Integer);
285begin
286 FList.GetBuffer(Position, Buffer, Count);
287 Inc(Position, Count);
288end;
289
290procedure TBinarySerializer.Assign(Source: TBinarySerializer);
291begin
292 FList := Source.FList;
293end;
294
295procedure TBinarySerializer.WriteAnsiString(Data: string);
296var
297 StringLength: Longint;
298begin
299 StringLength := Length(Data);
300 Write(StringLength, SizeOf(StringLength));
301 Write(Data[1], StringLength);
302end;
303
304procedure TBinarySerializer.WriteByte(Data: Byte);
305begin
306 Write(Data, SizeOf(Byte));
307end;
308
309procedure TBinarySerializer.WriteCardinal(Data: Cardinal);
310begin
311 if SwapData then Data := SwapEndian(Data);
312 Write(Data, SizeOf(Cardinal));
313end;
314
315procedure TBinarySerializer.WriteInt64(Data: Int64);
316begin
317 if SwapData then Data := SwapEndian(Data);
318 Write(Data, SizeOf(Int64));
319end;
320
321procedure TBinarySerializer.WriteString(Data:string);
322begin
323 if Length(Data) > 0 then
324 Write(Data[1], Length(Data));
325end;
326
327procedure TBinarySerializer.WriteShortString(Data: ShortString);
328begin
329 WriteByte(Length(Data));
330 Write(Data[1], Length(Data));
331end;
332
333procedure TBinarySerializer.WriteStream(AStream: TStreamByte; Count: Integer);
334var
335 Buffer: array of Byte;
336begin
337 if Count > AStream.Size then Count := AStream.Size; // Limit max. stream size
338 AStream.Position := 0;
339 if Count > 0 then begin
340 SetLength(Buffer, Count);
341 AStream.ReadBuffer(Pointer(Buffer)^, Count);
342 Write(Pointer(Buffer)^, Count);
343 end;
344end;
345
346procedure TBinarySerializer.WriteDouble(Value: Double);
347begin
348 Write(Value, SizeOf(Double));
349end;
350
351procedure TBinarySerializer.WriteSingle(Value: Single);
352begin
353 Write(Value, SizeOf(Single));
354end;
355
356procedure TBinarySerializer.WriteUnixTime(Data: TDateTime);
357var
358 DataUnix: Int64;
359begin
360 DataUnix := DateTimeToUnix(Data);
361 WriteCardinal(DataUnix);
362end;
363
364procedure TBinarySerializer.WriteWord(Data: Word);
365begin
366 if SwapData then Data := SwapEndian(Data);
367 Write(Data, SizeOf(Word));
368end;
369
370end.
371
Note: See TracBrowser for help on using the repository browser.