Einzelnen Beitrag anzeigen

Benutzerbild von igel457
igel457

Registriert seit: 31. Aug 2005
1.622 Beiträge
 
FreePascal / Lazarus
 
#1

Bitweiser Zugriff auf Daten

  Alt 13. Okt 2009, 00:37
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
Andreas
"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
  Mit Zitat antworten Zitat