Bitweiser Zugriff auf Binärdaten
Grund und Zweck
Für das Auslesen mancher Datenstrukturen (u.a. Huffmantabellen, einige Dateiformate (MP3, JPEG)) ist es notwendig einen bitweisen Zugriff auf die Daten zu haben. Dieses Problem ist jedoch alles andere als trivial, da Computersysteme nun mal auf das Auslesen einzelner Bytes spezialisiert sind.
Im Nachfolgenden das Grundgerüst für eine Klasse, die Zugriff auf einzelne Bits eines Datenbereichs gewährleistet. Natürlich ist die Klasse nach belieben erweiterbar. Weitere einzubauende Funktionen wären: z.B. Suchen und Schreiben von Daten und ein Überlaufschutz.
Die Daten werden dabei
von links nach rechts gelesen:
Code:
. Byte 1 | Byte 2 |
. 1010 1010 | 1010 1010 |
-->
Maximal können
32 Bit auf einmal gelesen werden.
Der Code
Delphi-Quellcode:
type
TBitAccess = class
private
FDataPointer: PByte;
FBitPos: integer;
public
constructor Create(AData: PByte);
function ReadBits(ACount: integer): Cardinal;
end;
implementation
{ TBitAccess }
constructor TBitAccess.Create(AData: PByte);
begin
inherited Create;
FDataPointer := AData;
end;
function TBitAccess.ReadBits(ACount: integer): Cardinal;
function DataToRead: integer;
begin
if FBitPos > 0 then
begin
result := 8 - FBitPos;
if result > ACount then
result := ACount;
end else
begin
result := ACount;
if ACount > 8 then
result := 8;
end;
end;
var
dtr: Integer;
begin
result := 0;
while ACount > 0 do
begin
//(1)
dtr := DataToRead;
//(2)
result := (result shl dtr) or
((FDataPointer^ shr (8 - (dtr + FBitPos))) and
($FF shr (8 - dtr)));
//(3)
FBitPos := (FBitPos + dtr) mod 8;
//(4)
if FBitPos = 0 then
inc(FDataPointer);
ACount := ACount - dtr;
end;
end;
end.
Wie es funktioniert
(1)
FDataPointer ist der Pointer auf das aktuelle Byte. FBitPos ist die Position innerhalb des Bytes. Die Funktion DataToRead gibt die Anzahl der Bits, die in einem Durchgang gelesen werden müssen zurück, maximal kann ein Byte auf einmal gelesen werden (8 Bit). Dabei versucht die Funktion stets zunächst das noch "angebrochene" Byte zu Ende zu lesen.
(2)
Zunächst wird im Ergebnis für die zu lesenden Daten durch verschieben nach rechts "Platz" gemacht. Dann wird das aktuelle Byte entsprechend ausgerichtet und auf die hinzuzufügenden Daten durch eine Maske beschnitten.
(3)
Zähle die Bitposition hoch.
(4)
Zähle ein Byte hoch, wenn ein komplettes Byte gelesen wurde.
Beispiel
Delphi-Quellcode:
var
bits: TBitAccess;
//Byte 1 | Byte 2 | Byte 3 | Byte 4
//1010 1010 | 1010 1010 | 1010 1010 | 1010 1010
const
data = #170#170#170#170;
begin
bits := TBitAccess.Create(PByte(@data[1]));
try
Writeln(bits.ReadBits(4)); //1010 = 10
Writeln(bits.ReadBits(1)); //1 = 1
Writeln(bits.ReadBits(1)); //0 = 0
Writeln(bits.ReadBits(3)); //101 = 5
Writeln(bits.ReadBits(1)); //0 = 0
Writeln(bits.ReadBits(2)); //10 = 2
Writeln(bits.ReadBits(3)); //101 = 5
Writeln(bits.ReadBits(2)); //01 = 1
Writeln(bits.ReadBits(6)); //0101 01 = 21
Writeln(bits.ReadBits(8)); //0101 0101 = 85
finally
bits.Free;
end;
end;
So, ich hoffe, diesen Code kann jemand gebrauchen
Andreas
Schlüsselwörter: bit, lesen, byte, bitweise, bitweiser zugriff, shift, pointer, huffman, hufmann, huffmann
"Sollen sich auch alle schämen, die gedankenlos sich der Wunder der Wissenschaft und Technik bedienen, und nicht mehr davon geistig erfasst haben als die Kuh von der Botanik der Pflanzen, die sie mit Wohlbehagen frisst." - Albert Einstein