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

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