source: CoolStreaming/UBitStream.pas

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