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

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