diff --git a/src/bitpack.cc b/src/bitpack.cc index 2a508ce..a0a9cd6 100644 --- a/src/bitpack.cc +++ b/src/bitpack.cc @@ -10,108 +10,7 @@ using vuint16 = vector; using vuchar = vector; using ustring = std::basic_string; -int max(const int t_n) { - return ipow(2, t_n) - 1; -} - -/////////////////////////////////////////////////////////////////////////////// -// packing // -/////////////////////////////////////////////////////////////////////////////// - -vuchar pack(const vuint16 &t_input) { - return pack_n(t_input.begin(), t_input.end(), 9); -} - -/** - * Packs \p t_input into unsigned char, assuming the max value of t_input - * only takes \p t_n bits - * - * \param t_input_begin pointer to the beginning of the vector of values to be packed - * \param t_input_end pointer to the end of the input vector - * \param t_n maximum size of an input value in bits - * \return Returns a vector of unsigned 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, const int t_n) { - if (t_n == 16) { - return pack_16(t_input_begin, t_input_end); - } - const int max_value = max(t_n); // max value held within t_n bits - -#ifdef Debug - std::printf("%d bits! %ld chars remaining\n", t_n, - std::distance(t_input_begin, t_input_end)); - std::printf("max: %d\n", max_value); -#endif - - int step = t_n / 8; - int left_shift = 0; - int middle_shift = 0; - int right_shift = 0; - uchar current_char = 0; - bool char_touched = false; - vuchar ret{}; - - for (auto it = t_input_begin; it != t_input_end; ++it) { - if ((left_shift += step) >= t_n) { - left_shift = (left_shift - t_n) + step; - } - ret.push_back((current_char | (*it >> left_shift)) & 0xFFu); - // current_char = 0; - - bool zero_right_shift = (right_shift == 0); - right_shift -= step; - if (right_shift < 0) { - middle_shift = std::abs(right_shift); - right_shift = 8 - std::abs(right_shift); - if (!zero_right_shift) { - current_char = (*it >> middle_shift) & 0xFFu; - ret.push_back(current_char); - } - } - if (right_shift == 0) { - current_char = *it & 0xffu; - ret.push_back(current_char); - current_char = 0; - char_touched = false; - } else { - current_char = (*it << right_shift) & 0xFFu; - char_touched = true; - } - - // il faut écrire la valeur pour la décompression - if (*it >= max_value) { - if (char_touched) { - ret.push_back(current_char); - } - const auto next_vec = pack_n(it, t_input_end, t_n + 1); - ret.insert(ret.end(), next_vec.begin(), next_vec.end()); - return ret; - } - } - if (char_touched) { - ret.push_back(current_char); - } - return ret; -} - -vuchar pack_16(const vuint16::const_iterator t_input_begin, - const vuint16::const_iterator t_input_end) { -#ifdef Debug - std::printf("16 bits! %ld chars remaining\n", - std::distance(t_input_begin, t_input_end)); -#endif - vuchar ret{}; - std::for_each(t_input_begin, t_input_end, [&](const auto value) { - ret.push_back((value >> 8) & 0xFFu); - ret.push_back(value & 0xFFu); - }); - return ret; -} - -/////////////////////////////////////////////////////////////////////////////// -// unpacking // -/////////////////////////////////////////////////////////////////////////////// +int max(const int t_n) { return ipow(2, t_n) - 1; } constexpr uint16_t mask_n(int t_nb_bits) { if (t_nb_bits == 0) { @@ -128,60 +27,167 @@ constexpr uint16_t masks[17] = { mask_n(6), mask_n(7), mask_n(8), mask_n(9), mask_n(10), mask_n(11), mask_n(12), mask_n(13), mask_n(14), mask_n(15), mask_n(16)}; +/////////////////////////////////////////////////////////////////////////////// +// packing // +/////////////////////////////////////////////////////////////////////////////// + +vuchar pack(const vuint16 &t_input) { + return pack_n(t_input.begin(), t_input.end(), vuchar{}, 9); +} + +/** + * Packs \p t_input into unsigned char, assuming the max value of t_input + * only takes \p t_n bits + * + * \param t_input_begin pointer to the beginning of the vector of values to be + * packed \param t_input_end pointer to the end of the input vector \param t_n + * maximum size of an input value in bits \return Returns a vector of unsigned + * 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, + int t_n) { + if (t_n == 16) { + return pack_16(t_input_begin, t_input_end, vector()); + } + const int max_value = max(t_n); // max value held within t_n bits + +#ifdef Debug + std::printf("%d bits! %ld chars remaining\n", t_n, + std::distance(t_input_begin, t_input_end)); + std::printf("max: %d\n", max_value); +#endif + + int step = t_n % 8; + int left_shift = 0; + int right_shift = 0; + uchar current_char = 0; + bool char_touched = false; + + // 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 + if (*it >= max_value) { + // é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)); + bool zero_rs = (right_shift == 0); + right_shift -= 0; + if(right_shift < 0) { + if(!zero_rs) { + current_char = static_cast(masks[t_n] >> (-right_shift) & 0xffu); + t_res.push_back(current_char); + } + } + t_res.push_back(static_cast(masks[t_n])); + return pack_n(it, t_input_end, t_res, t_n + 1); + } + + if ((left_shift += step) >= t_n) { + left_shift = (left_shift - t_n) + step; + } + t_res.push_back( + static_cast(current_char | (*it >> left_shift & 0xFFu))); + // current_char = 0; + + bool zero_rs = (right_shift == 0); + right_shift -= step; + if (right_shift < 0) { + if (!zero_rs) { + current_char = static_cast(*it >> (-right_shift) & 0xFFu); + t_res.push_back(current_char); + } + right_shift = 8 + right_shift; + } + if (right_shift == 0) { + current_char = static_cast(*it & 0xffu); + t_res.push_back(current_char); + current_char = 0; + char_touched = false; + } else { + current_char = static_cast(*it << right_shift & 0xFFu); + char_touched = true; + } + } + if (char_touched) { + t_res.push_back(current_char); + } + return t_res; +} + +vuchar pack_16(const vuint16::const_iterator t_input_begin, + const vuint16::const_iterator t_input_end, vuchar t_res) { +#ifdef Debug + std::printf("16 bits! %ld chars remaining\n", + std::distance(t_input_begin, t_input_end)); +#endif + std::for_each(t_input_begin, t_input_end, [&](const auto value) { + t_res.push_back((value >> 8) & 0xFFu); + t_res.push_back(value & 0xFFu); + }); + return t_res; +} + +/////////////////////////////////////////////////////////////////////////////// +// unpacking // +/////////////////////////////////////////////////////////////////////////////// + vuint16 unpack(ustring &&t_input) { - return unpack_n(t_input.begin(), t_input.end(), 9); + return unpack_n(t_input.begin(), t_input.end(), vuint16{}, 9); } vuint16 unpack_n(const ustring::const_iterator t_begin, - const ustring::const_iterator t_end, const int t_n) { + const ustring::const_iterator t_end, vuint16 t_res, int t_n) { #ifdef Debug std::printf("Chunk! %d bits, %ld compressed chars\n", t_n, std::distance(t_begin, t_end)); #endif if (t_n == 16) { - return unpack_16(t_begin, t_end); + return unpack_16(t_begin, t_end, vector()); } - int step = t_n / 8; + int step = t_n % 8; int left_shift = 0; int right_shift = 0; - vuint16 ret{}; const int max_value = max(t_n); for (auto it = t_begin; it < t_end - 1; /* nope */) { uint16_t current_char = 0; // left bits - left_shift = - ((left_shift += step) >= t_n) ? (left_shift - t_n) + step : left_shift; - current_char = static_cast(*it << left_shift); + if ((left_shift += step) >= t_n) { + left_shift = (left_shift - t_n) + step; + } + current_char = static_cast(*it << left_shift) & masks[t_n]; // right bits - bool zero_rs = right_shift; + bool zero_rs = (right_shift == 0); right_shift -= step; if (right_shift < 0) { - // optional middle bits before right bits - if (zero_rs) { - current_char |= *++it << (-right_shift); + // if previous right shift was negative and not zero + if (!zero_rs) { + current_char |= *++it << (-right_shift) & masks[16 + right_shift]; } right_shift = 8 + right_shift; } - current_char |= *(++it) >> right_shift; + current_char |= *++it >> right_shift & masks[8 - right_shift]; // char made! - ret.push_back(current_char &= masks[t_n]); - if (current_char >= max_value) { - const auto next_vec = unpack_n(it + 1, t_end, t_n + 1); - ret.insert(ret.end(), next_vec.begin(), next_vec.end()); - return ret; + if (current_char >= max_value) { // if it is the mask + return unpack_n(it + 1, t_end, t_res, t_n + 1); } + t_res.push_back(current_char &= masks[t_n]); if (right_shift == 0) { ++it; } } - return ret; + return t_res; } vuint16 unpack_16(const ustring::const_iterator t_begin, - const ustring::const_iterator t_end) { - vuint16 ret{}; + const ustring::const_iterator t_end, vuint16 t_res) { for (auto it = t_begin; it < t_end; ++it) { - ret.push_back(static_cast((*it << 8) | *(++it))); + t_res.push_back(static_cast(*it << 8 | *++it)); } - return ret; + return t_res; } diff --git a/src/bitpack.hh b/src/bitpack.hh index e3d37d2..beddb8f 100644 --- a/src/bitpack.hh +++ b/src/bitpack.hh @@ -15,22 +15,24 @@ std::vector pack(const std::vector &); /// \brief Packs std::uint16_t of n bits into unsigned char std::vector -pack_n(const std::vector::const_iterator, - const std::vector::const_iterator, const int); +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(const std::vector::const_iterator, - const std::vector::const_iterator); +pack_16(std::vector::const_iterator , std::vector::const_iterator , + std::vector ); std::vector unpack(std::basic_string &&); std::vector -unpack_n(const std::basic_string::const_iterator, - const std::basic_string::const_iterator, const int t_n); +unpack_n(std::basic_string::const_iterator t_begin, + std::basic_string::const_iterator t_end, + std::vector t_res, int t_n); std::vector -unpack_16(const std::basic_string::const_iterator, - const std::basic_string::const_iterator); +unpack_16(std::basic_string::const_iterator, + std::basic_string::const_iterator, + std::vector); #endif /* LZW_SRC_BITPACK_H_ */ diff --git a/src/uncompress.cc b/src/uncompress.cc index b1427a2..28ca44f 100644 --- a/src/uncompress.cc +++ b/src/uncompress.cc @@ -24,6 +24,9 @@ ustring lzw_uncompress(vuint16 &&t_compressed) { for (auto it = t_compressed.begin() + 1; it != t_compressed.end(); ++it) { v = *it; const auto uncompressed{dico_uncompress(dict, v, old)}; +#ifdef Debug + std::printf("%d = %s\n", v, uncompressed.c_str()); +#endif ret.insert(ret.end(), uncompressed.begin(), uncompressed.end()); old = v; }