Skip to content

Instantly share code, notes, and snippets.

@Suavac
Created March 11, 2015 18:07
Show Gist options
  • Save Suavac/6fb5a66eb186c469f425 to your computer and use it in GitHub Desktop.
Save Suavac/6fb5a66eb186c469f425 to your computer and use it in GitHub Desktop.
// 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