delphi - 当以任意位长度定位时,从字节数组中读取变量

标签 delphi arrays converters bit-manipulation bit

在 Delphi XE3 中,我试图解码从 UDP 套接字读取的一些数据。 显然,数据编码如下(按时间顺序列出):

NAME                    BITS    TYPE
RECURRENCE INDICATOR    1       BOOLEAN
TRANSMITTER CODE        24      STRING
LATITUDE                25      INTEGER
LONGITUDE               26      INTEGER
DERIVATION              4       INTEGER
//I am not able to reach the documentation from work but the lat and long
//translates with a constant of 0.00000536441, so you take the binary (2 based)
//number, convert to decimal (10 based) and multiply with the constant for the 
//float value of the coordinates.

现在,我的代码如下所示(是的 - 这是早期测试和手动计算):

procedure TForm1.UDPUDPRead(AThread: TIdUDPListenerThread; AData: array of Byte; 
                            ABinding: TIdSocketHandle);
var
  s: string;
  recInd: Boolean;
  trCode: String;
  lat, long, deri: Integer;
begin
Label1.Caption := IntToStr(Length(AData)) + ' bytes received @ ' + 
                  TimeToStr(Time);
s := BytesToHex(AData);
If CheckBox2.Checked Then Memo1.Lines.Clear;
Memo1.Lines.Add(s);
end;

问题是如何从该字节数组中设置变量 recInd、trCode、lat、long 和 deri?
所需的功能类似于:

function SubBin(AData: array of byte; start, length: integer):array of byte
//Used like this:
recInd := SubBin(AData, 0, 1);
trCode := SubBin(AData, 1, 24);
lat := SubBin(AData, 25, 25);
long := SubBin(AData, 50, 26);
deri := SubBin(AData, 76, 4);

最佳答案

假设位顺序 MSB 在前,您可以尝试这样的操作(未调试,未优化,只是作为一个想法):

function ExtractBitArray(AData:TBytes; AFrom,ALength:Integer): TBytes;
var
  ByteIdxFrom: integer;
  i: integer;
  BitEndOfs: integer;
  Mask: byte;

  procedure ___ShiftBytesRight(var ABuf:TBytes);
  var
    CFhi,CFlo: Byte;
    B: byte;
    i: integer;
  begin
    CFHi := 0;
    for i := low(ABuf) to high(ABuf) do
      begin
        B := ABuf[i];
        CFlo := B;
        B := (B shr 1) or CFhi;
        ABuf[i] := B;
        CFhi := CFlo shl 7 and $80;
      end;
  end;

begin
  ByteIdxFrom := AFrom div 8;
  BitEndOfs := (AFrom + ALength) mod 8;
  //
  SetLength(Result,ALength div 8 + 1);
  for i := Low(Result) to High(Result) do
    Result[i] := AData[ByteIdxFrom + i];
  //
  if BitEndOfs>0 then
    for I := BitEndOfs to 7 do
      ___ShiftBytesRight(Result);
  //
  Mask := $FF;
  for i := ALength mod 8 to 7 do
    Mask := Mask shr 1;
  Result[0] := Result[0] and Mask;
end;

关于delphi - 当以任意位长度定位时,从字节数组中读取变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18949752/

相关文章:

c - 查找数组中的对称性

jsf - 重写 JSF 转换器 javax.faces.convert.BigDecimalConverter 以支持使用 @FacesConverter(forClass = BigDecimal.class) 的自定义转换器

javascript - 如何使用 Javascript 将此文本转换为正确的 HTML 字符

delphi - 删除和插入行时如何更新 SynMemo Undo/RedoList

Delphi:如何检查是否按下了任何鼠标按钮 - 在鼠标事件之外?

delphi - 如何在 Delphi 中在运行时创建自定义属性并将其附加到字段

C++ 将十进制字符串拆分为两个整数

Delphi ADO 与 MS Access - 运行特定查询后查询时间减少

python - loadtxt 函数的隐藏错误

javascript - 计算对象数组内的数组数量