source: trunk/Packages/CoolStreaming/BitStream.pas

Last change on this file was 323, checked in by chronos, 6 months ago
File size: 9.2 KB
Line 
1unit BitStream;
2
3// Date: 2010-08-17
4
5interface
6
7uses
8 Classes, SysUtils, RtlConsts, Math, Memory;
9
10type
11 TBytes = array[0..MaxInt - 1] of Byte;
12
13 { TBitStream }
14
15 TBitStream = class
16 private
17 function GetBit(Index: Integer):Boolean; virtual;
18 function GetPosition: LongInt; virtual;
19 function GetSize: LongInt; virtual;
20 procedure SetBit(Index: Integer;const AValue: Boolean); virtual;
21 procedure SetPosition(const AValue: LongInt); virtual;
22 procedure SetSize(const AValue: LongInt); virtual;
23 public
24 function Seek(Offset: LongInt; Origin: TSeekOrigin): LongInt; virtual;
25 function Read(var Buffer; Count: Longint): Longint; virtual;
26 function CopyFrom(Source: TBitStream; Count: LongInt): LongInt;
27 function Write(const Buffer; Count: Longint): Longint; virtual;
28 function EqualTo(Source: TBitStream): Boolean;
29 function GetString: string;
30 procedure SetString(const AValue: string);
31 procedure ReadBuffer(var Buffer; Count: Longint);
32 procedure WriteBuffer(const Buffer; Count: Longint);
33 function ReadBit: Boolean;
34 procedure WriteBit(AValue: Boolean);
35 function ReadNumber(Count: Byte): QWord;
36 procedure WriteNumber(AValue: QWord; Count: Byte);
37 property Position: LongInt read GetPosition write SetPosition;
38 property Size: LongInt read GetSize write SetSize;
39 property Bit[Index: Integer]: Boolean read GetBit write SetBit;
40 property AsString: string read GetString write SetString;
41 end;
42
43 { TMemoryBitStream }
44
45 TMemoryBitStream = class(TBitStream)
46 private
47 FMemory: TPositionMemory;
48 FPosition: LongInt;
49 FSize: LongInt;
50 function GetPosition: LongInt; override;
51 function GetSize: LongInt; override;
52 procedure SetPosition(const AValue: LongInt); override;
53 procedure SetSize(const AValue: LongInt); override;
54 function WriteToByte(var Data: Byte; NewData, Pos, Count: Byte): Byte;
55 public
56 function Read(var Buffer; Count: Longint): Longint; override;
57 function Write(const Buffer; Count: Longint): Longint; override;
58 function Seek(Offset: LongInt; Origin: TSeekOrigin): LongInt; override;
59 constructor Create;
60 destructor Destroy; override;
61 property Memory: TPositionMemory read FMemory;
62 end;
63
64
65implementation
66
67{ TBitStream }
68
69function TBitStream.GetBit(Index: Integer):Boolean;
70begin
71 Seek(Index, soBeginning);
72 Read(Result, 1);
73end;
74
75function TBitStream.GetPosition:LongInt;
76begin
77 Result := Seek(0, soCurrent);
78end;
79
80function TBitStream.GetSize: LongInt;
81var
82 P: LongInt;
83begin
84 P := Seek(0, soCurrent);
85 GetSize := Seek(0, soEnd);
86 Seek(P, soBeginning);
87end;
88
89procedure TBitStream.SetBit(Index: Integer;const AValue: Boolean);
90begin
91 Seek(Index, soBeginning);
92 Write(AValue, 1);
93end;
94
95procedure TBitStream.SetPosition(const AValue:LongInt);
96begin
97 Seek(AValue, soBeginning);
98end;
99
100procedure TBitStream.SetSize(const AValue:LongInt);
101begin
102end;
103
104function TBitStream.Seek(Offset:LongInt;Origin:TSeekOrigin):LongInt;
105begin
106 Result := 0;
107end;
108
109function TBitStream.Read(var Buffer; Count:Longint):Longint;
110begin
111 Result := 0;
112end;
113
114function TBitStream.CopyFrom(Source: TBitStream; Count: LongInt): LongInt;
115var
116 BlockSize: LongInt;
117 Buffer: array[0..1023] of Byte;
118begin
119 Result := 0;
120 while Count > 0 do begin
121 if Count > (SizeOf(Buffer) * 8) then BlockSize := SizeOf(Buffer) * 8
122 else BlockSize := Count;
123 BlockSize := Source.Read(Buffer, BlockSize);
124 BlockSize := Write(Buffer, BlockSize);
125 if BlockSize = 0 then Break;
126 Dec(Count, BlockSize);
127 Result := Result + BlockSize;
128 end;
129end;
130
131function TBitStream.Write(const Buffer; Count:Longint):Longint;
132begin
133 Result := 0;
134end;
135
136function TBitStream.EqualTo(Source: TBitStream): Boolean;
137var
138 I: Integer;
139begin
140 if Size = Source.Size then begin
141 I := 0;
142 Result := True;
143 Position := 0;
144 Source.Position := 0;
145 while (I < Size) and (ReadBit = Source.ReadBit) do Inc(I);
146 if I < Size then Result := False;
147 end else Result := False;
148end;
149
150procedure TBitStream.ReadBuffer(var Buffer; Count:Longint);
151begin
152 if Read(Buffer, Count) < Count then
153 raise EReadError.Create(SReadError);
154end;
155
156procedure TBitStream.WriteBuffer(const Buffer; Count:Longint);
157begin
158 if Write(Buffer, Count) < Count then
159 raise EWriteError.Create(SWriteError);
160end;
161
162function TBitStream.ReadBit:Boolean;
163begin
164 Read(Result, 1);
165 Result := Boolean(Integer(Result) and 1);
166end;
167
168procedure TBitStream.WriteBit(AValue:Boolean);
169begin
170 Write(AValue, 1);
171end;
172
173function TBitStream.ReadNumber(Count: Byte): QWord;
174begin
175 Result := 0;
176 Read(Result, Count);
177 Result := Result and ((QWord(1) shl Count) - 1);
178end;
179
180procedure TBitStream.WriteNumber(AValue: QWord; Count: Byte);
181begin
182 Write(AValue, Count);
183end;
184
185function TBitStream.GetString: string;
186var
187 I: Integer;
188begin
189 Result := '';
190 Position := 0;
191 for I := 0 to Size - 1 do
192 Result := Result + IntToStr(Integer(ReadBit));
193end;
194
195procedure TBitStream.SetString(const AValue: string);
196var
197 I: Integer;
198begin
199 Size := 0;
200 for I := 1 to Length(AValue) do
201 WriteBit(Boolean(StrToInt(AValue[I])));
202 Position := 0;
203end;
204
205{ TMemoryBitStream }
206
207function TMemoryBitStream.GetPosition:LongInt;
208begin
209 Result := FPosition;
210end;
211
212function TMemoryBitStream.GetSize:LongInt;
213begin
214 Result := FSize;
215end;
216
217procedure TMemoryBitStream.SetPosition(const AValue:LongInt);
218begin
219 Seek(AValue, soBeginning);
220end;
221
222procedure TMemoryBitStream.SetSize(const AValue: LongInt);
223begin
224 FSize := AValue;
225 FMemory.Size := Ceil(AValue / 8);
226 if FPosition > FSize then FPosition := FSize;
227end;
228
229function TMemoryBitStream.WriteToByte(var Data: Byte; NewData, Pos, Count: Byte) :Byte;
230begin
231 Data := Byte(Data and not (((1 shl Count) - 1) shl Pos) // Make zero space for new data
232 or ((NewData and ((1 shl Count) - 1)) shl Pos)); // Write new data
233 Result := Count;
234 if Result > (8 - Pos) then Result := 8 - Pos;
235end;
236
237function TMemoryBitStream.Read(var Buffer;Count:Longint):Longint;
238var
239 ByteCount: LongInt;
240 I: LongInt;
241 PosInByte: Byte;
242 Data: Byte;
243begin
244 if (Count < 0) or (Count > (Size - Position)) then
245 raise EReadError.Create(SReadError);
246
247 Result := 0;
248 if (FSize > 0) and (FPosition < FSize) and (FPosition >= 0) then begin
249 if (FPosition + Count) > FSize then Count := FSize - FPosition;
250 ByteCount := Ceil(Count / 8);
251 PosInByte := FPosition mod 8;
252 FMemory.Position := Trunc(FPosition / 8);
253 Data := FMemory.ReadByte; // Read first byte
254 for I := 0 to ByteCount - 1 do begin
255 TBytes(Buffer)[I] := (Data shr PosInByte) and ((1 shl (8 - PosInByte)) - 1);
256 if (I < ByteCount) and (FMemory.Position < FMemory.Size) then begin
257 Data := FMemory.ReadByte;
258 end else Data := 0;
259 if PosInByte > 0 then
260 TBytes(Buffer)[I] := TBytes(Buffer)[I] or
261 ((Integer(Data) and ((1 shl PosInByte) - 1)) shl (8 - PosInByte));
262 if (I = (ByteCount - 1)) then
263 TBytes(Buffer)[I] := TBytes(Buffer)[I] and ((1 shl (Count - 8 * (ByteCount - 1))) - 1);
264 end;
265 Inc(FPosition, Count);
266 Result := Count;
267 end;
268end;
269
270function TMemoryBitStream.Write(const Buffer; Count: Longint): Longint;
271var
272 ByteCount: LongInt;
273 BitCount: LongInt;
274 WriteBitCount: Integer;
275 RestBitCount: Integer;
276 NextRestBitCount: Integer;
277 I: LongInt;
278 BytePos: Byte;
279 Data: Byte;
280
281function Min(Value1, Value2: Integer): Integer;
282begin
283 if Value1 < Value2 then Result := Value1
284 else Result := Value2;
285end;
286
287begin
288 if Count < 0 then
289 raise EWriteError.Create(SWriteError);
290
291 RestBitCount := 0;
292 NextRestBitCount := 0;
293 BitCount := Count;
294 ByteCount := Ceil(Count / 8);
295 FMemory.Position := Trunc(FPosition / 8);
296 BytePos := FPosition mod 8;
297 I := 0;
298 while (I < ByteCount) or (RestBitCount > 0) do begin
299 WriteBitCount := Min(8 - BytePos, BitCount);
300 if (FMemory.Position < FMemory.Size) and (WriteBitCount < 8) then begin
301 Data := FMemory.ReadByte;
302 FMemory.Position := FMemory.Position - 1;
303 end else Data := 0;
304
305 // Write rest of previous source byte to target
306 if RestBitCount > 0 then begin
307 Dec(BitCount, WriteToByte(Data, TBytes(Buffer)[I - 1] shr (8 - BytePos), 0, RestBitCount));
308 WriteBitCount := Min(8 - BytePos, BitCount);
309 end;
310
311 // Write part up to one byte from source to target
312 Dec(BitCount, WriteToByte(Data, TBytes(Buffer)[I], BytePos, WriteBitCount));
313 FMemory.WriteByte(Data);
314
315 RestBitCount := Min(8 - WriteBitCount, BitCount);
316 Inc(I);
317 end;
318 Inc(FPosition, Count);
319 if FSize < FPosition then FSize := FPosition;
320 Result := Count;
321end;
322
323function TMemoryBitStream.Seek(Offset:LongInt;Origin:TSeekOrigin):LongInt;
324begin
325 case Origin of
326 soBeginning: FPosition := Offset;
327 soEnd: FPosition := FSize + Offset;
328 soCurrent: FPosition := FPosition + Offset;
329 end;
330 //if FPosition > FSize then FPosition := FSize;
331 Result := FPosition;
332end;
333
334constructor TMemoryBitStream.Create;
335begin
336 FMemory := TPositionMemory.Create;
337 FPosition := 0;
338 FSize := 0;
339end;
340
341destructor TMemoryBitStream.Destroy;
342begin
343 FreeAndNil(FMemory);
344 inherited;
345end;
346
347end.
348
Note: See TracBrowser for help on using the repository browser.