source: CoolStreaming/UStreamHelper.pas

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