From 3a4eff5ceb86b7ed83dcc99c169ef5f1906fbd32 Mon Sep 17 00:00:00 2001 From: Phuntsok Drak-pa Date: Thu, 3 May 2018 13:28:17 +0200 Subject: [PATCH] Fixed crashing processes and changed file writer --- src/compress.cc | 29 ++++++++------- src/compress.hh | 7 ++-- src/io.cc | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ src/io.hh | 31 ++++++++++++++++ 4 files changed, 146 insertions(+), 16 deletions(-) create mode 100644 src/io.cc create mode 100644 src/io.hh diff --git a/src/compress.cc b/src/compress.cc index 0c40e0b..87e3f63 100644 --- a/src/compress.cc +++ b/src/compress.cc @@ -9,12 +9,15 @@ #include #include #include +#include "io.hh" using dict_t = std::map, uint32_t>; using ustring = std::basic_string; // chaîne non encodée -using uvec = std::vector; // chaîne encodée +using uvec = std::vector; // chaîne encodée using std::printf; +constexpr size_t CHUNK_SIZE = 32768; + /** * * Reçoit une liste de paires std::thread/vecteurs, le premier étant le @@ -26,14 +29,12 @@ using std::printf; */ void join_and_write( std::vector, uvec>> &t_threads, - FILE *t_out) { + std::vector> &compressed_text) { for (auto &elem : t_threads) { (*elem.first).join(); } for (auto &elem : t_threads) { - for (const auto c : elem.second) { - write_utf8(t_out, c); - } + compressed_text.push_back(std::move(elem.second)); } t_threads.clear(); } @@ -99,24 +100,28 @@ void compress(const std::string &t_in_file, const char *t_out_file) { exit(1); } + // collection of chunks + std::vector> compressed_text{}; + // thread pool std::vector, uvec>> threads{}; - // char chunk[32768]; - std::vector chunk(32768, 0); + // chunk chars + std::vector chunk(CHUNK_SIZE, 0); while (input_file.read(chunk.data(), static_cast(chunk.size()))) { threads.emplace_back(nullptr, uvec{}); + threads.back().second.reserve(CHUNK_SIZE); threads.back().first = std::make_unique( std::thread{lzw_compress, chunk, ref(threads.back().second)}); assert(threads.back().first); if (threads.size() >= 8) { - join_and_write(threads, out); + join_and_write(threads, compressed_text); } } if (!threads.empty()) { - join_and_write(threads, out); + join_and_write(threads, compressed_text); } if (input_file.tellg() != std::ios::end) { @@ -133,11 +138,11 @@ void compress(const std::string &t_in_file, const char *t_out_file) { } uvec ret{}; lzw_compress(chunk, ret); - for (const auto c : ret) { - write_utf8(out, c); - } + compressed_text.push_back(std::move(ret)); } + write_file(out, compressed_text); + fclose(out); input_file.close(); } diff --git a/src/compress.hh b/src/compress.hh index 056fa6f..39aaf71 100644 --- a/src/compress.hh +++ b/src/compress.hh @@ -12,10 +12,9 @@ #include /// \brief Exécution des threads et écriture de leur résultat dans le fichier de sortie -void join_and_write( - std::vector, std::vector>> - &, - FILE *); +void join_and_write(std::vector, + std::vector>> &, + std::vector> &); /// \brief Compression d'une chaine de caractères void lzw_compress(const std::vector &, std::vector &); diff --git a/src/io.cc b/src/io.cc new file mode 100644 index 0000000..57ba9ba --- /dev/null +++ b/src/io.cc @@ -0,0 +1,95 @@ +/** + * \file io.cc + * \brief Body for file reading and writing + */ + +#include "io.hh" + +#ifdef Debug +constexpr bool debug_mode = true; +#else +constexpr bool debug_mode = false; +#endif + +/** + * É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 quatre octets sont écrit un `uint32_t` déterminant la taille d'un + * caractère\n + * - Sur quatre octets sont écrit un `uint32_t` déterminant le nombre de chunk + * composant le fichier\n + * - Sont ensuite écrits les chunks sur des nombres d’octets variable suivant + * la taille d’un caractère et le nombre de caractères\n + * \n + * Un chunk est composé de la manière qui suit :\n + * - Sur quatre octets sont écrit un `uint32_t` déterminant le nombre de + * caractères composant le chunk\n + * - Les caractères composant le chunk, accolés les uns au autres. Si le + * dernier caractère ne remplis pas le dernier octet du chunk, alors ces + * derniers bits seront initialisés à 0.\n + * La taille d’un chunk est donc la taille d’un caractère multiplié par le + * nombre de caractères du chunk, le tout divisé par 8. Si le résultat n’est + * pas un entier, alors il est nivelé vers le haut pour avoir un nombre entier + * d’octets (e.g. si le résultat est 103.4, alors 104 octets seront utilisés). + * + * \param[out] t_out Fichier de sortie + * \param[in] t_text Collection ordonnée des chunks à écrire dans \p t_out + */ +void write_file(FILE *t_out, std::vector> &t_text) { + { + uint32_t char_size = 12; + if constexpr (debug_mode) { + std::printf("Char size: %u\n", char_size); + } + fwrite(&char_size, sizeof(uint32_t), 1, t_out); + auto size = static_cast(t_text.size()); + if constexpr (debug_mode) { + std::printf("Number of chunks: %u\n", size); + } + fwrite(&size, sizeof(uint32_t), 1, t_out); + } + for(const auto &chunk : t_text) { + // write size of chunk in uint32_t + { + auto size = static_cast(chunk.size()); + if constexpr (debug_mode) { + std::printf("Size of chunk: %u\n", size); + } + fwrite(&size, sizeof(uint32_t), 1, t_out); + } + uint8_t remainder = 0x00; + for(size_t i = 0; i < chunk.size(); ++i) { + if(i % 2 == 0) { + // char = xxxx xxxx xxxx + // ^^^^^^^^^ ^^^^ + // write keep in remainder as xxxx0000 + auto temp = static_cast(chunk[i] >> 4); + fwrite(&temp, sizeof(temp), 1, t_out); + if constexpr (debug_mode) { + std::printf("writing: %x\t\t", temp); + } + remainder = static_cast(chunk[i] << 4); + } else { + // already have `remainder = yyyy0000` + // char = xxxx xxxx xxxx + // ^^^^ ^^^^^^^^^ + // remainder = yyyyxxxx write after remainder + // remainder = 00000000 + remainder &= static_cast(chunk[i]) >> 8 & 0xF0; + fwrite(&remainder, sizeof(remainder), 1, t_out); + if constexpr (debug_mode) { + std::printf("writing remainder: %x\t\t", remainder); + } + auto temp = static_cast(chunk[i]); + fwrite(&temp, sizeof(temp), 1, t_out); + if constexpr (debug_mode) { + std::printf("writing: %x\n", temp); + } + remainder = 0x00; + } + } + if(remainder != 0) { + fwrite(&remainder, sizeof(remainder), 1, t_out); + } + } +} diff --git a/src/io.hh b/src/io.hh new file mode 100644 index 0000000..4f9f358 --- /dev/null +++ b/src/io.hh @@ -0,0 +1,31 @@ +/** + * \file io.h + * \brief Header for file reading and writing + */ + +#ifndef LZW_SRC_IO_H_ +#define LZW_SRC_IO_H_ + +#include +#include +#include + +/* + * Un fichier compressé se compose ainsi : + * char_size : taille d'un caractère en bits (1B) + * nb_chunk : nombre de chunks (4B) + * chunks* : chunks + * + * 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)) + * + * 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 *, std::vector> &); + +#endif /* LZW_SRC_IO_H_ */