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

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