gpt4 book ai didi

c - RLE 实现每隔一段时间就会失败

转载 作者:行者123 更新时间:2023-12-04 07:37:48 24 4
gpt4 key购买 nike

我为二进制文件的 RLE 压缩实现了以下两个函数。

char* RLEcompress(char* data, size_t origSize, size_t* compressedSize) {
char* ret = calloc(2 * origSize, 1);
size_t retIdx = 0, inIdx = 0;
size_t retSize = 0;
while (inIdx < origSize) {
size_t count = 1;
size_t contIdx = inIdx;
while (contIdx < origSize - 1 && data[inIdx] == data[++contIdx]) {
count++;
}
size_t tmpCount = count;

// break down counts with 2 or more digits into counts ≤ 9
while (tmpCount > 9) {
tmpCount -= 9;
ret[retIdx++] = data[inIdx];
ret[retIdx++] = data[inIdx];
ret[retIdx++] = '9';
retSize += 3;
}

ret[retIdx++] = data[inIdx];
retSize += 1;
if (tmpCount > 1) {
// repeat character (this tells the decompressor that the next digit
// is in fact the # of consecutive occurrences of this char)
ret[retIdx++] = data[inIdx];
// convert single-digit count to dataing
ret[retIdx++] = '0' + tmpCount;
retSize += 2;
}

inIdx += count;
}
*compressedSize = retSize;
return ret;
}

char* RLEdecompress(char* data, size_t compressedSize, size_t uncompressedSize, size_t extraAllocation) {
char* ret = calloc(uncompressedSize + extraAllocation, 1);
size_t retIdx = 0, inIdx = 0;
while (inIdx < compressedSize) {
ret[retIdx++] = data[inIdx];
if (data[inIdx] == data[inIdx + 1]) { // next digit is the # of occurrences
size_t occ = ((data[inIdx + 2]) - '0');
for (size_t i = 1; i < occ && retIdx < compressedSize; i++) {
ret[retIdx++] = data[inIdx];
}
inIdx += 2;
}
inIdx += 1;
}
return ret;
}
它们似乎工作正常,即 diff将原始文件与先压缩后未压缩的版本进行比较时,不会产生任何输出。
但是,每隔一段时间,文件就会不同,表明某处存在错误。我没能在展示这一点的文件中找到模式,但我会给你一个例子来说明差异的样子。
enter image description here
下一个是原件。
如您所见,在先压缩后未压缩的版本中,字节 21 重复了两次。我一直无法确定问题所在。不幸的是,这个错误发生在很少的文件中:到目前为止,我只用两个 pdf 文件观察过它,包括上面显示的一个,但我不能分享它们,因为它是受版权保护的内容,但我正在努力想出另一个文件失败,所以我可以为您提供一个示例。
我有一种感觉,上面的代码有一些“明显”的错误,我只是想念它。非常感谢帮助。
编辑:
这是我用来读取有问题的文件,压缩它,然后解压缩它的一个测试程序。我还在中间步骤中将压缩的文件保存到磁盘以获取更多调试数据。
int main(int argc, char** argv) {
size_t compsz;
FILE* fp = fopen(argv[1], "r");
if (!fp) {
perror("fp");
return 1;
}

if (fseek(fp, 0L, SEEK_END) == -1) {
return -1;
}
// get file size
size_t filecontentLen = ftell(fp);
if (filecontentLen < 0) {
return -1;
}
rewind(fp);

char* filecontentBuf = calloc(filecontentLen, 1);
if (!filecontentBuf) {
fclose(fp);
errno = ENOMEM;
return -1;
}
// read original
if (fread(filecontentBuf, sizeof(char), filecontentLen, fp) <= 0) {
int errnosave = errno;
if (ferror(fp)) {
fclose(fp);
free(filecontentBuf);
errno = errnosave;
return -1;
}
}
// write compressed
char* compressed = RLEcompress(filecontentBuf, filecontentLen, &compsz);
FILE* fpcompWrite = fopen("compressed", "w+");
if (fwrite(compressed, compsz, 1, fpcompWrite) == -1) {
perror("fwrite");
}
fclose(fpcompWrite);

// read compressed
FILE* fpcompRead = fopen("compressed", "r");
if (!fpcompRead) {
perror("fpcompRead");
return 1;
}
char* compBuf = calloc(compsz * 2, 1);
fread(compBuf, compsz, 1, fpcompRead);
fclose(fpcompRead);

// decompress and write file
char* uncompBuf = RLEdecompress(compBuf, compsz, filecontentLen, 0);
FILE* funcomp = fopen("uncompressed", "w+");
fwrite(uncompBuf, filecontentLen, 1, funcomp);
fclose(funcomp);
}

最佳答案

我认为问题在于

for (size_t i = 1; i < occ && retIdx < compressedSize; i++) {
ret[retIdx++] = data[inIdx];
}
应该改成
for (size_t i = 1; i < occ && retIdx < uncompressedSize; i++) {
ret[retIdx++] = data[inIdx];
}
在解压算法中,自 redIdxuncompressedSize 为界,并且可能在极少数情况下它复制的字节数少于应有的字节数。

关于c - RLE 实现每隔一段时间就会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67647668/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com