diff --git a/AppIcon.rc b/AppIcon.rc deleted file mode 100644 index bf46194..0000000 --- a/AppIcon.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "appIcon.ico" \ No newline at end of file diff --git a/Huffman-algorithm-implementation-in-Qt/HuffmanCoding.pro b/Huffman-algorithm-implementation-in-Qt/HuffmanCoding.pro new file mode 100644 index 0000000..5283fad --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/HuffmanCoding.pro @@ -0,0 +1,24 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = HuffmanCoding +TEMPLATE = app + + +SOURCES += main.cpp\ + choose.cpp \ + encoding.cpp \ + decoding.cpp \ + huffman.cpp \ + guiutils.cpp + +HEADERS += choose.h \ + encoding.h \ + decoding.h \ + huffman.h \ + guiutils.h + +FORMS += choose.ui \ + encoding.ui \ + decoding.ui diff --git a/Huffman-algorithm-implementation-in-Qt/choose.cpp b/Huffman-algorithm-implementation-in-Qt/choose.cpp new file mode 100644 index 0000000..b2723d2 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/choose.cpp @@ -0,0 +1,58 @@ +#include "choose.h" +#include "ui_choose.h" +#include "encoding.h" +#include "decoding.h" + +// Конструктор: +Choose::Choose(QWidget *parent) : + QDialog(parent), + ui(new Ui::Choose) +{ + ui->setupUi(this); + + // Связать клик на кнопку "Сжать данные" с методом showCompressDialog(): + connect(ui->compressButton, SIGNAL(clicked()), this, SLOT(showCompressDialog())); + + // Связать клик на кнопку "Восстановить данные" с методом showDecompressDialog(): + connect(ui->decompressButton, SIGNAL(clicked()), this, SLOT(showDecompressDialog())); +} + +// Деструктор: +Choose::~Choose() +{ + delete ui; +} + +// Показать диалоговое окно для сжатия данных: +void Choose::showCompressDialog() +{ + // Диалоговое окно для сжатия данных: + Encoding* en = new Encoding(this); + // Если в конструктор передавать указатель на родительский виджет, + // то диалоговое окно будет отцентрировано относительно родителя. + + // Делаем размеры диалогового окна не изменяемыми: + en->setFixedSize(en->size()); + + en->setWindowTitle("Сжати данных по алгоритму Хаффмана"); + + // Показать диалоговое окно: + en->exec(); +} + +// Показать диалоговое окно для восстановления данных: +void Choose::showDecompressDialog() +{ + // Диалоговое окно для восстановления данных: + Decoding* de = new Decoding(this); + // Если в конструктор передавать указатель на родительский виджет, + // то диалоговое окно будет отцентрировано относительно родителя. + + // Делаем размеры диалогового окна не изменяемыми: + de->setFixedSize(de->size()); + + de->setWindowTitle("Восстановление данных сжатых по алгоритму Хаффмана"); + + // Показать диалоговое окно: + de->exec(); +} diff --git a/choose.h b/Huffman-algorithm-implementation-in-Qt/choose.h similarity index 51% rename from choose.h rename to Huffman-algorithm-implementation-in-Qt/choose.h index 38be58e..9e4760d 100644 --- a/choose.h +++ b/Huffman-algorithm-implementation-in-Qt/choose.h @@ -1,8 +1,3 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - #ifndef CHOOSE_H #define CHOOSE_H @@ -12,19 +7,26 @@ namespace Ui { class Choose; } +// Главное диалоговое окно приложения: class Choose : public QDialog { Q_OBJECT public: + // Конструктор: explicit Choose(QWidget *parent = 0); + + // Деструктор: ~Choose(); private: Ui::Choose *ui; private slots: + // Показать диалоговое окно для сжатия данных: void showCompressDialog(); + + // Показать диалоговое окно для восстановления данных: void showDecompressDialog(); }; diff --git a/Huffman-algorithm-implementation-in-Qt/choose.ui b/Huffman-algorithm-implementation-in-Qt/choose.ui new file mode 100644 index 0000000..48e4bb4 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/choose.ui @@ -0,0 +1,50 @@ + + + Choose + + + + 0 + 0 + 300 + 200 + + + + Сжатие и восстановление данных + + + + :/images/icon.png:/images/icon.png + + + + + 20 + 20 + 256 + 64 + + + + Сжать данные + + + + + + 20 + 110 + 256 + 64 + + + + Восстановить данные + + + + + + + diff --git a/Huffman-algorithm-implementation-in-Qt/decoding.cpp b/Huffman-algorithm-implementation-in-Qt/decoding.cpp new file mode 100644 index 0000000..03a3377 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/decoding.cpp @@ -0,0 +1,57 @@ +#include "decoding.h" +#include "ui_decoding.h" +#include "QFileDialog" +#include "guiutils.h" + +// Конструктор: +Decoding::Decoding(QWidget *parent) : + QDialog(parent), + ui(new Ui::Decoding) +{ + ui->setupUi(this); + + // Связать кнопку "Обзор…" с методом browseInputFile(): + connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseInputFile())); + + // Связать кнопку "Восстановить данные" с методом decompressFile(): + connect(ui->decodeButton, SIGNAL(clicked()), this, SLOT(decompressFile())); +} + +// Деструктор: +Decoding::~Decoding() +{ + delete ui; +} + +// Метод для выбора файла для восстановления: +void Decoding::browseInputFile() +{ + // Открыть диалоговое окно для выбора файла: + inputFileName = QFileDialog::getOpenFileName(this, + tr("Открыть файл"), + QString(), + tr("Бинарные файлы (*.bin)")); + + ui->inputFile->setText(inputFileName); +} + +// Восстановить сжатый файл: +void Decoding::decompressFile() +{ + // Если имя файла пустое: + if (inputFileName == "") + { + showDoneMessage("Пожалуйста, выберите файл.", "Восстановление данных"); + } + + // Иначе, если имя файла есть: + else + { + // Имя файла: + QByteArray byteArray = inputFileName.toUtf8(); + const char* inputFile = byteArray.constData(); + + // Сжать файл: + huffmanDecode(inputFile); + } +} diff --git a/Huffman-algorithm-implementation-in-Qt/decoding.h b/Huffman-algorithm-implementation-in-Qt/decoding.h new file mode 100644 index 0000000..0e29de0 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/decoding.h @@ -0,0 +1,43 @@ +#ifndef DECODING_H +#define DECODING_H + +#include +#include "huffman.h" + +namespace Ui { +class Decoding; +} + +class Decoding : public QDialog +{ + Q_OBJECT + +public: + + // Конструктор: + explicit Decoding(QWidget *parent = 0); + + // Деструктор: + ~Decoding(); + + // Получить имя входного файла: + QString getInputFileName(); + +private: + + // Пользовательский интерфейс: + Ui::Decoding *ui; + + // Имя входного файла: + QString inputFileName; + +public slots: + + // Метод для выбора файла для восстановления: + void browseInputFile(); + + // Восстановить сжатый файл: + void decompressFile(); +}; + +#endif // DECODING_H diff --git a/Huffman-algorithm-implementation-in-Qt/decoding.ui b/Huffman-algorithm-implementation-in-Qt/decoding.ui new file mode 100644 index 0000000..41a3a1e --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/decoding.ui @@ -0,0 +1,62 @@ + + + Decoding + + + + 0 + 0 + 500 + 79 + + + + Dialog + + + + :/images/icon.png:/images/icon.png + + + + + 10 + 40 + 475 + 23 + + + + Восстановить данные + + + + + + 10 + 10 + 401 + 20 + + + + + + + + + + 420 + 10 + 64 + 23 + + + + Обзор… + + + + + + diff --git a/Huffman-algorithm-implementation-in-Qt/encoding.cpp b/Huffman-algorithm-implementation-in-Qt/encoding.cpp new file mode 100644 index 0000000..401c5dd --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/encoding.cpp @@ -0,0 +1,57 @@ +#include "encoding.h" +#include "ui_encoding.h" +#include "QFileDialog" +#include "guiutils.h" + +// Конструктор: +Encoding::Encoding(QWidget *parent) : + QDialog(parent), + ui(new Ui::Encoding) +{ + ui->setupUi(this); + + // Связать кнопку "Обзор…" с методом browseInputFile(): + connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseInputFile())); + + // Связать кнопку "Сжать данные" с методом compressFile(): + connect(ui->encodeButton, SIGNAL(clicked()), this, SLOT(compressFile())); +} + +// Деструктор: +Encoding::~Encoding() +{ + delete ui; +} + +// Метод для выбора файла для сжатия: +void Encoding::browseInputFile() +{ + // Открыть диалоговое окно для выбора файла: + inputFileName = QFileDialog::getOpenFileName(this, + tr("Открыть файл"), + QString(), + tr("Текстовые файлы (*.txt)")); + + ui->inputFile->setText(inputFileName); +} + +// Метод для сжатия файла: +void Encoding::compressFile() +{ + // Если имя файла пустое: + if (inputFileName == "") + { + showDoneMessage("Пожалуйста, выберите файл.", "Сжатие данных"); + } + + // Иначе, если имя файла есть: + else + { + // Имя файла: + QByteArray byteArray = inputFileName.toUtf8(); + const char* inputFile = byteArray.constData(); + + // Сжать файл: + huffmanEncode(inputFile); + } +} diff --git a/Huffman-algorithm-implementation-in-Qt/encoding.h b/Huffman-algorithm-implementation-in-Qt/encoding.h new file mode 100644 index 0000000..bc2afb1 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/encoding.h @@ -0,0 +1,43 @@ +#ifndef ENCODING_H +#define ENCODING_H + +#include +#include "huffman.h" + +namespace Ui { +class Encoding; +} + +class Encoding : public QDialog +{ + Q_OBJECT + +public: + + // Конструктор: + explicit Encoding(QWidget *parent = 0); + + // Деструктор: + ~Encoding(); + + // Получить имя входного файла: + QString getInputFileName(); + +private: + + // Пользовательский интерфейс: + Ui::Encoding *ui; + + // Имя входного файла: + QString inputFileName; + +public slots: + + // Метод для выбора файла для сжатия: + void browseInputFile(); + + // Метод для сжатия файла: + void compressFile(); +}; + +#endif // ENCODING_H diff --git a/Huffman-algorithm-implementation-in-Qt/encoding.ui b/Huffman-algorithm-implementation-in-Qt/encoding.ui new file mode 100644 index 0000000..c3909f6 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/encoding.ui @@ -0,0 +1,62 @@ + + + Encoding + + + + 0 + 0 + 500 + 79 + + + + Dialog + + + + :/images/icon.png:/images/icon.png + + + + + 10 + 40 + 475 + 23 + + + + Сжать данные + + + + + + 10 + 10 + 401 + 20 + + + + + + + + + + 420 + 10 + 64 + 23 + + + + Обзор… + + + + + + diff --git a/Huffman-algorithm-implementation-in-Qt/guiutils.cpp b/Huffman-algorithm-implementation-in-Qt/guiutils.cpp new file mode 100644 index 0000000..f4b5e71 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/guiutils.cpp @@ -0,0 +1,12 @@ +#include "guiutils.h" +#include "QMessageBox" + +// Показать информационное сообщение: +void showDoneMessage(const char* msg, const char* title) +{ + QMessageBox msgBox; + msgBox.setText(msg); + msgBox.setWindowTitle(title); + msgBox.setIcon(QMessageBox::Information); + msgBox.exec(); +} diff --git a/Huffman-algorithm-implementation-in-Qt/guiutils.h b/Huffman-algorithm-implementation-in-Qt/guiutils.h new file mode 100644 index 0000000..42572e5 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/guiutils.h @@ -0,0 +1,7 @@ +#ifndef GUIUTILS_H +#define GUIUTILS_H + +// Показать информационное сообщение: +void showDoneMessage(const char* msg, const char* title); + +#endif // GUIUTILS_H diff --git a/Huffman-algorithm-implementation-in-Qt/huffman.cpp b/Huffman-algorithm-implementation-in-Qt/huffman.cpp new file mode 100644 index 0000000..9a0b1a6 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/huffman.cpp @@ -0,0 +1,512 @@ +#include "huffman.h" +#include "QProgressDialog" +#include "guiutils.h" + +// Посчитать частотность всех символов и сохранить в списке: +void calcCharFreq(FILE* src, unsigned int* freqList) +{ + int c; // символ. + + // Считываем очередной символ из файла: + while((c = fgetc(src)) != EOF) + { + freqList[c]++; + } + + // Перемещаемся в начало файла: + rewind(src); +} + +// Построить список узлов Хаффмана (частотности сортируются по возрастанию): +void buildNodeList(HuffNode** nodeList, unsigned int* freqList) +{ + unsigned int i; + HuffNode* newNode; + + for (i = 0; i < CHARS_LIMIT; i++) + { + // Если частотность символа больше 0, + // т.е. символ встречался во входном файле: + if (freqList[i] > 0) + { + // Создание нового узла дерева Хаффмана: + newNode = (HuffNode *)calloc(1, sizeof(HuffNode)); + newNode->charCode = i; + newNode->freq = freqList[i]; + newNode->next = NULL; + newNode->left = NULL; + newNode->right = NULL; + newNode->leaf = true; + + // Добавление нового узла в дерево Хаффмана: + addToNodeList(nodeList, newNode); + } + } +} + +// Построить список узлов из раскодированных частотностей: +void buildNodeList(HuffNode** nodeList, HuffFreq* hFreq, unsigned int numOfFreq) +{ + unsigned int i; + HuffNode* newNode; + + for (i = 0; i < numOfFreq; i++) + { + newNode = (HuffNode *)malloc(sizeof(HuffNode)); + newNode->charCode = hFreq[i].charCode; + newNode->freq = hFreq[i].freq; + newNode->next = 0; + newNode->left = 0; + newNode->right = 0; + newNode->leaf = true; + + addToNodeList(nodeList, newNode); + } +} + + +// Добавить новый узел в список узлов Хаффмана (по возрастающему порядку): +void addToNodeList(HuffNode** nodeList, HuffNode* newNode) +{ + HuffNode* prevNode = NULL; // предыдущий узел. + HuffNode* currNode = *nodeList; // текущий узел. + + while(currNode != NULL && currNode->freq < newNode->freq) + { + prevNode = currNode; + currNode = prevNode->next; + } + + newNode->next = currNode; + + if(prevNode == NULL) + { + *nodeList = newNode; + } + else + { + prevNode->next = newNode; + } +} + +// Построить дерево Хаффмана из списка узлов Хаффмана: +void buildHuffTree(HuffNode** nodeList) +{ + HuffNode* leftNode, *rightNode; + HuffNode* newNode; + + while ((*nodeList)->next) + { + leftNode = *nodeList; + *nodeList = leftNode->next; + + rightNode = *nodeList; + *nodeList = rightNode->next; + + newNode = (HuffNode *)calloc(1, sizeof(HuffNode)); + newNode->charCode = 0; + newNode->freq = leftNode->freq + rightNode->freq; + newNode->next = NULL; + newNode->left = leftNode; + newNode->right = rightNode; + newNode->leaf = false; + + addToNodeList(nodeList, newNode); + } +} + +// Построить таблицу перекодировки Хаффмана: +bool buildHuffCode(HuffNode* treeRoot, HuffCode* hCode, unsigned char goalChar) +{ + if (treeRoot->charCode == goalChar && treeRoot->leaf) + { + return true; + } + + if (treeRoot->left) + { + hCode->code[hCode->length] = '0'; + hCode->length++; + + if (hCode->length == MAX_CODE_SIZE) + { + printf("Code size exceeds limit!"); + return false; + } + + if (buildHuffCode(treeRoot->left, hCode, goalChar)) + { + hCode->code[hCode->length] = 0; + return true; + } + else + { + hCode->length--; + hCode->code[hCode->length] = 0; + } + } + + if (treeRoot->right) + { + hCode->code[hCode->length] = '1'; + hCode->length++; + + if (buildHuffCode(treeRoot->right, hCode, goalChar)) + { + return true; + } + else + { + hCode->length--; + hCode->code[hCode->length] = 0; + } + } + + return false; +} + +// Вывести заголовок Хаффмана в выходной файл: +void writeHeader(FILE* dest, unsigned int numOfFreq, unsigned int fileSize) +{ + HuffHeader hHeader; + + hHeader.numOfFreq = numOfFreq; // количество частотностей. + hHeader.fileSize = fileSize; // размер файла. + + fwrite(&hHeader, sizeof(hHeader), 1, dest); +} + +// Вывести символ и его частотность в выходной файл: +void writeFreq(FILE* dest, unsigned int* freqList) +{ + unsigned int i; + HuffFreq hFreq; + for (i = 0; i < CHARS_LIMIT; i++) + { + // Если частотность символа больше 0, + // т.е. символ встречался во входном файле: + if (freqList[i] > 0) + { + hFreq.charCode = i; // код символа. + hFreq.freq = freqList[i]; // частотность символа. + + fwrite(&hFreq, sizeof(HuffFreq), 1, dest); + } + } +} + +// Вывести закодированные по Хаффману данные в выходной файл: +void writeEncodedData(FILE* src, FILE* dest, HuffCode* huffCodeTable, unsigned int fileSize) +{ + int i, c; + unsigned int bits = 0; + char currChar = 0; + HuffCode currCode; + bool cancel = false; + unsigned int interval = fileSize/100; + int progress = 1; + unsigned int bytes = 0; + + QProgressDialog progressDialog("Сжатие данных...", "Отмена", 0, fileSize, nullptr); + progressDialog.setWindowModality(Qt::WindowModal); + progressDialog.setValue(0); + + while ((c = fgetc(src)) != EOF) + { + bytes++; + currCode = huffCodeTable[c]; + + for (i = 0; i < currCode.length; i++) + { + currChar = (currChar << 1) + (currCode.code[i] == '1' ? 1 : 0); + bits++; + + if(bits == 8) + { + fputc(currChar, dest); + currChar = 0; + bits = 0; + } + } + + + if (bytes > interval * progress) + { + progressDialog.setValue(progress); + progress++; + } + + if (progressDialog.wasCanceled()) + { + cancel = true; + showDoneMessage("Отменено!", "Сжатие данных"); + break; + } + } + + if (bits > 0) + { + currChar = currChar << (8 - bits); + fputc(currChar, dest); + } + + progressDialog.setValue(fileSize); + + if (!cancel) + { + showDoneMessage("Файл успешно сжат!", "Сжатие данных"); + } +} + +// Вывести раскодированные по Хаффману данные в выходной файл: +void writeDecodedData(FILE * src, FILE * dest, HuffNode * rootTree, unsigned int fileSize) +{ + int bit = -1; + int c; + unsigned int bytesWritten = 0; + HuffNode * currNode = rootTree; + bool cancel = false; + unsigned int interval = fileSize/100; + int progress = 1; + + QProgressDialog progressDialog("Восстановление данных...", "Отмена", 0, fileSize, nullptr); + progressDialog.setWindowModality(Qt::WindowModal); + progressDialog.setValue(0); + + while (bytesWritten < fileSize) + { + if (bit < 0) + { + c = fgetc(src); + + if (c == EOF) + { + break; + } + + bit = 7; + } + + if ((c >> bit) & 1) + { + currNode = currNode->right; + } + else + { + currNode = currNode->left; + } + + if (currNode->leaf) + { + fputc(currNode->charCode, dest); + bytesWritten++; + currNode = rootTree; + } + + bit--; + + if (bytesWritten > interval*progress) + { + progressDialog.setValue(interval*progress); + progress++; + } + + if (progressDialog.wasCanceled()) + { + cancel = true; + showDoneMessage("Омененно!", "Восстановление данных"); + break; + } + } + + progressDialog.setValue(fileSize); + + if(!cancel) + { + showDoneMessage("Файл успешно восстановлен!", "Восстановление данных"); + } +} + +// Освободить память занятую по дерево Хаффмана: +void freeHuffTree(HuffNode* treeRoot) +{ + if (treeRoot) // если узел не пустой. + { + freeHuffTree(treeRoot->left); // удаляем левую часть. + freeHuffTree(treeRoot->right); // удаляем правую часть. + + // После того как левая и правая часть удалены, + // удаляем сам узел: + free(treeRoot); + } +} + +// Закодировать файл по Хаффману: +void huffmanEncode(const char* inputFile) +{ + // Открыть исходный файл: + FILE* src = fopen(inputFile, "rb"); + + // Проверка на существование входного файла: + if (src == NULL) + { + fprintf(stderr, "Невозможно открыть входной файл."); + exit(EXIT_FAILURE); + } + + // Открыть выходной файл: + char outputPath[1000]; + const char * fileExtension = ".bin"; + outputFilePath(inputFile, outputPath, fileExtension); + FILE * dest = fopen(outputPath, "wb"); + + // Получить размер входного файла: + unsigned int fileSize; + fileSize = getFileSize(src); + + // Посчитать частотности символов: + unsigned int * freqList; + freqList = (unsigned int *)calloc(CHARS_LIMIT, sizeof(unsigned int)); + calcCharFreq(src, freqList); + + // Посчитать количество частотностей + // (т.е. тех которые больше нуля): + unsigned int numOfFreq; + numOfFreq = calcNumOfFreq(freqList); + + // Построить список Хаффмана (частотности отсортированные по возрастанию): + HuffNode* nodeList = NULL; + buildNodeList(&nodeList, freqList); + + // Построить дерево Хаффмана: + buildHuffTree(&nodeList); + HuffNode * treeRoot = nodeList; + + // Построить таблицу Хаффмана: + unsigned int i; + HuffCode newCode; + HuffCode * huffCodeTable; + huffCodeTable = (HuffCode *)calloc(CHARS_LIMIT, sizeof(HuffCode)); + for(i=0; i 0) + { + newCode.length = 0; + buildHuffCode(treeRoot, &newCode, i); + huffCodeTable[i] = newCode; + } + } + + // Записать заголовок: + writeHeader(dest, numOfFreq, fileSize); + + // Записать частотности: + writeFreq(dest, freqList); + + // Вывести закодированные по Хаффману данные в выходной файл: + writeEncodedData(src, dest, huffCodeTable, fileSize); + + // Освободить память: + freeHuffTree(treeRoot); + treeRoot = NULL; + free(huffCodeTable); + free(freqList); + + // Закрыть файлы: + fclose(src); + fclose(dest); +} + +// Раскодировать файл по Хаффману: +void huffmanDecode(const char * inputFile) +{ + // Открыть исходный файл: + FILE *src = fopen(inputFile, "rb"); + + // Проверка на существование входного файла: + if (src == NULL) + { + fprintf(stderr, "Невозможно открыть входной файл."); + exit(EXIT_FAILURE); + } + + // Открыть выходной файл: + char outputPath[1000]; + const char* fileExtension = ".txt"; + outputFilePath(inputFile, outputPath, fileExtension); + FILE* dest = fopen(outputPath, "wb"); + + // Считать заголовок: + HuffHeader hHeader; + fread(&hHeader, sizeof(hHeader), 1, src); + + // Считать частотности: + HuffFreq* hFreq = (HuffFreq *)calloc(hHeader.numOfFreq, sizeof(HuffFreq)); + fread(hFreq, sizeof(HuffFreq), hHeader.numOfFreq, src); + + // Построить список частотностей: + HuffNode* nodeList = NULL; + buildNodeList(&nodeList, hFreq, hHeader.numOfFreq); + + // Построить дерево Хаффмана: + buildHuffTree(&nodeList); + + // Вывести раскодированные по Хаффману данные в выходной файл: + writeDecodedData(src, dest, nodeList, hHeader.fileSize); + + // Освободить память: + freeHuffTree(nodeList); + nodeList = NULL; + free(hFreq); + + // Закрыть файлы: + fclose(src); + fclose(dest); +} + +// Получить размер файла в байтах: +unsigned int getFileSize(FILE* src) +{ + unsigned int fileSize = 0; + int c; + + while ((c = fgetc(src)) != EOF) + { + fileSize++; + } + rewind(src); + + return fileSize; +} + +// Вычислить количество частотностей: +unsigned int calcNumOfFreq(unsigned int* freqList) +{ + unsigned int i; + unsigned int numOfFreq = 0; + + for (i = 0; i < CHARS_LIMIT; i++) + { + if (freqList[i] > 0) + { + numOfFreq++; + } + } + + return numOfFreq; +} + +// Сформировать имя выходного файла: +void outputFilePath(const char *path, char * outputPath, const char *fileExtension) +{ + int i; + const int pathLength = strlen(path); + + for (i = 0; i < pathLength - 4; i++) + { + outputPath[i] = path[i]; + } + outputPath[i] = 0; + + strcat(outputPath, fileExtension); +} diff --git a/Huffman-algorithm-implementation-in-Qt/huffman.h b/Huffman-algorithm-implementation-in-Qt/huffman.h new file mode 100644 index 0000000..61995d3 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/huffman.h @@ -0,0 +1,92 @@ +#ifndef HUFFMAN_H +#define HUFFMAN_H + +#include "stdio.h" + +// Константы: +#define MAX_CODE_SIZE 32 +#define CHARS_LIMIT 256 + +// Узел Хаффмана: +struct HuffNode +{ + unsigned int freq; // частотность. + unsigned char charCode; // код символа. + bool leaf; // является ли узел листом? + + // Навигация по дереву: + HuffNode* next; + HuffNode* left; + HuffNode* right; +}; + +// Таблица Хаффмана: +struct HuffCode +{ + unsigned char code[MAX_CODE_SIZE]; + int length; +}; + +// Заголовок Хаффмана: +struct HuffHeader +{ + unsigned int numOfFreq; // количество частотностей. + unsigned int fileSize; +}; + +// Частотность Хаффмана: +struct HuffFreq +{ + unsigned int freq; // частотность. + unsigned char charCode; // код символа. +}; + +// Посчитать частотность всех символов и сохранить в списке: +void calcCharFreq(FILE* src, unsigned int* freqList); + +// Построить список узлов Хаффмана (частотности сортируются по возрастанию): +void buildNodeList(HuffNode** nodeList, unsigned int* freqList); + +// Построить список узлов из раскодированных частотностей: +void buildNodeList(HuffNode** nodeList, HuffFreq* hFreq, unsigned int numOfFreq); + +// Добавить новый узел в список узлов Хаффмана (по возрастающему порядку): +void addToNodeList(HuffNode** nodeList, HuffNode* newNode); + +// Построить дерево Хаффмана из списка узлов Хаффмана: +void buildHuffTree(HuffNode** nodeList); + +// Построить таблицу перекодировки Хаффмана: +bool buildHuffCode(HuffNode* treeRoot, HuffCode* hCode, unsigned char goalChar); + +// Вывести заголовок Хаффмана в выходной файл: +void writeHeader(FILE* dest, unsigned int numOfFreq, unsigned int fileSize); + +// Вывести символ и его частотность в выходной файл: +void writeFreq(FILE* dest, unsigned int* freqList); + +// Вывести закодированные по Хаффману данные в выходной файл: +void writeEncodedData(FILE* src, FILE* dest, HuffCode* huffCodeTable, unsigned int fileSize); + +// Вывести раскодированные по Хаффману данные в выходной файл: +void writeDecodedData(FILE* src, FILE* dest, HuffNode* rootTree, unsigned int fileSize); + +// Освободить память занятую по дерево Хаффмана: +void freeHuffTree(HuffNode* treeRoot); + +// Закодировать файл по Хаффману: +void huffmanEncode(const char* inputFile); + +// Раскодировать файл по Хаффману: +void huffmanDecode(const char * inputFile); + +// Получить размер файла в байтах: +unsigned int getFileSize(FILE* src); + +// Вычислить количество частотностей: +unsigned int calcNumOfFreq(unsigned int* freqList); + +// Сформировать имя выходного файла: +void outputFilePath(const char* path, char* outputPath, const char *fileExtension); + +#endif // HUFFMAN_H diff --git a/Huffman-algorithm-implementation-in-Qt/main.cpp b/Huffman-algorithm-implementation-in-Qt/main.cpp new file mode 100644 index 0000000..70cb5c2 --- /dev/null +++ b/Huffman-algorithm-implementation-in-Qt/main.cpp @@ -0,0 +1,17 @@ +#include +#include "choose.h" +#include "encoding.h" +#include "decoding.h" + +// Точка входа в программу: +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + // Создание и отображение диалогового окна с двумя кнопками + // "Сжать данные" и "Восстановить данные": + Choose w; + w.show(); + + return a.exec(); +} diff --git a/HuffmanCoding.pro b/HuffmanCoding.pro deleted file mode 100644 index 248f762..0000000 --- a/HuffmanCoding.pro +++ /dev/null @@ -1,29 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2012-07-02T00:13:53 -# -#------------------------------------------------- - -QT += core gui - -TARGET = HuffmanCoding -TEMPLATE = app - - -SOURCES += main.cpp\ - choose.cpp \ - encoding.cpp \ - decoding.cpp - -HEADERS += choose.h \ - encoding.h \ - decoding.h - -FORMS += choose.ui \ - encoding.ui \ - decoding.ui - -RESOURCES += \ - Res.qrc - -RC_FILE = AppIcon.rc diff --git a/HuffmanCoding.pro.user b/HuffmanCoding.pro.user deleted file mode 100644 index 96a930d..0000000 --- a/HuffmanCoding.pro.user +++ /dev/null @@ -1,365 +0,0 @@ - - - - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - System - false - 4 - true - 1 - true - 0 - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop - Qt4ProjectManager.Target.DesktopTarget - 0 - 0 - 0 - - ProjectExplorer.ToolChain.Msvc:D:\Program Files\Microsoft SDKs\Windows\v7.1\bin\SetEnv.cmd:/x86:C:/Program Files/Debugging Tools for Windows (x64)/cdb.exe - - - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - - - Make - - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Qt 4.8.1 for Desktop - MSVC2010 (Qt SDK) Debug - - Qt4ProjectManager.Qt4BuildConfiguration - 2 - D:/Document/Qt_workspace/HuffmanCoding-build-desktop-Qt_4_8_1_for_Desktop_-_MSVC2010__Qt_SDK__Debug - 1 - true - - - ProjectExplorer.ToolChain.Msvc:D:\Program Files\Microsoft SDKs\Windows\v7.1\bin\SetEnv.cmd:/x86:C:/Program Files/Debugging Tools for Windows (x64)/cdb.exe - - - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - - - Make - - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Qt 4.8.1 for Desktop - MSVC2010 (Qt SDK) Release - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - D:/Document/Qt_workspace/HuffmanCoding-build-desktop-Qt_4_8_1_for_Desktop_-_MSVC2010__Qt_SDK__Release - 1 - true - - - ProjectExplorer.ToolChain.Mingw:D:/QtSDK/mingw/bin/mingw32-g++.exe.x86-windows-msys-pe-32bit.d:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe - - - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - - - Make - - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Qt 4.7.4 for Desktop - MinGW 4.4 (Qt SDK) Debug - - Qt4ProjectManager.Qt4BuildConfiguration - 2 - D:/Document/Qt_workspace/HuffmanCoding-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK__Debug - 4 - true - - - ProjectExplorer.ToolChain.Mingw:D:/QtSDK/mingw/bin/mingw32-g++.exe.x86-windows-msys-pe-32bit.d:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe - - - qmake - - QtProjectManager.QMakeBuildStep - false - true - - false - - - Make - - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - Qt 4.7.4 for Desktop - MinGW 4.4 (Qt SDK) Release - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - D:/Document/Qt_workspace/HuffmanCoding-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK__Release - 4 - true - - 4 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - No deployment - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - true - true - - - false - false - false - false - false - false - false - false - true - true - 0.01 - 0.01 - 10 - 10 - true - true - 25 - 25 - - - true - true - valgrind - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - HuffmanCoding - - Qt4ProjectManager.Qt4RunConfiguration - 2 - - HuffmanCoding.pro - false - false - - - 3768 - true - false - false - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.EnvironmentId - {066e5e43-daa7-4569-af38-c687449d4982} - - - ProjectExplorer.Project.Updater.FileVersion - 10 - - diff --git a/README b/README deleted file mode 100644 index 127fb47..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -This is an implementation of Huffman algorithm in Qt. \ No newline at end of file diff --git a/Res.qrc b/Res.qrc deleted file mode 100644 index ff6f51a..0000000 --- a/Res.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - icon.png - - diff --git a/appIcon.ico b/appIcon.ico deleted file mode 100644 index ec73fac..0000000 Binary files a/appIcon.ico and /dev/null differ diff --git a/choose.cpp b/choose.cpp deleted file mode 100644 index 840ce87..0000000 --- a/choose.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - -#include "choose.h" -#include "ui_choose.h" -#include "encoding.h" -#include "decoding.h" - -Choose::Choose(QWidget *parent) : - QDialog(parent), - ui(new Ui::Choose) -{ - ui->setupUi(this); - - /** Connect Compress File button to open compress dialog **/ - connect(ui->compressButton, SIGNAL(clicked()), this, SLOT(showCompressDialog())); - - /** Connect Decompress File button to open decompress dialog **/ - connect(ui->decompressButton, SIGNAL(clicked()), this, SLOT(showDecompressDialog())); -} - -Choose::~Choose() -{ - delete ui; -} - -void Choose::showCompressDialog() -{ - QDialog parent; - Encoding * en; - en = new Encoding(&parent); - en->setFixedSize(en->size()); - en->setWindowTitle("Huffman Encoding"); - en->exec(); -} - -void Choose::showDecompressDialog() -{ - QDialog parent; - Decoding * de; - de = new Decoding(&parent); - de->setFixedSize(de->size()); - de->setWindowTitle("Huffman Decoding"); - de->exec(); -} diff --git a/choose.ui b/choose.ui deleted file mode 100644 index af44272..0000000 --- a/choose.ui +++ /dev/null @@ -1,56 +0,0 @@ - - - Choose - - - - 0 - 0 - 284 - 161 - - - - Huffman Coding - - - - :/images/icon.png:/images/icon.png - - - - - 80 - 20 - 133 - 121 - - - - - - - Compress File - - - - - - - Decompress File - - - - - - - - - compressButton - decompressButton - - - - - - diff --git a/decoding.cpp b/decoding.cpp deleted file mode 100644 index 78374bf..0000000 --- a/decoding.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - -#include "decoding.h" -#include "ui_decoding.h" -#include "QFileDialog" -#include "QMessageBox" -#include "stdio.h" -#include "stdlib.h" -#include -#include "QDebug" -#include "QProgressDialog" -#include "choose.h" - -Decoding::Decoding(QWidget *parent) : - QDialog(parent), - ui(new Ui::Decoding) -{ - ui->setupUi(this); - - /** Connect decompress dialog buttons **/ - connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseInputFile())); - connect(ui->decodeButton, SIGNAL(clicked()), this, SLOT(decompressFile())); - - /** Warning initially hidden **/ - ui->warningText->setVisible(false); -} - -Decoding::~Decoding() -{ - delete ui; -} - -void Decoding::browseInputFile() -{ - /** Open select file dialog **/ - inputFileName = QFileDialog::getOpenFileName(this, tr("Open File"),"/home/piyush/Desktop", - tr("Binary File (*.bin)")); - - ui->inputFile->setText(inputFileName); -} - -QString Decoding::getInputFileName() -{ - return inputFileName; -} - -void Decoding::outputFilePath(const char *path, char * outputPath, const char *fileExtension) -{ - int i; - const int pathLength = strlen(path); - - for(i=0; iwarningText->setVisible(false); - showDoneMessage("Please select a file."); - } - else - { - ui->warningText->setVisible(false); - - QByteArray byteArray1 = inputFileName.toUtf8(); - const char* inputFile = byteArray1.constData(); - huffmanDecode(inputFile); - } -} - -void Decoding::showDoneMessage(const char * msg) -{ - QMessageBox msgBox; - msgBox.setText(msg); - msgBox.setWindowTitle("Decompression"); - msgBox.setIcon(QMessageBox::Information); - QIcon icon(":/images/icon.png"); - msgBox.setWindowIcon(icon); - msgBox.exec(); -} - -void Decoding::buildNodeList(HuffNode ** nodeList, HuffFreq * hFreq, unsigned int numOfFreq) -{ - unsigned int i; - HuffNode * newNode; - - for (i = 0; i < numOfFreq; i++) - { - newNode = (HuffNode *) malloc(sizeof(HuffNode)); - newNode->charCode = hFreq[i].charCode; - newNode->freq = hFreq[i].freq; - newNode->next = NULL; - newNode->left = NULL; - newNode->right = NULL; - newNode->leaf = true; - - addToNodeList(nodeList, newNode); - } -} - -void Decoding::addToNodeList(HuffNode ** nodeList, HuffNode * newNode) -{ - HuffNode * prevNode = NULL; - HuffNode * currNode = *nodeList; - - while ((currNode != NULL && currNode->freq < newNode->freq)) - { - prevNode = currNode; - currNode = prevNode->next; - } - - newNode->next = currNode; - - if (prevNode == NULL) - { - *nodeList = newNode; - } - else - { - prevNode->next = newNode; - } -} - -void Decoding::buildHuffTree(HuffNode ** nodeList) -{ - HuffNode * newNode, * leftNode, * rightNode; - - while((*nodeList)->next != NULL) - { - newNode = (HuffNode *)malloc(sizeof(HuffNode)); - - leftNode = *nodeList; - *nodeList = leftNode->next; - - rightNode = *nodeList; - *nodeList = rightNode->next; - - newNode->charCode = 0; - newNode->freq = leftNode->freq + rightNode->freq; - newNode->next = NULL; - newNode->left = leftNode; - newNode->right = rightNode; - newNode->leaf = false; - - addToNodeList(nodeList, newNode); - } -} - -void Decoding::writeDecodedData(FILE * src, FILE * dest, HuffNode * rootTree, unsigned int fileSize) -{ - int bit = -1; - unsigned int c; - unsigned int bytesWritten = 0; - HuffNode * currNode = rootTree; - bool cancel = false; - unsigned int interval = fileSize/100; - int progress = 1; - - QProgressDialog progressDialog("Decompressing...", "Cancel", 0, fileSize, this); - progressDialog.setWindowModality(Qt::WindowModal); - progressDialog.setValue(0); - - while(bytesWritten < fileSize) - { - if(bit < 0) - { - c = fgetc(src); - - if(c == EOF) - { - break; - } - - bit = 7; - } - - if((c >> bit) & 1) - { - currNode = currNode->right; - } - else - { - currNode = currNode->left; - } - - if(currNode->leaf) - { - fputc(currNode->charCode, dest); - bytesWritten++; - currNode = rootTree; - } - - bit--; - - if(bytesWritten > interval*progress) - { - progressDialog.setValue(interval*progress); - progress++; - } - - if (progressDialog.wasCanceled()) - { - cancel = true; - showDoneMessage("Aborted!"); - break; - } - } - - progressDialog.setValue(fileSize); - - if(!cancel) - { - showDoneMessage("File Decompressed Successfully!"); - } -} - -void Decoding::freeHuffTree(HuffNode * treeRoot) -{ - if(treeRoot) - { - freeHuffTree(treeRoot->left); - freeHuffTree(treeRoot->right); - - free(treeRoot); - } -} - -void Decoding::huffmanDecode(const char * inputFile) -{ - /** Open source file **/ - FILE *src = fopen(inputFile, "rb"); - - /** Open destination file **/ - char outputPath[1000]; - const char * fileExtension = ".txt"; - outputFilePath(inputFile, outputPath, fileExtension); - FILE * dest = fopen(outputPath, "wb"); - - /** Check if file exist **/ - if (src == NULL) - { - fprintf(stderr, "Could not open file."); - exit(EXIT_FAILURE); - } - - /** Read Hufffman header **/ - HuffHeader hHeader; - fread(&hHeader, sizeof(hHeader), 1, src); - - /** Read Huffman freq **/ - HuffFreq *hFreq = (HuffFreq *)calloc(hHeader.numOfFreq, sizeof(HuffFreq)); - fread(hFreq, sizeof(HuffFreq), hHeader.numOfFreq, src); - - /** Produce frequency node list **/ - HuffNode * nodeList = NULL; - buildNodeList(&nodeList, hFreq, hHeader.numOfFreq); - - /** Build Huffman tree **/ - buildHuffTree(&nodeList); - - /** Write Huffman decoded data to destination file **/ - writeDecodedData(src, dest, nodeList, hHeader.fileSize); - - /** Free up memory **/ - freeHuffTree(nodeList); - nodeList = NULL; - free(hFreq); - - /** Close files **/ - fclose(src); - fclose(dest); -} diff --git a/decoding.h b/decoding.h deleted file mode 100644 index 4eabfa1..0000000 --- a/decoding.h +++ /dev/null @@ -1,93 +0,0 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - -#ifndef DECODING_H -#define DECODING_H - -#include - -namespace Ui { -class Decoding; -} - -class Decoding : public QDialog -{ - Q_OBJECT - -public: - explicit Decoding(QWidget *parent = 0); - ~Decoding(); - - /** Input file name getter **/ - QString getInputFileName(); - - /** Huffman encoding **/ - void huffmanDecode(const char * inputFile); - -private: - Ui::Decoding *ui; - - /** Input file name string **/ - QString inputFileName; - - /** Output file path **/ - void outputFilePath(const char * path, char * outputPath, const char * fileExtension); - - /** Get output file name **/ - void getOutputFileName(); - - /** Show decompressing done message **/ - void showDoneMessage(const char * msg); - - /** Huffman node **/ - struct HuffNode - { - unsigned char charCode; - unsigned int freq; - bool leaf; - HuffNode * next; - HuffNode * left; - HuffNode * right; - }; - - /** Huffman header node **/ - struct HuffHeader - { - unsigned int numOfFreq; - unsigned int fileSize; - }; - - /** Huffman freq node **/ - struct HuffFreq - { - unsigned int freq; - unsigned char charCode; - }; - - /** Build node list of decoded freq **/ - void buildNodeList(HuffNode ** nodeList, HuffFreq * hFreq, unsigned int numOfFreq); - - /** Add new Huffman node to node list **/ - void addToNodeList(HuffNode ** nodeList, HuffNode * newNode); - - /** Construct Huffman tree **/ - void buildHuffTree(HuffNode ** nodeList); - - /** Write Huffman decoded data to output file **/ - void writeDecodedData(FILE * src, FILE * dest, HuffNode * rootTree, unsigned int fileSize); - - /** Free Huffman tree memory **/ - void freeHuffTree(HuffNode * treeRoot); - -public slots: - - /** Browse input file **/ - void browseInputFile(); - - /** Compress file **/ - void decompressFile(); -}; - -#endif // DECODING_H diff --git a/decoding.ui b/decoding.ui deleted file mode 100644 index 1c8dfb4..0000000 --- a/decoding.ui +++ /dev/null @@ -1,81 +0,0 @@ - - - Decoding - - - - 0 - 0 - 563 - 111 - - - - Dialog - - - - :/images/icon.png:/images/icon.png - - - - - 20 - 20 - 521 - 29 - - - - - - - - - - - - - - Browse - - - - - - - - - 210 - 70 - 91 - 23 - - - - Decompress - - - - - - 330 - 70 - 121 - 16 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-style:italic; color:#ff0000;">*Please Select a File</span></p></body></html> - - - - - - - - diff --git a/encoding.cpp b/encoding.cpp deleted file mode 100644 index 629b467..0000000 --- a/encoding.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - -#include "encoding.h" -#include "ui_encoding.h" -#include "QFileDialog" -#include "QMessageBox" -#include "stdio.h" -#include "stdlib.h" -#include -#include "QProgressDialog" - -Encoding::Encoding(QWidget *parent) : - QDialog(parent), - ui(new Ui::Encoding) -{ - ui->setupUi(this); - - /** Connect compress dialog buttons **/ - connect(ui->browseButton, SIGNAL(clicked()), this, SLOT(browseInputFile())); - connect(ui->encodeButton, SIGNAL(clicked()), this, SLOT(compressFile())); - - /** Warning initially hidden **/ - ui->warningText->setVisible(false); -} - -Encoding::~Encoding() -{ - delete ui; -} - -void Encoding::browseInputFile() -{ - /** Open select file dialog **/ - inputFileName = QFileDialog::getOpenFileName(this, tr("Open File"),"/home/piyush/Desktop", - tr("Document Files (*.txt)")); - ui->inputFile->setText(inputFileName); -} - -void Encoding::outputFilePath(const char *path, char * outputPath, const char *fileExtension) -{ - int i; - const int pathLength = strlen(path); - - for(i=0; iwarningText->setVisible(false); - showDoneMessage("Please select a file."); - } - else - { - ui->warningText->setVisible(false); - - QByteArray byteArray1 = inputFileName.toUtf8(); - const char* inputFile = byteArray1.constData(); - - huffmanEncode(inputFile); - } -} - -void Encoding::showDoneMessage(const char * msg) -{ - QMessageBox msgBox; - msgBox.setText(msg); - msgBox.setWindowTitle("Compression"); - msgBox.setIcon(QMessageBox::Information); - QIcon icon(":/images/icon.png"); - msgBox.setWindowIcon(icon); - msgBox.exec(); -} - -unsigned int Encoding::getFileSize(FILE * src) -{ - unsigned int fileSize = 0; - unsigned int c; - - while((c = fgetc(src)) != EOF) - { - fileSize++; - } - rewind(src); - - return fileSize; -} - -void Encoding::calcCharFreq(FILE * src, unsigned int * freqList) -{ - unsigned int c; - - while((c = fgetc(src)) != EOF) - { - freqList[c]++; - } - rewind(src); -} - -unsigned int Encoding::calcNumOfFreq(unsigned int * freqList) -{ - unsigned int i; - unsigned int numOfFreq = 0; - - for(i=0; i 0) - { - numOfFreq++; - } - } - - return numOfFreq; -} - -void Encoding::buildNodeList(HuffNode ** nodeList, unsigned int * freqList) -{ - unsigned int i; - HuffNode * newNode; - - for(i=0; i 0) - { - newNode = (HuffNode *)calloc(1, sizeof(HuffNode)); - newNode->charCode = i; - newNode->freq = freqList[i]; - newNode->next = NULL; - newNode->left = NULL; - newNode->right = NULL; - newNode->leaf = true; - - addToNodeList(nodeList, newNode); - } - } -} - -void Encoding::addToNodeList(HuffNode ** nodeList, HuffNode * newNode) -{ - HuffNode * prevNode = NULL; - HuffNode * currNode = *nodeList; - - while(currNode != NULL && currNode->freq < newNode->freq) - { - prevNode = currNode; - currNode = prevNode->next; - } - - newNode->next = currNode; - - if(prevNode == NULL) - { - *nodeList = newNode; - } - else - { - prevNode->next = newNode; - } -} - -void Encoding::buildHuffTree(HuffNode ** nodeList) -{ - HuffNode * leftNode, * rightNode, * currNode; - HuffNode * newNode; - - while((*nodeList)->next) - { - leftNode = *nodeList; - *nodeList = leftNode->next; - - rightNode = *nodeList; - *nodeList = rightNode->next; - - newNode = (HuffNode *)calloc(1, sizeof(HuffNode)); - newNode->charCode = 0; - newNode->freq = leftNode->freq + rightNode->freq; - newNode->next = NULL; - newNode->left = leftNode; - newNode->right = rightNode; - newNode->leaf = false; - - addToNodeList(nodeList, newNode); - } -} - -bool Encoding::buildHuffCode(HuffNode * treeRoot, HuffCode * hCode, unsigned char goalChar) -{ - if(treeRoot->charCode == goalChar && treeRoot->leaf) - { - return true; - } - - if(treeRoot->left) - { - hCode->code[hCode->length] = '0'; - hCode->length++; - - if(hCode->length == MAX_CODE_SIZE) - { - printf("Code size exceeds limit!"); - return false; - } - - if(buildHuffCode(treeRoot->left, hCode, goalChar)) - { - hCode->code[hCode->length] = 0; - return true; - } - else - { - hCode->length--; - hCode->code[hCode->length] = 0; - } - } - - if(treeRoot->right) - { - hCode->code[hCode->length] = '1'; - hCode->length++; - - if(buildHuffCode(treeRoot->right, hCode, goalChar)) - { - return true; - } - else - { - hCode->length--; - hCode->code[hCode->length] = 0; - } - } - - return false; -} - -void Encoding::writeHeader(FILE * dest, HuffHeader hHeader, unsigned int numOfFreq, unsigned int fileSize) -{ - hHeader.numOfFreq = numOfFreq; - hHeader.fileSize = fileSize; - - fwrite(&hHeader, sizeof(hHeader), 1, dest); -} - -void Encoding::writeFreq(FILE * dest, unsigned int * freqList, HuffFreq hFreq) -{ - unsigned int i; - - for(i=0; i 0) - { - hFreq.charCode = i; - hFreq.freq = freqList[i]; - - fwrite(&hFreq, sizeof(HuffFreq), 1, dest); - } - } -} - -void Encoding::writeEncodedData(FILE * src, FILE * dest, HuffCode * huffCodeTable, unsigned int fileSize) -{ - unsigned int i, c; - unsigned int bits = 0; - char currChar = 0; - HuffCode currCode; - bool cancel = false; - unsigned int interval = fileSize/100; - int progress = 1; - unsigned int bytes = 0; - - QProgressDialog progressDialog("Compressing...", "Cancel", 0, fileSize, this); - progressDialog.setWindowModality(Qt::WindowModal); - progressDialog.setValue(0); - - while((c = fgetc(src)) != EOF) - { - bytes++; - currCode = huffCodeTable[c]; - - for(i=0; i interval*progress) - { - progressDialog.setValue(progress); - progress++; - } - - if (progressDialog.wasCanceled()) - { - cancel = true; - showDoneMessage("Aborted!"); - break; - } - } - - if(bits > 0) - { - currChar = currChar << (8 - bits); - fputc(currChar, dest); - } - - progressDialog.setValue(fileSize); - - if(!cancel) - { - showDoneMessage("File Compressed Successfully!"); - } -} - -void Encoding::freeHuffTree(HuffNode * treeRoot) -{ - if(treeRoot) - { - freeHuffTree(treeRoot->left); - freeHuffTree(treeRoot->right); - - free(treeRoot); - } -} - -void Encoding::huffmanEncode(const char* inputFile) -{ - /** Read source file **/ - FILE * src = fopen(inputFile, "rb"); - - /** Open destination file **/ - char outputPath[1000]; - const char * fileExtension = ".bin"; - outputFilePath(inputFile, outputPath, fileExtension); - FILE * dest = fopen(outputPath, "wb"); - - /** Check if source file exists **/ - if (src == NULL || dest == NULL) - { - printf("Could not find the input file!"); - exit(EXIT_FAILURE); - } - - /** Get size of source file **/ - unsigned int fileSize; - fileSize = getFileSize(src); - - /** Produce chars freqency list **/ - unsigned int * freqList; - freqList = (unsigned int *)calloc(CHARS_LIMIT, sizeof(unsigned int)); - calcCharFreq(src, freqList); - - /** Calculate number of frequencies **/ - unsigned int numOfFreq; - numOfFreq = calcNumOfFreq(freqList); - - /** Produce Huffman node list (frequencies sorted in ascending order)**/ - HuffNode * nodeList = NULL; - buildNodeList(&nodeList, freqList); - - /** Build Huffman tree **/ - buildHuffTree(&nodeList); - HuffNode * treeRoot = nodeList; - - /** Build Huffman code lookup table **/ - unsigned int i; - HuffCode newCode; - HuffCode * huffCodeTable; - huffCodeTable = (HuffCode *)calloc(CHARS_LIMIT, sizeof(HuffCode)); - for(i=0; i 0) - { - newCode.length = 0; - buildHuffCode(treeRoot, &newCode, i); - huffCodeTable[i] = newCode; - } - } - - /** Write Hufffman header to destination file **/ - HuffHeader hHeader; - writeHeader(dest, hHeader, numOfFreq, fileSize); - - /** Write Huffman freq to destination file **/ - HuffFreq hFreq; - writeFreq(dest, freqList, hFreq); - - /** Write encoded data to destination file **/ - writeEncodedData(src, dest, huffCodeTable, fileSize); - - /** Free up memory **/ - freeHuffTree(treeRoot); - treeRoot = NULL; - free(huffCodeTable); - free(freqList); - - /** Close files **/ - fclose(src); - fclose(dest); -} - - diff --git a/encoding.h b/encoding.h deleted file mode 100644 index 2204e27..0000000 --- a/encoding.h +++ /dev/null @@ -1,120 +0,0 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - -#ifndef ENCODING_H -#define ENCODING_H - -#include -#include - -/* Constants */ -#define MAX_CODE_SIZE 32 -#define CHARS_LIMIT 256 - -namespace Ui { -class Encoding; -} - -class Encoding : public QDialog -{ - Q_OBJECT - -public: - explicit Encoding(QWidget *parent = 0); - ~Encoding(); - - /** Input file name getter **/ - QString getInputFileName(); - - /** Huffman encoding **/ - void huffmanEncode(const char* inputFile); - - /** Get size of file (in bytes) **/ - unsigned int getFileSize(FILE * src); - - /** Calculate number of frequencies **/ - unsigned int calcNumOfFreq(unsigned int * freqList); - -private: - Ui::Encoding *ui; - - /** Input file name string **/ - QString inputFileName; - - /** Output file path **/ - void outputFilePath(const char * path, char * outputPath, const char * fileExtension); - - /** Show decompressing done message **/ - void showDoneMessage(const char * msg); - - /** Huffman node **/ - struct HuffNode - { - unsigned int freq; - unsigned char charCode; - bool leaf; - HuffNode * next; - HuffNode * left; - HuffNode * right; - }; - - /** Hufman code **/ - struct HuffCode - { - unsigned char code[MAX_CODE_SIZE]; - unsigned int length; - }; - - /** Huffman header node **/ - struct HuffHeader - { - unsigned int numOfFreq; - unsigned int fileSize; - }; - - /** Huffman freq node **/ - struct HuffFreq - { - unsigned int freq; - unsigned char charCode; - }; - - /** Calculate & store freq of each char in list **/ - void calcCharFreq(FILE * src, unsigned int * freqList); - - /** Build Huffman node list (frequencies sorted in ascending order) **/ - void buildNodeList(HuffNode ** nodeList, unsigned int * freqList); - - /** Add new node to list (in ascending order) **/ - void addToNodeList(HuffNode ** nodeList, HuffNode * newNode); - - /** Build Huffman tree from nodeList **/ - void buildHuffTree(HuffNode ** nodeList); - - /** Build Huffman code lookup table **/ - bool buildHuffCode(HuffNode * treeRoot, HuffCode * hCode, unsigned char goalChar); - - /** Write Huffman header to output file **/ - void writeHeader(FILE * dest, HuffHeader hHeader, unsigned int numOfFreq, unsigned int fileSize); - - /** Write char & freq data to output file **/ - void writeFreq(FILE * dest, unsigned int * freqList, HuffFreq hFreq); - - /** Write Huffman encoded data to output file **/ - void writeEncodedData(FILE * src, FILE * dest, HuffCode * huffCodeTable, unsigned int fileSize); - - /** Free Huffman tree memory **/ - void freeHuffTree(HuffNode * treeRoot); - -public slots: - - /** Browse input file **/ - void browseInputFile(); - - /** Compress file **/ - void compressFile(); -}; - -#endif // ENCODING_H diff --git a/encoding.ui b/encoding.ui deleted file mode 100644 index 25f373e..0000000 --- a/encoding.ui +++ /dev/null @@ -1,81 +0,0 @@ - - - Encoding - - - - 0 - 0 - 563 - 111 - - - - Dialog - - - - :/images/icon.png:/images/icon.png - - - - - 20 - 20 - 521 - 29 - - - - - - - - - - - - - - Browse - - - - - - - - - 210 - 70 - 91 - 23 - - - - Compress - - - - - - 320 - 70 - 141 - 20 - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-style:italic; color:#ff0000;">*Please Select a File</span></p></body></html> - - - - - - - - diff --git a/icon.png b/icon.png deleted file mode 100644 index f7289d3..0000000 Binary files a/icon.png and /dev/null differ diff --git a/license.txt b/license.txt deleted file mode 100644 index 789ef32..0000000 --- a/license.txt +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (c) 2012 Piyush Kant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN \ No newline at end of file diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 00aa48c..0000000 --- a/main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/*********************************************** -Copyright (c) 2012 Piyush Kant -See the file license.txt for copying permission. -************************************************/ - -#include -#include "choose.h" -#include "encoding.h" -#include "decoding.h" - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - Choose w; - w.show(); - - return a.exec(); -}