Revision bf2e204c-132c-42cb-aaa8-80cfa30f84e8 - Code Review Stack Exchange

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! :-)

Thanks in advance.

**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;
 }

AltStyle によって変換されたページ (->オリジナル) /