Argent007

LZW codec

Mar 26th, 2023
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.20 KB | None | 0 0
  1. #include <fstream>
  2. #include <iostream>
  3. #include <map>
  4. #include <optional>
  5. #include <vector>
  6. #include <algorithm>
  7.  
  8. std::string num_to_bitstring(int count, uint64_t num)
  9. {
  10.     std::string res(count, '0');
  11.     for (size_t i = 0; i < count; i++)
  12.     {
  13.         if (num % 2)
  14.             res[i] = '1';
  15.         num /= 2;
  16.     }
  17.     std::reverse(begin(res), end(res));
  18.     return res;
  19. }
  20.  
  21. class bit_reader
  22. {
  23.     std::istream inp;
  24.     uint64_t buffer;
  25.     size_t buffer_length;
  26. public:
  27.     bit_reader(std::istream& input_stream) :inp(input_stream.rdbuf()), buffer(0), buffer_length(0)
  28.     {
  29.         static_assert(sizeof(decltype(inp)::char_type) == 1, "char_type must be 1-byte");
  30.     }
  31.     std::optional<uint64_t> get_bits(int count)
  32.     {
  33.         union { decltype(inp)::char_type ch; unsigned char u_ch; };
  34.         while ((buffer_length < count) && inp.get(ch))
  35.         {
  36.             buffer += ((uint64_t)u_ch) << buffer_length;
  37.             buffer_length += 8;
  38.         }
  39.         if (buffer_length < count)
  40.             return std::nullopt;
  41.         else
  42.         {
  43.             buffer_length -= count;
  44.             uint64_t result = buffer & (((uint64_t)1 << count) - 1);
  45.             buffer >>= count;
  46.             return result;
  47.         }
  48.     }
  49. };
  50.  
  51. class bit_writer
  52. {
  53.     std::ostream out;
  54.     uint64_t buffer;
  55.     size_t buffer_length;
  56. public:
  57.     bit_writer(std::ostream& output_stream) :out(output_stream.rdbuf()), buffer(0), buffer_length(0)
  58.     {
  59.         static_assert(sizeof(decltype(out)::char_type) == 1, "char_type must be 1-byte");
  60.     }
  61.     void write_bits(int count, uint64_t bits)
  62.     {
  63.         union { decltype(out)::char_type ch; unsigned char u_ch; };
  64.         buffer += bits << buffer_length;
  65.         buffer_length += count;
  66.         while (buffer_length >= 8)
  67.         {
  68.             u_ch = buffer & (((uint64_t)1<<8) - 1);
  69.             out.put(ch);
  70.             buffer >>= 8;
  71.             buffer_length -= 8;
  72.         }
  73.     }
  74.     ~bit_writer()
  75.     {
  76.         if (buffer_length > 0)
  77.             write_bits(8 - buffer_length, 0);
  78.         out.flush();
  79.     }
  80. };
  81.  
  82. namespace lzw {
  83.     void encode2(std::istream& ifs, std::ostream& ofs, const uint8_t bits_per_index);
  84.     void decode2(std::istream& ifs, std::ostream& ofs);
  85. }
  86.  
  87. void lzw::encode2(std::istream& ifs, std::ostream& ofs, const uint8_t bits_per_index) {
  88.     bit_writer out(ofs);
  89.     std::map<std::string, int> map;
  90.     for (int i = 0; i < 256; i++) {
  91.         map[std::string(1, (char)i)] = i;
  92.     }
  93.     out.write_bits(8, bits_per_index);
  94.     std::string prefix = "";
  95.     char ch;
  96.     while (ifs.get(ch)) {
  97.         std::string new_prefix = prefix + ch;
  98.         if (map.contains(new_prefix)) {
  99.             prefix = std::move(new_prefix);
  100.         }
  101.         else {
  102.             //std::cout << map.size() << " [" << new_prefix << "]\n";
  103.             if (map.size() < 1ull << bits_per_index)
  104.             {
  105.                 map[new_prefix] = map.size();
  106.                 out.write_bits(bits_per_index, map[prefix]);
  107.                 prefix = ch;
  108.             }
  109.             else
  110.             {
  111.                 out.write_bits(bits_per_index, map[prefix]);
  112.                 prefix = ch;
  113.                 map.clear();
  114.                 for (int i = 0; i < 256; i++) {
  115.                     map[std::string(1, (char)i)] = i;
  116.                 }
  117.             }
  118.         }
  119.     }
  120.     if(prefix != "")
  121.         out.write_bits(bits_per_index, map[prefix]);
  122. }
  123.  
  124.  
  125.  
  126. void lzw::decode2(std::istream& ifs, std::ostream& ofs)
  127. {
  128.     bit_reader inp(ifs);
  129.     auto bpi = inp.get_bits(8);
  130.     if (!bpi)
  131.         return;
  132.     auto bits_per_index = *bpi;
  133.  
  134.     std::vector<std::string> map;
  135.     for (int i = 0; i < 256; i++) {
  136.         map.push_back(std::string(1, (char)i));
  137.     }
  138.  
  139.     std::optional<uint64_t> index;
  140.     int prev_index = -1;
  141.     while (index = inp.get_bits(bits_per_index)) {
  142.         if (*index < map.size())
  143.         {
  144.             ofs.write(map[*index].c_str(), map[*index].length());
  145.             if (prev_index != -1)
  146.                 if(map.size()< 1ull<<bits_per_index)
  147.                     map.push_back(map[prev_index] + map[*index][0]);
  148.                 else
  149.                     map.resize(256);
  150.         }
  151.         else
  152.         {
  153.             map.push_back(map[prev_index] + map[prev_index][0]);
  154.             ofs.write(map.back().c_str(), map.back().length());
  155.         }
  156.         prev_index = *index;
  157.     }
  158. }
  159.  
  160.  
  161.  
  162. int main() {
  163.  
  164.     std::ifstream test_in("a.txt", std::ios::binary);
  165.     //std::cout << std::endl;
  166.     std::ofstream test_out("a_enc.lzw", std::ios::binary);
  167.  
  168.     lzw::encode2(test_in, test_out, 9);
  169.     test_out.close();
  170.  
  171.     std::cout << std::endl;
  172.     std::ifstream encoded_in("a_enc.lzw", std::ios::binary);
  173.     std::cout << std::endl;
  174.     std::ofstream decoded_out("a_dec.txt", std::ios::binary);
  175.  
  176.     lzw::decode2(encoded_in, decoded_out);
  177.     decoded_out.close();
  178.  
  179.     return 0;
  180. }
  181.  
  182. //-----------------------------------------------------------------------------------------------
Add Comment
Please, Sign In to add comment