Created
March 11, 2015 18:07
-
-
Save Suavac/6fb5a66eb186c469f425 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Hencoding.cpp : Defines the entry point for the console application. | |
// SLAWOMIR MLYNAROWICZ - 12100888 | |
// RICHARD DUNN - 12100858 | |
// 1BCT 2014, CT103, NUIG | |
//#include "stdafx.h" | |
#pragma once | |
#define _CRT_SECURE_NO_WARNINGS | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "HuffmanEncoding.h" | |
#include "Utilities.h" | |
int getCommand(); // Function propmts for the command, runs its initial analysis, validation and assign futrher operation | |
void readCommand(char *commandString); // The utility function to split command for its key elements | |
void runCommand(int command); | |
void executeCommand(int operation, int printFile); | |
int prepareForEncoding(char *bufStr); | |
int writeBinaryCode(char *bufStr, int size, int printFile); | |
int compress(int bits_in[]); | |
void readTextFile(); | |
int readBinaryFile(int printFile); | |
void decode(int *arrPtr, struct QueueNode* root, int num, int printFile); | |
int *decompress(int bitNum); | |
void writeTextFile(char *bufStr); | |
FILE *openFile(char *fileName, char *mode); // Open file for reading | |
FILE *writeFile(char *fileName, char *mode);// Open file for writing (use for checking if access wor writing is granted) | |
void closeFile(FILE *fptr); // Close file | |
int bits_out[16]; // Part of decompress function. Allows "returning" of an array. | |
char character[500]; | |
int frequency[500]; | |
int size = 0; | |
char *inputPath; | |
char *outputPath; | |
char bufStr[150000]; | |
int sizeBuf; | |
int main(){ | |
print_Header(); | |
printf("_____________________________________________________\n\n"); | |
getCommand(); | |
return 0; | |
} | |
int getCommand(){ // Function propmts for the command, runs its initial analysis, validation and assign futrher operation | |
char commandString[50]; | |
fflush(stdin); | |
printf("\nCommand Line>> ");gets(commandString); // Prompt for and store the command | |
if(!strlen(commandString))getCommand(); // If no input display error and request new command | |
readCommand(commandString); // // call the utility function to split command for its key elements | |
// INITIAL VALIDATION AND ANALYSIS OF THE COMMAND - DECIDE IF THE UTILITY OR OPERATIONAL FUNCTIONS SHOULD BE EXECUTED | |
/* --- UTILITY --- */ | |
if (!strcmp(array[0], "help" )){ // Display 'Help' information | |
print_Header();print_Help();getCommand();} | |
else if (!strcmp(array[0], "clear")){ system("cls"); print_Header(); getCommand();} // Clear screen | |
else if (!strcmp(array[0], "exit" )){ exit(0);} // Exit program | |
/* --- OPERATIONS --- */ | |
else if (!strcmp(array[0], "encode")){ runCommand(1);} // Perform encoding operation | |
else if (!strcmp(array[0], "decode")){ runCommand(2);} // Perform decoding operation | |
/* --- VALIDATION --- */ | |
else{ printErrorCode(1,NULL); getCommand(); } // Print error - command not recognised, request new command | |
return 0; | |
} | |
void runCommand(int command){ | |
int subCommand; // Variable used for switching between 'file' and 'console' encoding operations | |
switch(command){ //------------------------------------------------------------------------ start of command switch | |
case 1: /////////////// FOR THE ENCODING OPERATIONS ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
if (array[1]==NULL) { // If operation target not specyfied | |
printErrorCode(6,NULL); // Print error | |
getCommand(); // Prompt for next command | |
} | |
else if (!strcmp(array[1], "file")) { subCommand = 1;} // Read from the file | |
else if (!strcmp(array[1], "console")){ subCommand = 2;} // Read from the console | |
else{ printErrorCode(1, NULL); getCommand();} // If operation not recognised return syntax error | |
switch(subCommand){ //------------------------------------------------------------ start of subCommand switch | |
case 1: // RUN ENCODING OPERATION BASED ON INPUT FROM THE FILE | |
if(array[2]==NULL){ // If the file path wasn't provided | |
printErrorCode(2,NULL); // Print error - path is missing | |
getCommand(); // Prompt for next command | |
} | |
else if (array[3] == NULL){ // If no output option was specyfied print to the console only | |
inputPath = processFileName(array[2],1); // Store the input file patch | |
executeCommand(1,0); // Run encoding operation on the file content | |
} | |
// if writing to the file indicated, but output file path not provided | |
else if (!strcmp(array[3], "write") && array[4]==NULL ){ | |
printErrorCode(3,NULL); // Print error - output path is missing | |
getCommand(); // Prompt for next command | |
} | |
// If writing to the file indicated, and output file path provided | |
else if (!strcmp(array[3], "write") && array[4]!=NULL){ | |
inputPath = processFileName(array[2],1); // sStore the input file patch | |
outputPath = array[4]; // Store the output file patch | |
int pathValid = validatePath(outputPath,0); // Check if file exist - prompt for further action | |
if(pathValid){ | |
executeCommand(1,1); // Run encoding operation on the file content | |
} | |
else{ | |
printf("\n<< skipped << \n\n"); | |
printf("_____________________________________________________\n\n"); | |
getCommand(); | |
} | |
} | |
else{ printErrorCode(1, NULL); getCommand();} // If operation not recognised return syntax error | |
break; | |
case 2: // RUN ENCODING OPERATION BASED ON INPUT FROM THE CONSOLE | |
if(array[2]==NULL){ // If secondary operation not indicated | |
executeCommand(2,0); // Print to the console only | |
} | |
// If writing to the file indicated, but output file path not provided | |
else if (!strcmp(array[2], "write") && array[3] ==NULL){ | |
printErrorCode(3,NULL); // Print error - output path is missing | |
getCommand(); // Prompt for next command | |
} | |
// if writing to the file indicated, and output file path provided | |
else if (!strcmp(array[2], "write") && array[3] !=NULL){ | |
outputPath = array[3]; // Store the output file patch | |
int pathValid = validatePath(outputPath,0); // Check if file exist - prompt for further action | |
if(pathValid){ | |
executeCommand(2,1); // Print to the console and the file | |
} | |
else{ | |
printf("\n<< skipped << \n\n"); | |
printf("_____________________________________________________\n\n"); | |
getCommand(); | |
} | |
} | |
else{ // If operation not recognised --------------------------> | |
printErrorCode(1, NULL); // Return syntax error | |
getCommand(); // Prompt for next command | |
} | |
break; | |
} //------------------------------------------------------------ end of subCommand switch | |
break; | |
case 2: /////////////// FOR THE DECODING OPERATIONS ///////////////////////////////////////////////////////////////////////////////////////////////////// | |
if (array[1]==NULL) { // If input file path not provided | |
printErrorCode(2,NULL); // Print error - Missing input file path | |
getCommand(); // Prompt for next command | |
} | |
// If input file path provided and secondary operation not indicated | |
else if(array[1]!=NULL && array[2]==NULL){ | |
inputPath = processFileName(array[1],0); // Store the input file path | |
executeCommand(3,0); // Decode file and print to the screen only | |
} | |
// If input file path provided, secondary operation indicated correctly, but output file path not provided | |
else if(array[2]!=NULL && !strcmp(array[2], "write") && array[3]==NULL ){ | |
printErrorCode(3,NULL); // Print error - Missing output file path | |
getCommand(); // Prompt for next command | |
} | |
// If input file path provided, secondary operation indicated correctly, and output file path provided | |
else if(array[2]!=NULL && !strcmp(array[2], "write") && array[3]!=NULL ){ | |
inputPath = processFileName(array[1],0); // Store the input file path | |
outputPath = array[3]; // Store the output file patch | |
int pathValid = validatePath(outputPath,1); // Check if file exist - prompt for further action | |
if(pathValid){ | |
executeCommand(3,1); // Decode file -> print to the screen and file | |
} | |
else{ | |
printf("\n<< skipped << \n\n"); | |
printf("_____________________________________________________\n\n"); | |
getCommand(); | |
} | |
} | |
else{ // If operation not recognised --------------------------> | |
printErrorCode(1, NULL); // Return syntax error | |
getCommand(); // Prompt for next command | |
} | |
break; | |
} //------------------------------------------------------------------------ end of command switch | |
} | |
///////END OF runCommand(int command); | |
void executeCommand(int operation, int printFile){ | |
int valid=0; // Used for a 'minimum input' validation within the console encoding operation | |
switch (operation){ | |
case 1: // FILE INPUT ENCODING OPERATION --- in this case user provides the 'inputPath' and/or 'outputPath' to the files | |
readTextFile(); // Open file and get its content (text) | |
prepareForEncoding(bufStr); // Process string: 1. Count and store arrays of unique characters and their frequencies | |
// 2. sort arrays in the ascending order: a. by the frequency b. by the character | |
HuffmanCodes(character, frequency, size); // Construct Huffman codes | |
printf("\n\n FILE: %s\n", inputPath); | |
printf( "\n\n Oryginal Text: \n\n %s\n",bufStr );// Print the oryginal tekst | |
print_Table(character, frequency, bufStr, size); // Print table of arrays to the screen: 1. index no 2. unique character 3. frequency 4. prefix code | |
writeBinaryCode(bufStr, size, printFile); // Print message in the oryginal and encoded form to the console and/or file.dat | |
// The 'printFile' var is used as flag to enable/disable file operation | |
// 1 indicates that that oryginal text came from file and will be displayed on the screen | |
memset(bufStr, 0, sizeof(bufStr)); // Clear the buffer | |
size=0; // This counter holds the size of the 'character' and 'frequency' arrays and is set in the prepareForEncoding() function | |
// It has to be re-set to 0 in order to perform another operation correctly | |
printf("_____________________________________________________\n\n"); | |
getCommand(); // Prompt for new command | |
break; | |
case 2: // CONSOLE INPUT ENCODING OPERATION --- in this case user types input into console window and/or provides the 'outputPath' to the file | |
do{ // Prompt for input untill there is at least two unique characters or termination of current operation | |
printf("\nEnter The text: "); // Prompt for and store the string | |
fflush(stdin); | |
gets(bufStr); | |
size=0; | |
if(!strcmp(bufStr,"--q")){ // Exit current operation | |
system("cls"); // Reset | |
print_Header(); | |
getCommand(); | |
break; | |
} | |
else if(!strcmp(bufStr,"--help")){ // Exit current operation | |
print_Help(); // Print help | |
getCommand(); | |
break; | |
} | |
prepareForEncoding(bufStr); | |
if(strlen(character)<=1){ // If there is less than 2 unique characters | |
printErrorCode(5, NULL); // Display error - there must be atleast 2 unique characters | |
valid=0; | |
} | |
else{ | |
valid=1; // End loop | |
HuffmanCodes(character, frequency, size); | |
print_Table(character, frequency, bufStr, size); | |
printf("_____________________________________________________\n\n"); | |
writeBinaryCode(bufStr, size, printFile); | |
size = 0; | |
getCommand(); | |
} | |
}while(valid==0); | |
break; | |
case 3: // FILE INPUT DECODING OPERATION --- in this case user provides the 'inputPath' to the encoded file and/or 'outputPath' for decoded file | |
readBinaryFile(printFile); | |
break; | |
} | |
} | |
/*Function counts the unique characters along with their frequencies in the given string. It creates | |
an arrays of these entities and sorts them in the ascending order in two steps: | |
1. By their frequencies | |
2. By the alphabetical order | |
The above operation are essential for the HuffmanEncoding.h operations */ | |
int prepareForEncoding(char *bufStr ){ | |
memset(frequency, NULL, sizeof(frequency)); | |
memset(character, NULL, sizeof(character)); | |
for (int i=0; i<= strlen(bufStr); i++) { | |
for (int j=0; j <= strlen(bufStr); j++) { | |
if (bufStr[i] == character[j]) { | |
frequency[j] +=1; | |
break; | |
} | |
else if (character[j] == '\0'){ | |
character[j] = bufStr[i]; | |
size++; | |
frequency[j] +=1; | |
break; | |
} | |
} | |
} | |
for (int i = 0; i < strlen(character); ++i){ // Sorting character and frequency arrays in the ascending order | |
for (int j = i + 1; j < strlen(character); ++j){ | |
if (frequency[i] > frequency[j]){ // By the frequency - primary | |
int temp_f = frequency[i]; | |
char temp_c = character[i]; | |
frequency[i] = frequency[j]; | |
frequency[j] = temp_f; | |
character[i] = character[j]; | |
character[j] = temp_c; | |
} | |
if(frequency[i] == frequency[j] && character[i]>character[j]){ // In alphabetical order - secondary | |
//(If two characters happens to have the same frequency) | |
int temp_f = frequency[i]; | |
char temp_c = character[i]; | |
frequency[i] = frequency[j]; | |
frequency[j] = temp_f; | |
character[i] = character[j]; | |
character[j] = temp_c; | |
} | |
} | |
} | |
return 0; | |
} | |
void readTextFile(){ | |
fflush(stdin); | |
FILE *fptr; | |
fptr = openFile(inputPath, "r"); | |
fseek(fptr, 0, SEEK_END); | |
sizeBuf = ftell(fptr); | |
fseek(fptr, 0, SEEK_SET); | |
fgets(bufStr, sizeBuf+1, fptr); | |
closeFile( fptr ); | |
} | |
void writeTextFile(char *bufStr){ | |
FILE *fptr; | |
fptr = writeFile( strcat(outputPath, ".txt"), "w"); | |
for(int i=0; i<strlen(bufStr); i++) | |
fprintf(fptr, "%c", bufStr[i]); | |
closeFile( fptr ); | |
} | |
int compress(int bits_in[]){ // Takes int array contain only 1's or 0's and returns integer representation of same binary sequence | |
int bitNum = 0; // Int to hold encoded bits(16) | |
for (int i=0; i<16; i++){ | |
bitNum |= bits_in[i]; // Write digits from right to left using OR | |
if (i < 15){ | |
bitNum <<= 1; // Shift all digits left by one | |
} | |
} | |
return bitNum;// e.g. a return of '5' symbolises 101 | |
} | |
int *decompress(int bitNum){// Takes a intger and returns its binary value as a pointer to a global int[16] array | |
int readPos = 1<<15; // Start at leftmost bit | |
for (int i=0; i<16; i++){ | |
if (bitNum & readPos){ // Use AND to test for 1 | |
bits_out[i] = 1; | |
} | |
else{ // Else 0 | |
bits_out[i] = 0; | |
} | |
readPos >>= 1; // Shift comparison bit one position to the right | |
} | |
return bits_out; | |
} | |
int writeBinaryCode(char *bufStr, int size, int printFile){ | |
int bufNum = 0; // Counter for cycling through input buffer | |
int strCtr = 0; // Counter for number of characters in message | |
int strCount= 0; // Same as above. Only for storing original message length | |
int temp[16]; // Temp array used when converting between types | |
int msgRay[10000]; // Array to hold integer representations of huffman binary. See function 'int compress(int bits_in[])' | |
char codeStr[150000]; // Array containing char representation of encoded binary message | |
while (bufStr[bufNum] != '\0'){ // Loop over input text until end | |
int c=0; | |
while (bufStr[bufNum] != codes[c++].character);// Find matching character from huffman tree | |
c--; | |
for(int j=0; j<codes[c].length; j++){ | |
codeStr[strCtr++] = (char)(((int)'0')+codes[c].code[j]);// Write corresponding huffman code to codeStr[] | |
} | |
bufNum++; | |
} | |
memset(codeStr,NULL,sizeof codeStr); | |
strCount = strCtr; // Take note of original message length | |
while (strCtr % 16 != 0){ // Fill out last int with 0's if not modulo 16 | |
codeStr[strCtr++] = '0'; | |
} | |
int msgLenInt = strCtr/16; // Take note of number of ints to be created to hold binary | |
int t=0; | |
for (int i=0; i<msgLenInt; i++){ | |
for (int j=0; j<16; j++){ | |
temp[j] = codeStr[t] - '0'; // Convert back to type int for use in compress() function | |
t++; | |
} | |
msgRay[i] = compress(temp); // Arrays of size 16 passed to compress() to create integer representations of binary code | |
} | |
printf(" Total size of header: %d Bytes\n\n", (sizeof(char)*size)+(sizeof(int)*size)+sizeof(int)+sizeof(int)); | |
printf(" Total size of compressed message: %d Bytes\n\n", sizeof(int)*msgLenInt); | |
if (printFile){ // if writing to the file enabled---- | |
FILE *fptr; | |
fptr = writeFile(strcat(outputPath, ".dat"), "wb"); | |
/* Write a header to binary file for decoding*/ | |
fwrite( &size, sizeof(int), 1, fptr ); // Number of unique charaters | |
fwrite( &strCount, sizeof(int), 1, fptr ); // Size of original message | |
fwrite( &character, sizeof(char)*size, 1, fptr); // Array of all unique characters | |
fwrite( &frequency, sizeof(int)*size, 1, fptr); // Array of all unique characters frequencies | |
/* Write encoded message to rest of binary file*/ | |
for (int i=0; i<msgLenInt; i++){ | |
fwrite( &msgRay[i], sizeof(int), 1, fptr ); | |
} | |
printf(" -- Binary file created! : %s\n\n", outputPath); | |
closeFile( fptr ); | |
} | |
return 0; | |
} | |
int readBinaryFile(int printFile){ | |
int sizeBin = 0; // Number of unique characters expected in binary file header | |
int strCount= 0; // Number of characters in original message | |
char charBin[1000]; // Temp array for unique characters | |
int freqBin[1000]; // Temp array for character frequencies | |
int bufBin[15000]; // Temp array for encoded message | |
int *temp; // Pointer to temp binary array. Used with decompress() function | |
int msgRay[5000]; // Buffer for 'message' ints | |
fflush(stdin); | |
FILE *fptr; | |
fptr = openFile(inputPath, "rb"); | |
if ( fptr == NULL ){ | |
printErrorCode(4,inputPath); | |
getCommand(); | |
} | |
else{ | |
/* Read in header in same order as was written to file*/ | |
fread( &sizeBin, sizeof( int ), 1, fptr ); | |
fread( &strCount, sizeof( int ), 1, fptr ); | |
fread( &charBin, sizeof(char)*sizeBin, 1, fptr); | |
fread( &freqBin, sizeof(int)*sizeBin, 1, fptr); | |
int ctr = (strCount/16)+1; // Determine number of 'message' integers to read from file. +1 | |
/* Read encoded message and decompress */ | |
int pos = 0; | |
for (int i=0; i<ctr; i++){ | |
fread( &msgRay[i], sizeof(int), 1, fptr);// Read message (per int) | |
temp = decompress(msgRay[i]); // Decompress (per int) | |
for (int j=0; j<16; j++){ | |
bufBin[pos] = temp[j]; // Append to array | |
pos++; | |
} | |
} | |
struct QueueNode* root = buildHuffmanTree(charBin, freqBin, sizeBin); | |
decode(bufBin, root, strCount, printFile); // Decode message using huffman tree | |
} | |
closeFile( fptr ); | |
getCommand(); | |
return 0; | |
} | |
/* Funtion to decode binary message by 'running' along the huffman binary tree | |
Arguments are: Pointer to binary array | |
Pointer to huffman tree root node | |
Length of original message | |
Argument for printing decoded message to file */ | |
void decode(int *arrPtr, struct QueueNode* root, int bufPos, int printFile){ | |
int i=0; | |
QueueNode *temp = root; | |
printf("\n\n Decoded text from the %s file\:\n\n \" ", inputPath); | |
while(bufPos > 0) { | |
if (*arrPtr == 0){ | |
temp = temp->left; // If branch is '0', go to left child | |
arrPtr++; | |
bufPos--; | |
} | |
else { | |
temp = temp->right;// If branch is '1', go to right child | |
arrPtr++; | |
bufPos--; | |
} | |
if (isLeaf(temp)){ // If node is a leaf, return character | |
printf("%c", temp->data); | |
bufStr[i]=temp->data; | |
i++; | |
temp = root; // Return to start of huffman tree | |
} | |
} | |
printf(" \" \n\n "); | |
if(printFile){ | |
bufStr[i]='\0'; | |
writeTextFile(bufStr); | |
printf("\n\n File %s created succesfully!\n\n", outputPath); | |
} | |
putchar('\n'); | |
if (root != temp){ | |
printf("Unreadable data in file\n"); | |
} | |
} | |
FILE * writeFile(char *fileName, char *mode){ | |
FILE *fptr = fopen(fileName, mode); | |
if ( fptr == NULL ) { // Check if file can be written in given location | |
printErrorCode(7,outputPath); // If not print error - Access Denied ! | |
getCommand(); // Prompt for the command | |
} | |
return fptr; | |
} | |
FILE * openFile(char *fileName, char *mode){ | |
FILE *fptr = fopen(fileName, mode); | |
if ( fptr == NULL ) { // Check if file exists | |
printErrorCode(4,inputPath); // If not print error - file <file name> doesn't exist | |
getCommand(); // Prompt for the command | |
} | |
return fptr; | |
} | |
void closeFile(FILE *fptr){ | |
fclose(fptr); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment