| 1 | unit UBitStream;
|
|---|
| 2 |
|
|---|
| 3 | // Date: 2010-08-17
|
|---|
| 4 |
|
|---|
| 5 | {$mode delphi}
|
|---|
| 6 |
|
|---|
| 7 | interface
|
|---|
| 8 |
|
|---|
| 9 | uses
|
|---|
| 10 | Classes, SysUtils, RtlConsts, Math, UMemory;
|
|---|
| 11 |
|
|---|
| 12 | type
|
|---|
| 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 |
|
|---|
| 67 | implementation
|
|---|
| 68 |
|
|---|
| 69 | { TBitStream }
|
|---|
| 70 |
|
|---|
| 71 | function TBitStream.GetBit(Index: Integer):Boolean;
|
|---|
| 72 | begin
|
|---|
| 73 | Seek(Index, soBeginning);
|
|---|
| 74 | Read(Result, 1);
|
|---|
| 75 | end;
|
|---|
| 76 |
|
|---|
| 77 | function TBitStream.GetPosition:LongInt;
|
|---|
| 78 | begin
|
|---|
| 79 | Result := Seek(0, soCurrent);
|
|---|
| 80 | end;
|
|---|
| 81 |
|
|---|
| 82 | function TBitStream.GetSize: LongInt;
|
|---|
| 83 | var
|
|---|
| 84 | P: LongInt;
|
|---|
| 85 | begin
|
|---|
| 86 | P := Seek(0, soCurrent);
|
|---|
| 87 | GetSize := Seek(0, soEnd);
|
|---|
| 88 | Seek(P, soBeginning);
|
|---|
| 89 | end;
|
|---|
| 90 |
|
|---|
| 91 | procedure TBitStream.SetBit(Index: Integer;const AValue: Boolean);
|
|---|
| 92 | begin
|
|---|
| 93 | Seek(Index, soBeginning);
|
|---|
| 94 | Write(AValue, 1);
|
|---|
| 95 | end;
|
|---|
| 96 |
|
|---|
| 97 | procedure TBitStream.SetPosition(const AValue:LongInt);
|
|---|
| 98 | begin
|
|---|
| 99 | Seek(AValue, soBeginning);
|
|---|
| 100 | end;
|
|---|
| 101 |
|
|---|
| 102 | procedure TBitStream.SetSize(const AValue:LongInt);
|
|---|
| 103 | begin
|
|---|
| 104 | end;
|
|---|
| 105 |
|
|---|
| 106 | function TBitStream.Seek(Offset:LongInt;Origin:TSeekOrigin):LongInt;
|
|---|
| 107 | begin
|
|---|
| 108 | Result := 0;
|
|---|
| 109 | end;
|
|---|
| 110 |
|
|---|
| 111 | function TBitStream.Read(var Buffer; Count:Longint):Longint;
|
|---|
| 112 | begin
|
|---|
| 113 | Result := 0;
|
|---|
| 114 | end;
|
|---|
| 115 |
|
|---|
| 116 | function TBitStream.CopyFrom(Source: TBitStream; Count: LongInt): LongInt;
|
|---|
| 117 | var
|
|---|
| 118 | BlockSize: LongInt;
|
|---|
| 119 | Buffer: array[0..1023] of Byte;
|
|---|
| 120 | begin
|
|---|
| 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;
|
|---|
| 131 | end;
|
|---|
| 132 |
|
|---|
| 133 | function TBitStream.Write(const Buffer; Count:Longint):Longint;
|
|---|
| 134 | begin
|
|---|
| 135 | Result := 0;
|
|---|
| 136 | end;
|
|---|
| 137 |
|
|---|
| 138 | function TBitStream.EqualTo(Source: TBitStream): Boolean;
|
|---|
| 139 | var
|
|---|
| 140 | I: Integer;
|
|---|
| 141 | begin
|
|---|
| 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;
|
|---|
| 150 | end;
|
|---|
| 151 |
|
|---|
| 152 | procedure TBitStream.ReadBuffer(var Buffer; Count:Longint);
|
|---|
| 153 | begin
|
|---|
| 154 | if Read(Buffer, Count) < Count then
|
|---|
| 155 | raise EReadError.Create(SReadError);
|
|---|
| 156 | end;
|
|---|
| 157 |
|
|---|
| 158 | procedure TBitStream.WriteBuffer(const Buffer; Count:Longint);
|
|---|
| 159 | begin
|
|---|
| 160 | if Write(Buffer, Count) < Count then
|
|---|
| 161 | raise EWriteError.Create(SWriteError);
|
|---|
| 162 | end;
|
|---|
| 163 |
|
|---|
| 164 | function TBitStream.ReadBit:Boolean;
|
|---|
| 165 | begin
|
|---|
| 166 | Read(Result, 1);
|
|---|
| 167 | Result := Boolean(Integer(Result) and 1);
|
|---|
| 168 | end;
|
|---|
| 169 |
|
|---|
| 170 | procedure TBitStream.WriteBit(AValue:Boolean);
|
|---|
| 171 | begin
|
|---|
| 172 | Write(AValue, 1);
|
|---|
| 173 | end;
|
|---|
| 174 |
|
|---|
| 175 | function TBitStream.ReadNumber(Count: Byte): QWord;
|
|---|
| 176 | begin
|
|---|
| 177 | Result := 0;
|
|---|
| 178 | Read(Result, Count);
|
|---|
| 179 | Result := Result and ((QWord(1) shl Count) - 1);
|
|---|
| 180 | end;
|
|---|
| 181 |
|
|---|
| 182 | procedure TBitStream.WriteNumber(AValue: QWord; Count: Byte);
|
|---|
| 183 | begin
|
|---|
| 184 | Write(AValue, Count);
|
|---|
| 185 | end;
|
|---|
| 186 |
|
|---|
| 187 | function TBitStream.GetString: string;
|
|---|
| 188 | var
|
|---|
| 189 | I: Integer;
|
|---|
| 190 | begin
|
|---|
| 191 | Result := '';
|
|---|
| 192 | Position := 0;
|
|---|
| 193 | for I := 0 to Size - 1 do
|
|---|
| 194 | Result := Result + IntToStr(Integer(ReadBit));
|
|---|
| 195 | end;
|
|---|
| 196 |
|
|---|
| 197 | procedure TBitStream.SetString(const AValue: string);
|
|---|
| 198 | var
|
|---|
| 199 | I: Integer;
|
|---|
| 200 | begin
|
|---|
| 201 | Size := 0;
|
|---|
| 202 | for I := 1 to Length(AValue) do
|
|---|
| 203 | WriteBit(Boolean(StrToInt(AValue[I])));
|
|---|
| 204 | Position := 0;
|
|---|
| 205 | end;
|
|---|
| 206 |
|
|---|
| 207 | { TMemoryBitStream }
|
|---|
| 208 |
|
|---|
| 209 | function TMemoryBitStream.GetPosition:LongInt;
|
|---|
| 210 | begin
|
|---|
| 211 | Result := FPosition;
|
|---|
| 212 | end;
|
|---|
| 213 |
|
|---|
| 214 | function TMemoryBitStream.GetSize:LongInt;
|
|---|
| 215 | begin
|
|---|
| 216 | Result := FSize;
|
|---|
| 217 | end;
|
|---|
| 218 |
|
|---|
| 219 | procedure TMemoryBitStream.SetPosition(const AValue:LongInt);
|
|---|
| 220 | begin
|
|---|
| 221 | Seek(AValue, soBeginning);
|
|---|
| 222 | end;
|
|---|
| 223 |
|
|---|
| 224 | procedure TMemoryBitStream.SetSize(const AValue: LongInt);
|
|---|
| 225 | begin
|
|---|
| 226 | FSize := AValue;
|
|---|
| 227 | FMemory.Size := Ceil(AValue / 8);
|
|---|
| 228 | if FPosition > FSize then FPosition := FSize;
|
|---|
| 229 | end;
|
|---|
| 230 |
|
|---|
| 231 | function TMemoryBitStream.WriteToByte(var Data: Byte; NewData, Pos, Count: Byte) :Byte;
|
|---|
| 232 | begin
|
|---|
| 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;
|
|---|
| 237 | end;
|
|---|
| 238 |
|
|---|
| 239 | function TMemoryBitStream.Read(var Buffer;Count:Longint):Longint;
|
|---|
| 240 | var
|
|---|
| 241 | ByteCount: LongInt;
|
|---|
| 242 | I: LongInt;
|
|---|
| 243 | PosInByte: Byte;
|
|---|
| 244 | Data: Byte;
|
|---|
| 245 | begin
|
|---|
| 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;
|
|---|
| 270 | end;
|
|---|
| 271 |
|
|---|
| 272 | function TMemoryBitStream.Write(const Buffer; Count: Longint): Longint;
|
|---|
| 273 | var
|
|---|
| 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 |
|
|---|
| 283 | function Min(Value1, Value2: Integer): Integer;
|
|---|
| 284 | begin
|
|---|
| 285 | if Value1 < Value2 then Result := Value1
|
|---|
| 286 | else Result := Value2;
|
|---|
| 287 | end;
|
|---|
| 288 |
|
|---|
| 289 | begin
|
|---|
| 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;
|
|---|
| 323 | end;
|
|---|
| 324 |
|
|---|
| 325 | function TMemoryBitStream.Seek(Offset:LongInt;Origin:TSeekOrigin):LongInt;
|
|---|
| 326 | begin
|
|---|
| 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;
|
|---|
| 334 | end;
|
|---|
| 335 |
|
|---|
| 336 | constructor TMemoryBitStream.Create;
|
|---|
| 337 | begin
|
|---|
| 338 | FMemory := TPositionMemory.Create;
|
|---|
| 339 | FPosition := 0;
|
|---|
| 340 | FSize := 0;
|
|---|
| 341 | end;
|
|---|
| 342 |
|
|---|
| 343 | destructor TMemoryBitStream.Destroy;
|
|---|
| 344 | begin
|
|---|
| 345 | FMemory.Free;
|
|---|
| 346 | inherited Destroy;
|
|---|
| 347 | end;
|
|---|
| 348 |
|
|---|
| 349 | end.
|
|---|
| 350 |
|
|---|