Here is a simple decompressor in C. I'd very much appreciate any advice or comments about the structure/logic of the program, style of the code, or reusability of the features. I'm a real novice and really eager to learn from people here, so fire away! **lzw.h:** /** * lzw.h * Function declarations for lzw decompression algorithm. */ #ifndef LZW_H #define LZW_H #include <stdio.h> #include <stdlib.h> /** * Frees all blocks between 'from' and 'to' (inclusive) in the dict. */ void free_dict (unsigned char* dict[], int from, int to); /** * Enters the first 256 ASCII values into dict. */ void load_dict_defaults (unsigned char* dict[]); /** * Reads 12 bits from source and returns them as an int. */ int fread_twelve(FILE* source); /** * LZW decompression of source to dest. * Returns 0 if successful, a positive integer otherwise. */ int decompress (FILE* source, FILE* dest); #endif // LZW_H **decompress.c:** /** * decompress.c * Implementation of LZW decompression algorithm using 12-bit fixed-width compression format. * * Usage: decompress */ #include "lzw.h" #include <stdio.h> #include <stdlib.h> int main (int argc, char* argv[]) { // check for correct number of args if (argc != 3) { printf("Usage: decompress source destination\n"); return 1; } // open compressed file FILE* source = fopen(argv[1], "r"); if (source == NULL) { printf("Error: cannot open %s\n", argv[1]); return 1; } // open destination file FILE* dest = fopen(argv[2], "w"); if (dest == NULL) { printf("Error: cannot open %s\n", argv[2]); return 1; } // decompress if (decompress(source, dest) == 1) { printf("Decompression failed\n"); fclose(source); fclose(dest); return 1; } else { fclose(source); fclose(dest); return 0; } } **lzw.c:** /** * lzw.c * Implementation of LZW decompression algorithm using 12-bit fixed-width compression format. * */ #include "lzw.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> unsigned char* dictionary[4096]; /** * Enters the first 256 ASCII values into dict. */ void load_dict_defaults (unsigned char* dict[]) { unsigned char* temp; unsigned char c = 0; for (int i = 0; i < 256; i++) { temp = calloc(2, sizeof(unsigned char)); temp[0] = c++; dict[i] = temp; } } /** * Frees all blocks between 'from' and 'to' (inclusive) in the dict. */ void free_dict (unsigned char* dict[], int from, int to) { for (int i = from; i <= to; i++) { free(dict[i]); } } /** * Reads 12 bits from source and returns them as an int. * Returns 0 on an error or EOF. */ int fread_twelve(FILE* source) { int value; static bool left = true; unsigned char buf[2]; if (left) { // if left, read two bytes and calculate int if (fread(buf, 1, 2, source) != 2) {return 0;} if (feof(source)) // we're at a 16-bit end! { value = (buf[0] << 8) | buf[1]; } else { value = (buf[0] << 4) | (buf[1] >> 4); } left = false; } else { // if right, rewind source by one byte, read two bytes and calculate int fseek(source, -1, SEEK_CUR); if (fread(buf, 1, 2, source) != 2) {return 0;} value = ((buf[0] & 0x0F) << 8) | buf[1]; left = true; } return value; } /** * LZW decompression of source to dest. * Returns 0 if successful, a positive integer otherwise. */ int decompress (FILE* source, FILE* dest) { load_dict_defaults(dictionary); int dictPos = 256; int prevCode, currCode; unsigned char* prevString, *currString; // read in the first character currCode = fread_twelve(source); if (dictionary[currCode] == NULL) { return 1; } size_t size; size = strlen((char*)dictionary[currCode]); currString = calloc(size + 2, sizeof(char)); //+2 for upcoming char and null memcpy(currString, dictionary[currCode], size+1); fprintf(dest, "%s", currString); prevCode = currCode; prevString = currString; // read in the rest of the characters while ( (currCode = fread_twelve(source)) && currCode ) { if (dictionary[currCode] == NULL) { return 1; } size = strlen((char*)dictionary[currCode]); currString = calloc(size + 2, sizeof(char)); //+2 for upcoming char and null currString = calloc((strlen((char*)dictionary[currCode]) + 2), sizeof(char)); memcpy(currString, dictionary[currCode], size+1); fprintf(dest, "%s", currString); if (currCode > dictPos) { dictionary[dictPos++] = (unsigned char*) strncat((char*)prevString, (char*)prevString, 1); } else { dictionary[dictPos++] = (unsigned char*) strncat((char*)prevString, (char*)currString, 1); } // restart dict if full. if (dictPos >= 4096) { free_dict(dictionary, 256, 4096); dictPos = 256; } prevCode = currCode; prevString = currString; } free_dict(dictionary, 0, dictPos-1); return 0; }