Delphi 字节数组固定长度补前导00 适配智能卡APDU指令
问题根因
你代码中先执行SetLength(taxPayerId, 20)申请了20字节的数组,后续直接将TEncoding.UTF8.GetBytes的返回值赋值给taxPayerId,这会直接覆盖之前申请的数组,替换为长度和字符串转码结果一致的短数组,长度设置完全失效。
修正方案
直接修正逻辑
直接修改你现有税号处理部分的代码即可达到目标效果:
var dateAndTimeOfIssue, taxPayerId: TArray<Byte>; dateOfIssueMS, DOIReversed: Int64; // 新增临时变量存储转码后的税号字节 tempTaxIdBytes: TArray<Byte>; i, contentOffset: Integer; begin // 原有日期处理逻辑无需修改,本身是正确的 dateOfIssueMS := StrToInt64(MilliSecondsBetween(f.InvoiceRequest.dateAndTimeOfIssue, UnixDateDelta).ToString); ReverseBytes(@(dateofIssueMS), @(DOIReversed), SizeOf(dateofIssueMS)); SetLength(dateAndTimeOfIssue, 8); Move(DOIReversed, dateAndTimeOfIssue[0], SizeOf(DOIReversed)); // 修正后的税号字节处理 tempTaxIdBytes := TEncoding.UTF8.GetBytes(F.MyCompany.taxpayerId); // 初始化20字节的目标数组,全部填充00 SetLength(taxPayerId, 20); for i := Low(taxPayerId) to High(taxPayerId) do taxPayerId[i] := $00; // 计算内容偏移量:内容放在数组尾部,前序补0 contentOffset := Length(taxPayerId) - Length(tempTaxIdBytes); if contentOffset >= 0 then Move(tempTaxIdBytes[0], taxPayerId[contentOffset], Length(tempTaxIdBytes)); end;
通用封装(推荐)
你后续需要处理多个字节数组、还要合并为最终APDU包,可以封装两个通用函数复用逻辑:
- 固定长度字节数组生成函数
/// <summary>生成固定长度的字节数组,空缺位置默认补00</summary> /// <param name="srcBytes">源内容字节</param> /// <param name="targetLen">目标数组长度</param> /// <param name="fillByte">填充用字节,默认$00</param> /// <param name="fillBefore">是否在内容前填充,True=前补,False=后补</param> function GetFixedLenBytes(const srcBytes: TArray<Byte>; targetLen: Integer; fillByte: Byte = $00; fillBefore: Boolean = True): TArray<Byte>; var i, copyOffset, copyLen: Integer; begin SetLength(Result, targetLen); // 先全量填充指定字节 for i := Low(Result) to High(Result) do Result[i] := fillByte; if Length(srcBytes) = 0 then Exit; // 计算复制偏移和长度,超出目标长度则截断 copyLen := Min(Length(srcBytes), targetLen); if fillBefore then copyOffset := targetLen - copyLen else copyOffset := 0; Move(srcBytes[0], Result[copyOffset], copyLen); end;
- 多字节数组合并函数
/// <summary>合并多个字节数组为一个数组</summary> function MergeByteArray(const arrList: array of TArray<Byte>): TArray<Byte>; var i, totalLen, currPos: Integer; begin totalLen := 0; for i := Low(arrList) to High(arrList) do Inc(totalLen, Length(arrList[i])); SetLength(Result, totalLen); currPos := 0; for i := Low(arrList) to High(arrList) do begin if Length(arrList[i]) = 0 then Continue; Move(arrList[i][0], Result[currPos], Length(arrList[i])); Inc(currPos, Length(arrList[i])); end; end;
后续处理其他字段、合并数组时直接调用即可:
// 处理税号 tempTaxIdBytes := TEncoding.UTF8.GetBytes(F.MyCompany.taxpayerId); taxPayerId := GetFixedLenBytes(tempTaxIdBytes, 20); // 处理其他字段同理,比如某字段需要后补0 // otherField := GetFixedLenBytes(otherBytes, 10, $00, False); // 合并为最终APDU字节数组 finalAPDU := MergeByteArray([dateAndTimeOfIssue, taxPayerId, otherField1, otherField2]);
内容的提问来源于stack exchange,提问作者q1werty
相关产品推荐
相关产品推荐

