170 lines
3.3 KiB
ObjectPascal
170 lines
3.3 KiB
ObjectPascal
program Bitwise_IO;
|
|
|
|
{$APPTYPE CONSOLE}
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Classes;
|
|
|
|
type
|
|
TBitReader = class
|
|
private
|
|
readData: Cardinal;
|
|
startPosition: Integer;
|
|
endPosition: Integer;
|
|
Stream: TStream;
|
|
procedure Align;
|
|
function BaseStream: TStream;
|
|
procedure EnsureData(bitCount: Integer);
|
|
function GetInBuffer: Integer;
|
|
public
|
|
constructor Create(sm: TStream);
|
|
function Read(bitCount: Integer): Integer;
|
|
function ReadBit: Boolean;
|
|
end;
|
|
|
|
TBitWriter = class
|
|
private
|
|
data: Byte;
|
|
dataLength: Integer;
|
|
Stream: TStream;
|
|
procedure Align;
|
|
function BaseStream: TStream;
|
|
function BitsToAligment: Integer;
|
|
public
|
|
constructor Create(sm: TStream);
|
|
procedure Write(value, length: Integer);
|
|
procedure WriteBit(value: Boolean);
|
|
end;
|
|
|
|
function TBitReader.GetInBuffer: Integer;
|
|
begin
|
|
result := endPosition - startPosition;
|
|
end;
|
|
|
|
function TBitReader.BaseStream: TStream;
|
|
begin
|
|
result := stream;
|
|
end;
|
|
|
|
constructor TBitReader.Create(sm: TStream);
|
|
begin
|
|
Stream := sm;
|
|
end;
|
|
|
|
procedure TBitReader.EnsureData(bitCount: Integer);
|
|
var
|
|
readBits: Integer;
|
|
b: Byte;
|
|
begin
|
|
readBits := bitCount - GetInBuffer;
|
|
while readBits > 0 do
|
|
begin
|
|
BaseStream.Read(b, 1);
|
|
readData := readData or (b shl endPosition);
|
|
endPosition := endPosition + 8;
|
|
readBits := readBits - 8;
|
|
end;
|
|
end;
|
|
|
|
function TBitReader.ReadBit: Boolean;
|
|
begin
|
|
Exit(Read(1) > 0);
|
|
end;
|
|
|
|
function TBitReader.Read(bitCount: Integer): Integer;
|
|
begin
|
|
EnsureData(bitCount);
|
|
result := (readData shr startPosition) and ((1 shl bitCount) - 1);
|
|
startPosition := startPosition + bitCount;
|
|
if endPosition = startPosition then
|
|
begin
|
|
endPosition := ord(startPosition = 0);
|
|
readData := 0;
|
|
end
|
|
else if (startPosition >= 8) then
|
|
begin
|
|
readData := readData shr startPosition;
|
|
endPosition := endPosition - startPosition;
|
|
startPosition := 0;
|
|
end;
|
|
end;
|
|
|
|
procedure TBitReader.Align;
|
|
begin
|
|
endPosition := ord(startPosition = 0);
|
|
readData := 0;
|
|
end;
|
|
|
|
function TBitWriter.BaseStream: TStream;
|
|
begin
|
|
Exit(stream);
|
|
end;
|
|
|
|
function TBitWriter.BitsToAligment: Integer;
|
|
begin
|
|
Exit((32 - dataLength) mod 8);
|
|
end;
|
|
|
|
constructor TBitWriter.Create(sm: TStream);
|
|
begin
|
|
Stream := sm;
|
|
end;
|
|
|
|
procedure TBitWriter.WriteBit(value: Boolean);
|
|
begin
|
|
self.Write(ord(value), 1);
|
|
end;
|
|
|
|
procedure TBitWriter.Write(value, length: Integer);
|
|
var
|
|
currentData: Cardinal;
|
|
currentLength: Integer;
|
|
begin
|
|
currentData := data or (value shl dataLength);
|
|
currentLength := dataLength + length;
|
|
while currentLength >= 8 do
|
|
begin
|
|
|
|
BaseStream.Write(currentData, 1);
|
|
currentData := currentData shr 8;
|
|
currentLength := currentLength - 8;
|
|
end;
|
|
data := currentData;
|
|
dataLength := currentLength;
|
|
end;
|
|
|
|
procedure TBitWriter.Align;
|
|
begin
|
|
if dataLength > 0 then
|
|
begin
|
|
BaseStream.Write(data, 1);
|
|
data := 0;
|
|
dataLength := 0;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ms: TMemoryStream;
|
|
writer: TBitWriter;
|
|
reader: TBitReader;
|
|
|
|
begin
|
|
ms := TMemoryStream.create();
|
|
writer := TBitWriter.create(ms);
|
|
writer.WriteBit(true);
|
|
writer.Write(5, 3);
|
|
writer.Write($0155, 11);
|
|
writer.Align();
|
|
ms.Position := 0;
|
|
reader := TBitReader.create(ms);
|
|
writeln(reader.ReadBit());
|
|
writeln(reader.Read(3));
|
|
writeln(format('0x%.4x', [reader.Read(11)]));
|
|
reader.Align();
|
|
ms.Free;
|
|
writer.Free;
|
|
reader.Free;
|
|
Readln;
|
|
end.
|