I've coded an SZDD decompression routine based on this pseudo-code. Testing it on one of Sonic CD's files gets me a segmentation fault. Next, I've tried to look up more information and compared it to other implementations. I've found one omission in the pseudo-code I took as a base. However, even after fixing that, I still get a segmentation fault. At this point, I'm out of ideas. What the heck is wrong with this code? Code (C): unsigned char* szdd_decompress(char* p_filename) { unsigned char* p_bytes = 0; unsigned int bytecnt = 0; unsigned char cntbytes[4]; unsigned int bytepos = 0; unsigned char dictionary[4096]; unsigned int pos = 4096 - 16; FILE* fp = 0; fp = fopen(p_filename, "rb"); if (fp == 0) return 0; if (fgetc(fp) != 'S') return 0; // magic if (fgetc(fp) != 'Z') return 0; if (fgetc(fp) != 'D') return 0; if (fgetc(fp) != 'D') return 0; if (fgetc(fp) != 0x88) return 0; if (fgetc(fp) != 0xF0) return 0; if (fgetc(fp) != 0x27) return 0; if (fgetc(fp) != 0x33) return 0; if (fgetc(fp) != 'A') return 0; // mode fgetc(fp); // last character of filename fread(cntbytes, 1, 4, fp); bytecnt = read_uint_littleendian(cntbytes); p_bytes = (unsigned char*)malloc(bytecnt); memset(dictionary, ' ', sizeof(dictionary)); do { unsigned int control = fgetc(fp); if (feof(fp)) break; for (unsigned int bit = 1; bit & 0xFF; bit <<= 1) { if (control & bit) { p_bytes[bytepos] = dictionary[pos] = fgetc(fp); ++pos; pos %= 4096; ++bytepos; } else { unsigned int matchpos = fgetc(fp); unsigned int matchlen = fgetc(fp); matchpos |= (matchlen & 0xF0) << 4; matchlen = (matchlen & 0x0F) + 3; while (matchlen-- != 0) { p_bytes[bytepos] = dictionary[pos] = dictionary[matchpos]; ++pos; pos %= 4096; ++matchpos; matchpos %= 4096; ++bytepos; } } } } while (1); fclose(fp); return p_bytes; }
Add a feof() check after the other fgetc()'s Code (C): if (control & bit) { p_bytes[bytepos] = dictionary[pos] = fgetc(fp); if (feof(fp)) break; // ADD THIS ++pos; pos %= 4096; ++bytepos; } else { unsigned int matchpos = fgetc(fp); unsigned int matchlen = fgetc(fp); if (feof(fp)) break; // ADD THIS matchpos |= (matchlen & 0xF0) << 4; matchlen = (matchlen & 0x0F) + 3; Basically, the final set of data can end before "bit" overflows back to 0. The breaks work with the for loop, because they'll break out of it, and then go back to the top of the do/while loop, which does another feof() check and breaks out of that.