From 4c212907c253db024c031cc9d55aaaf1d7bdeedb Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Thu, 21 Jun 2018 17:38:51 +0200 Subject: [PATCH] bugfixes --- src/bitpack.cc | 35 +++++++++++++++++++++-------------- src/bitpack.hh | 20 ++++++++++---------- src/common.cc | 6 +++--- src/compress.cc | 44 +++++++++++++++++++++++++------------------- src/compress.hh | 2 +- src/io.cc | 46 ++++++++++++++++++++-------------------------- src/io.hh | 12 +++++++----- src/main.cc | 9 +++++---- src/uncompress.cc | 46 ++++++++++++++++++++++++---------------------- src/uncompress.hh | 7 ++++--- 10 files changed, 120 insertions(+), 107 deletions(-) diff --git a/src/bitpack.cc b/src/bitpack.cc index 8740cda..da20f0e 100644 --- a/src/bitpack.cc +++ b/src/bitpack.cc @@ -32,7 +32,8 @@ constexpr uint16_t masks[17] = { /////////////////////////////////////////////////////////////////////////////// vuchar pack(const vuint16 &t_input) { - return pack_n(t_input.begin(), t_input.end(), vuchar{}, 9); + vuchar vec{}; + return pack_n(t_input.begin(), t_input.end(), vec, 9); } /** @@ -45,10 +46,13 @@ vuchar pack(const vuint16 &t_input) { * char containing the packed values from t_input */ vuchar pack_n(const vuint16::const_iterator t_input_begin, - const vuint16::const_iterator t_input_end, vuchar t_res, + const vuint16::const_iterator t_input_end, vuchar &t_res, int t_n) { +#ifdef Debug + std::printf("%d bits!\n", t_n); +#endif // Debug if (t_n == 16) { - return pack_16(t_input_begin, t_input_end, vector()); + return pack_16(t_input_begin, t_input_end, t_res); } const int max_value = max(t_n); // max value held within t_n bits @@ -60,22 +64,24 @@ vuchar pack_n(const vuint16::const_iterator t_input_begin, // pour chaque élément for (auto it = t_input_begin; it != t_input_end; ++it) { - // si on a atteint ou dépassé la valeur maximale, on change de nombre de bits + // si on a atteint ou dépassé la valeur maximale, on change de nombre de + // bits if (*it >= max_value) { - // écriture du masque pour notifier à la décompression du changement de bits + // écriture du masque pour notifier à la décompression du changement de + // bits if ((left_shift += step) >= t_n) { left_shift = (left_shift - t_n) + step; } const auto mask = masks[t_n] >> left_shift; - t_res.push_back( - static_cast(current_char | mask)); + t_res.push_back(static_cast(current_char | mask)); bool zero_rs = (right_shift == 0); right_shift -= step; - if(right_shift < 0) { // si right_shift est inférieur à zéro + if (right_shift < 0) { // si right_shift est inférieur à zéro // si right_shift était différent de zéro, alors extra octet if (!zero_rs) { - current_char = static_cast(masks[t_n] >> (-right_shift) & 0xffu); + current_char = + static_cast(masks[t_n] >> (-right_shift) & 0xffu); t_res.push_back(current_char); } } @@ -117,7 +123,7 @@ vuchar pack_n(const vuint16::const_iterator t_input_begin, } vuchar pack_16(const vuint16::const_iterator t_input_begin, - const vuint16::const_iterator t_input_end, vuchar t_res) { + const vuint16::const_iterator t_input_end, vuchar &t_res) { std::for_each(t_input_begin, t_input_end, [&](const auto value) { t_res.push_back(static_cast(value >> 8 & 0xFFu)); t_res.push_back(static_cast(value & 0xFFu)); @@ -130,13 +136,14 @@ vuchar pack_16(const vuint16::const_iterator t_input_begin, /////////////////////////////////////////////////////////////////////////////// vuint16 unpack(ustring &&t_input) { - return unpack_n(t_input.begin(), t_input.end(), vuint16{}, 9); + vuint16 vec{}; + return unpack_n(t_input.begin(), t_input.end(), vec, 9); } vuint16 unpack_n(const ustring::const_iterator t_begin, - const ustring::const_iterator t_end, vuint16 t_res, int t_n) { + const ustring::const_iterator t_end, vuint16 &t_res, int t_n) { if (t_n == 16) { - return unpack_16(t_begin, t_end, vector()); + return unpack_16(t_begin, t_end, t_res); } int step = t_n % 8; int left_shift = 0; @@ -173,7 +180,7 @@ vuint16 unpack_n(const ustring::const_iterator t_begin, } vuint16 unpack_16(const ustring::const_iterator t_begin, - const ustring::const_iterator t_end, vuint16 t_res) { + const ustring::const_iterator t_end, vuint16 &t_res) { for (auto it = t_begin; it < t_end; ++it) { t_res.push_back(static_cast(*it << 8 | *++it)); } diff --git a/src/bitpack.hh b/src/bitpack.hh index beddb8f..52c0def 100644 --- a/src/bitpack.hh +++ b/src/bitpack.hh @@ -14,25 +14,25 @@ std::vector pack(const std::vector &); /// \brief Packs std::uint16_t of n bits into unsigned char -std::vector -pack_n(std::vector::const_iterator , std::vector::const_iterator , - std::vector , int ); +std::vector pack_n(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &, int); /// \brief Specialization of \ref pack_n for 16bits -std::vector -pack_16(std::vector::const_iterator , std::vector::const_iterator , - std::vector ); +std::vector pack_16(std::vector::const_iterator, + std::vector::const_iterator, + std::vector &); std::vector unpack(std::basic_string &&); std::vector unpack_n(std::basic_string::const_iterator t_begin, - std::basic_string::const_iterator t_end, - std::vector t_res, int t_n); + std::basic_string::const_iterator t_end, + std::vector &, int t_n); std::vector unpack_16(std::basic_string::const_iterator, - std::basic_string::const_iterator, - std::vector); + std::basic_string::const_iterator, + std::vector &); #endif /* LZW_SRC_BITPACK_H_ */ diff --git a/src/common.cc b/src/common.cc index de65e8b..bf2c5b0 100644 --- a/src/common.cc +++ b/src/common.cc @@ -40,9 +40,9 @@ int ipow(int base, int exp) { * valeur numérique de la chaîne dans le dictionnaire. * * \param t_dictionary Dictionnaire - * \param t_nr_chaine Numéro de la chaine précédant le caractères \p t_c dans \p t_dictionary - * \param t_c Caractère suivant la chaine de caractères \p t_nr_chaine - * \return const std::pair + * \param t_nr_chaine Numéro de la chaine précédant le caractères \p t_c dans + * \p t_dictionary \param t_c Caractère suivant la chaine de caractères \p + * t_nr_chaine \return const std::pair */ std::pair dico(dic_comp_t &t_dictionary, const uint16_t t_nr_chaine, const uint8_t t_c) { diff --git a/src/compress.cc b/src/compress.cc index 334234d..7ee43db 100644 --- a/src/compress.cc +++ b/src/compress.cc @@ -4,11 +4,13 @@ */ #include "compress.hh" -#include "io.hh" #include "common.hh" +#include "io.hh" #include #include #include +#include +using std::ios; using std::string; using std::uint16_t; using std::uint8_t; @@ -20,7 +22,20 @@ using ustring = std::basic_string; using dict_t = std::map, uint16_t>; using std::printf; -const size_t DICT_MAX = static_cast(ipow(2, 17) - 256); /* 16 bits */ +ustring read_file(const string &filename) { + std::ifstream file{filename, ios::binary}; + assert(file); + file.unsetf(ios::skipws); + file.seekg(0, ios::end); + const auto file_size = file.tellg(); + file.seekg(0, ios::beg); + ustring res{}; + res.reserve(file_size); + res.insert(res.begin(), std::istream_iterator(file), + std::istream_iterator()); + file.close(); + return res; +} /** * La chaîne de caractères \p t_text est lue caractère par caractère, et est @@ -35,6 +50,7 @@ const size_t DICT_MAX = static_cast(ipow(2, 17) - 256); /* 16 bits */ */ vvuint16 lzw_compress(ustring &&t_text) { std::puts("Compressing..."); + const auto DICT_MAX = static_cast(ipow(2, 17) - 256); /* 16 bits */ uint16_t w = 0xFFFF; vuint16 chunk{}; vvuint16 res{}; @@ -46,7 +62,8 @@ vvuint16 lzw_compress(ustring &&t_text) { dict = dict_t{}; w = 0xFFFF; } - if (const auto &[yes, pos] = dico(dict, w, static_cast(c)); yes) { + if (const auto &[exists, pos] = dico(dict, w, static_cast(c)); + exists) { w = pos; } else { chunk.push_back(w); @@ -70,25 +87,14 @@ vvuint16 lzw_compress(ustring &&t_text) { * \param[in] t_out_file Chemin vers le fichier de sortie */ void compress(const std::string &t_in_file, const char *t_out_file) { - FILE *const input_file = fopen(t_in_file.c_str(), "rb"); - assert(input_file); - FILE *const out = (t_out_file != nullptr) ? fopen(t_out_file, "wb") - : fopen("output.lzw", "wb"); - if (out == nullptr) { + std::ofstream out{(t_out_file != nullptr) ? t_out_file : "output.lzw", + std::ios::out | std::ios::binary}; + if (!out.is_open()) { std::cerr << "Error at " << __FILE__ << ":" << __LINE__ - 4 << ": could not open output file. Aborting...\n"; - std::fclose(input_file); exit(1); } - - std::fseek(input_file, 0L, SEEK_END); - const auto file_size = static_cast(ftell(input_file)); - std::rewind(input_file); - - auto raw_text = std::make_unique(file_size); - std::fread(raw_text.get(), sizeof(unsigned char), file_size, input_file); - const auto compressed_text(lzw_compress(ustring{raw_text.get(), &raw_text[file_size]})); + const auto compressed_text(lzw_compress(read_file(t_in_file))); write_file(out, compressed_text); - fclose(out); - fclose(input_file); + out.close(); } diff --git a/src/compress.hh b/src/compress.hh index 4aa4c75..e0fa926 100644 --- a/src/compress.hh +++ b/src/compress.hh @@ -7,9 +7,9 @@ #define LZW_SRC_COMPRESS_H_ #include "common.hh" -#include #include #include +#include /// \brief Compression d'une chaine de caractères std::vector> diff --git a/src/io.cc b/src/io.cc index 2d156b0..543046b 100644 --- a/src/io.cc +++ b/src/io.cc @@ -6,46 +6,36 @@ #include "io.hh" #include "bitpack.hh" #include -#include -#ifdef Debug -constexpr bool debug_mode = true; -#include -#else -constexpr bool debug_mode = false; -#endif - -using std::vector; using std::uint16_t; +using std::vector; using vuint16 = vector; using vvuint16 = vector; /** * Écrit dans le fichier \p t_out les chunks passés en paramètre. Le fichier de * sortie est composé des éléments suivants :\n - * - Sur deux octets sont écrit un `uint16_t` déterminant le nombre de chunk - * composant le fichier\n + * - Sur deux octets sont écrit un `uint16_t` (deux octets) déterminant le + * nombre de chunk composant le fichier\n * - Sont ensuite écrits les chunks sur un nombre variable d’octets suivant la * taille des chunks\n * \n * Un chunk est composé de la manière qui suit :\n - * - Sur deux octets sont écrit un `uint32_t` déterminant le nombre d’octets - * composant le chunk\n + * - Sur deux octets sont écrit un `uint32_t` (quatre octets) déterminant le + * nombre d’octets composant le chunk\n * - Sur le nombre d’octets précisés par le header du chunk se trouvent les * données compressées par l’algorithme lzw puis via bit-packing.\n * * \param[out] t_out Fichier de sortie - * \param[in] t_text Collection ordonnée des chunks à écrire dans \p t_out + * \param[in] t_chunks Collection ordonnée des chunks à écrire dans \p t_out */ -void write_file(FILE *const t_out, const vvuint16 &t_text) { - const auto size = static_cast(t_text.size()); - if constexpr (debug_mode) { - std::printf("Number of chunks: %u\n", size); - } - fwrite(&size, sizeof(size), 1, t_out); - for (const auto &chunk : t_text) { - if constexpr (debug_mode) - std::printf("Chunk!\n"); +void write_file(std::ofstream &t_out, const vvuint16 &t_chunks) { + const auto nr_chunks = static_cast(t_chunks.size()); +#ifdef Debug + std::printf("Number of chunks: %u\n", nr_chunks); +#endif + t_out.write(reinterpret_cast(&nr_chunks), sizeof(nr_chunks)); + for (const auto &chunk : t_chunks) { write_chunk(t_out, chunk); } } @@ -57,9 +47,13 @@ void write_file(FILE *const t_out, const vvuint16 &t_text) { * \param t_out Output file * \param t_chunk Chunk to be written to \p t_out */ -void write_chunk(FILE *const t_out, const vuint16 &t_chunk) { +void write_chunk(std::ofstream &t_out, const vuint16 &t_chunk) { +#ifdef Debug + std::printf("Chunk!\n"); +#endif const auto output = pack(t_chunk); const auto chunk_size = static_cast(output.size()); - fwrite(&chunk_size, sizeof(chunk_size), 1, t_out); - fwrite(output.data(), sizeof(output[0]), output.size(), t_out); + t_out.write(reinterpret_cast(&chunk_size), sizeof(chunk_size)); + t_out.write(reinterpret_cast(output.data()), + sizeof(output[0]) * output.size()); } diff --git a/src/io.hh b/src/io.hh index 9979add..b138fc9 100644 --- a/src/io.hh +++ b/src/io.hh @@ -6,8 +6,9 @@ #ifndef LZW_SRC_IO_H_ #define LZW_SRC_IO_H_ -#include #include +#include +#include #include #include @@ -19,17 +20,18 @@ * * Un chunk se compose ainsi : * nb_char_chunk : nombre de caractères du chunk (2B) - * text* : caractères de taille char_size (ceil((char_size * nb_char_chunk) / 8)) + * text* : caractères de taille char_size (ceil((char_size * nb_char_chunk) / + * 8)) * * Si le dernier caractère ne termine pas le dernier octet du chunk, les * derniers bits sont mit à zéro */ - /// \brief Écrit dans le fichier le texte compressé -void write_file(FILE *const, const std::vector> &); +void write_file(std::ofstream &, + const std::vector> &); /// \brief Écrit un chunk dans le fichier de sortie -void write_chunk(FILE *const, const std::vector &); +void write_chunk(std::ofstream &, const std::vector &); #endif /* LZW_SRC_IO_H_ */ diff --git a/src/main.cc b/src/main.cc index 8e92669..2e60d2c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -6,11 +6,11 @@ * */ -#include -#include -#include #include "compress.hh" #include "uncompress.hh" +#include +#include +#include using std::printf; using std::puts; @@ -70,7 +70,8 @@ std::tuple process_args(int t_argc, char *t_argv[]) { {"uncompress", no_argument, nullptr, 'u'}, {nullptr, 0, nullptr, 0}}; int c = getopt_long(t_argc, t_argv, "hi:o:cu", long_options, &option_index); - if (c == -1) break; + if (c == -1) + break; switch (c) { case 0: break; diff --git a/src/uncompress.cc b/src/uncompress.cc index b1427a2..638e7b7 100644 --- a/src/uncompress.cc +++ b/src/uncompress.cc @@ -4,6 +4,8 @@ #include #include #include +#include +#include using std::fclose; using std::fopen; @@ -18,14 +20,17 @@ ustring lzw_uncompress(vuint16 &&t_compressed) { ustring ret{}; uint16_t old = 0; std::map dict{}; - uint16_t v = t_compressed[0]; - ret.append({static_cast(v)}); - old = v; + // uint16_t v = t_compressed[0]; + // ret.append({static_cast(v)}); + // old = v; + ret.append({static_cast(t_compressed[0])}); + old = t_compressed[0]; for (auto it = t_compressed.begin() + 1; it != t_compressed.end(); ++it) { - v = *it; - const auto uncompressed{dico_uncompress(dict, v, old)}; + // v = *it; + const auto uncompressed{dico_uncompress(dict, *it, old)}; ret.insert(ret.end(), uncompressed.begin(), uncompressed.end()); - old = v; + // old = v; + old = *it; } return ret; @@ -34,31 +39,28 @@ ustring lzw_uncompress(vuint16 &&t_compressed) { void uncompress(const string &t_input_name, const char *t_output_name) { FILE *const input = std::fopen(t_input_name.c_str(), "rb"); assert(input); - FILE *const output = (t_output_name != nullptr) ? std::fopen(t_output_name, "wb") : std::fopen((t_input_name + "_uncompressed").c_str(), "wb"); assert(output); - uint16_t nb_chunks = 0; - std::fseek(input, 0, SEEK_SET); std::fread(&nb_chunks, sizeof(nb_chunks), 1, input); - for (uint16_t i = 0; i < nb_chunks; ++i) { - uint32_t size_chunk = 0; - fread(&size_chunk, sizeof(size_chunk), 1, input); - auto *chunk = static_cast( - std::malloc(sizeof(unsigned char) * size_chunk)); - fread(chunk, sizeof(unsigned char), size_chunk, input); - - auto unpacked = unpack(ustring{chunk, chunk + size_chunk}); - const auto uncompressed_chunk = lzw_uncompress(std::move(unpacked)); - // sometimes will add null char - std::fwrite(uncompressed_chunk.data(), sizeof(uncompressed_chunk[0]), - uncompressed_chunk.size(), output); + uncompress_chunk(input, output); } - std::fclose(output); std::fclose(input); } + +void uncompress_chunk(FILE *const input, FILE *const output) { + uint32_t size_chunk = 0; + fread(&size_chunk, sizeof(size_chunk), 1, input); + auto chunk = new unsigned char[size_chunk]; + fread(chunk, sizeof(unsigned char), size_chunk, input); + auto unpacked = unpack(ustring{chunk, chunk + size_chunk}); + delete[] chunk; + const auto uncompressed_chunk = lzw_uncompress(std::move(unpacked)); + std::fwrite(uncompressed_chunk.data(), sizeof(uncompressed_chunk[0]), + uncompressed_chunk.size(), output); +} diff --git a/src/uncompress.hh b/src/uncompress.hh index ac6ae0c..f76bd3c 100644 --- a/src/uncompress.hh +++ b/src/uncompress.hh @@ -5,9 +5,10 @@ #include #include -std::basic_string -lzw_uncompress(std::vector &&); +std::basic_string lzw_uncompress(std::vector &&); -void uncompress(const std::string &, const char*); +void uncompress(const std::string &, const char *); + +void uncompress_chunk(FILE *, FILE *); #endif /* LZW_SRC_UNCOMPRESS_H_ */