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

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