将以字节为单位的二进制数据转换为六进制数据,并在C中进行相反的转换



我想将以字节为单位的二进制数据缓冲区转换为六进制缓冲区,其中六进制是两个最高有效位设置为零的字节。我还想做相反的事情,即将六进制的缓冲区转换回字节。作为一个测试,我使用伪随机数生成器生成一个以字节为单位的缓冲区,该生成器使用C中的内置版本创建0到255之间的数字。这是为了模拟二进制数据。伪随机数生成器的细节及其性能并不重要,只是生成了一个具有各种值的字节流。最终将读取一个二进制文件。

我修改了链接中的函数:如何用C进行base64编码(解码(?因此,使用六进制代替base64,而不是将字节编码为base64字符,然后将其解码回字节。我的编码功能如下:

int bytesToSextets(int inx, int iny, int numBytes, CBYTE* byteData, BYTE* sextetData) {
static int modTable[] = { 0, 2, 1 };
int numSextets = 4 * ((numBytes + 2) / 3);
int i, j;
for (i = inx, j = iny; i < numBytes;) {
BYTE byteA = i < numBytes ? byteData[i++] : 0;
BYTE byteB = i < numBytes ? byteData[i++] : 0;
BYTE byteC = i < numBytes ? byteData[i++] : 0;
UINT triple = (byteA << 0x10) + (byteB << 0x08) + byteC;
sextetData[j++] = (triple >> 18) & 0x3F;
sextetData[j++] = (triple >> 12) & 0x3F;
sextetData[j++] = (triple >> 6) & 0x3F;
sextetData[j++] = triple & 0x3F;
}
for (int i = 0; i < modTable[numBytes % 3]; i++) {
sextetData[numSextets - 1 - i] = 0;
}
return j - iny;
}

其中,inx是我要开始编码的输入字节缓冲区中的索引,iny是写入六进制开头的输出六进制缓冲区的索引,numBytes是要编码的字节数,*byteData、*sextetData是要读取和写入的各自缓冲区。最后一个for循环将sextetDatas的元素设置为零,当存在填充时,不要像原始代码中给定的那样使用"="。虽然零字节可以是有效的数据,因为缓冲区的长度是预先知道的,但我认为这不是问题。函数返回写入的六进制数,可以根据4*((numBytes+2(/3(进行检查。输出缓冲区的前几个六进制对缓冲区其余部分中编码的数据字节数进行编码,六进制数在公式中给出。

将六元组解码回字节的代码如下:

int sextetsToBytes(int inx, int iny, int numBytes, CBYTE* sextetData, BYTE* byteData) {
int numSextets = 4 * ((numBytes + 2) / 3);
int padding = 0;
if (sextetData[numSextets - 1 + inx] == 0) padding++;
if (sextetData[numSextets - 2 + inx] == 0) padding++;
int i, j;
for (i = inx, j = iny; i < numSextets + inx;) {
UINT sextetA = sextetData[i++];
UINT sextetB = sextetData[i++];
UINT sextetC = sextetData[i++];
UINT sextetD = sextetData[i++];
UINT triple = (sextetA << 18) + (sextetB << 12) + (sextetC << 6) + sextetD;
if (j < numBytes) byteData[j++] = (triple >> 16) & 0xFF;
if (j < numBytes) byteData[j++] = (triple >> 8) & 0xFF;
if (j < numBytes) byteData[j++] = triple & 0xFF;
}
return j - iny - padding;
}

其中,inx和iny是开始从缓冲区读取和写入缓冲区的索引,numBytes是将在输出缓冲区中的字节数,从中计算输入六进制数。输入缓冲区的长度是从bytesToExtents((写入的前几个六元组中找到的,因此inx是输入六元组缓冲区中开始实际转换回字节的位置。在原始函数中,给出了六进制的数量,从中可以使用numSextets/4*3计算字节数。众所周知,这是不可能的,也不应该有什么不同。最后两个参数*sextetData和*byteData分别是输入和输出缓冲区。

创建一个以字节为单位的输入缓冲区,转换为六进制,然后作为测试转换回字节。在生成的字节的初始缓冲器和从中间六进制缓冲器转换回后的字节的输出缓冲器之间进行比较。当输入缓冲区的长度是3的倍数时,匹配是完美的,并且最终输出缓冲区完全相同。然而,如果初始缓冲器中的字节数不是3的倍数,则最终输出缓冲器中的最后3个字节可能与原始字节不匹配。这显然与字节数不是3的倍数时的填充有关,但我无法找到问题的根源。顺便说一句,即使最后几个字节不匹配,这两个函数的返回值也总是正确的。

在头文件中,我有以下类型定义:

typedef unsigned char BYTE;
typedef const unsigned char CBYTE;
typedef unsigned int UINT;

虽然主要功能更复杂,但在最简单的版本中,它的形式如下:

// Allocate memory for bufA and bufB.
// Write the data length and other information into sextets 0 to 4 in bufB.
// Convert the bytes in bufA starting at index 0 to sextets in bufB starting at index 5.
int countSextets = bytesToSextets(0, 5, lenBufA, bufA, bufB);
// Allocate memory for bufC.
// Convert the sextets in bufB starting at index 5 back to bytes in bufC starting at index 0.
int countBytes = sextetsToBytes(5, 0, lenBufC, bufB, bufC);

正如我所说,这一切都正常工作,只是当lenBufA不是3的倍数时,bufC中最后3个恢复的字节与bufA中的字节不匹配,但计算的缓冲区长度都是正确的。

也许有人可以帮我澄清一下。

sextetData[numSextets - 1 - i] = 0;应为sextetData[iny + numSextets - 1 - i] = 0;

我最初发布的sextetsToBytes((版本存在问题,我使用测试填充

if (sextetData[numSextets - 1 + inx] == 0) padding++;
if (sextetData[numSextets - 2 + inx] == 0) padding++;

当然,不能使用base64的'='测试,但是,测试零仍然可能导致问题,因为零可能是有效的数据项。这有时确实会导致指定的输出字节数与通过向上计数循环中的字节并减去填充字节而得到的数字之间存在差异。只需从函数中删除填充字节,然后根据指定的输入值numBytes检查返回的计数,就可以了。修改后的代码如下:

int sextetsToBytes(int numBytes, CBYTE* sextetData, BYTE* byteData) {
int numSextets = 4 * ((numBytes + 2) / 3);
int i, j;
for (i = 0, j = 0; i < numSextets;) {
UINT sextetA = sextetData[i++];
UINT sextetB = sextetData[i++];
UINT sextetC = sextetData[i++];
UINT sextetD = sextetData[i++];
UINT triple = (sextetA << 18) + (sextetB << 12) + (sextetC << 6) + sextetD;
if (j < numBytes) byteData[j++] = (triple >> 16) & 0xFF;
if (j < numBytes) byteData[j++] = (triple >> 8) & 0xFF;
if (j < numBytes) byteData[j++] = triple & 0xFF;
}
return j;
}

相关内容

  • 没有找到相关文章

最新更新