shushus

Спринт 12. Бинарные файлы: читаем и пишем байты.

Apr 6th, 2023
349
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.16 KB | None | 0 0
  1. -----------------------------------------------------------------------
  2. compressor.h
  3. -----------------------------------------------------------------------
  4. #pragma once
  5.  
  6. #include <fstream>
  7. #include <iostream>
  8. #include <string>
  9.  
  10. class CompressorRLE {
  11. public:
  12.     static const int max_block_size = 128;
  13.     static const int min_repeats_for_special_block = 3;
  14.  
  15.     CompressorRLE(std::ostream& dst) : dst_(dst) {}
  16.  
  17.     void PutChar(char c) {
  18.        
  19.         if (block_size_ > 0 && c == last_char_) {
  20.             ++repeat_count_;
  21.            
  22.             if (repeat_count_ >= max_block_size - 1) {
  23.                 FinalizeRepeats();
  24.             }
  25.             return;
  26.         }
  27.  
  28.         FinalizeRepeats();
  29.         AddCharToBlock(c);
  30.     }
  31.  
  32.     void Finalize() {
  33.         FinalizeRepeats();
  34.         WriteBlock0(block, block_size_);
  35.     }
  36.  
  37.     size_t GetCompressedSize() const {
  38.         return compressed_size_;
  39.     }
  40.  
  41. private:
  42.     void FinalizeRepeats() {
  43.         if (repeat_count_ == 0) {
  44.             return;
  45.         }
  46.  
  47.         if (repeat_count_ < min_repeats_for_special_block) {
  48.             for (; repeat_count_ > 0; --repeat_count_) {
  49.                 AddCharToBlock(last_char_);
  50.             }
  51.             return;
  52.         }
  53.  
  54.         WriteBlock0(block, block_size_ - 1);
  55.         WriteBlock1(last_char_, repeat_count_ + 1);
  56.         block_size_ = 0;
  57.         repeat_count_ = 0;
  58.     };
  59.  
  60.     void AddCharToBlock(char c) {
  61.         block[block_size_++] = c;
  62.        
  63.         if (block_size_ >= max_block_size) {
  64.             WriteBlock0(block, block_size_);
  65.             block_size_ = 0;
  66.         }
  67.        
  68.         last_char_ = c;
  69.     }
  70.  
  71.     void WriteBlock0(char* data, int size) {
  72.         if (size == 0) {
  73.             return;
  74.         }
  75.  
  76.         unsigned char zero = static_cast<unsigned char>(((size - 1) << 1) + 0);
  77.         dst_.put(zero);
  78.         dst_.write(data, size);
  79.  
  80.         compressed_size_ += 1 + static_cast<size_t>(size);
  81.     }
  82.  
  83.     void WriteBlock1(char data, int size) {
  84.         if (size == 0) {
  85.             return;
  86.         }
  87.  
  88.         unsigned char zero = static_cast<unsigned char>(((size - 1) << 1) + 1);
  89.         dst_.put(zero);
  90.         dst_.put(data);
  91.  
  92.         compressed_size_ += 2;
  93.     }
  94.  
  95. private:
  96.     std::ostream& dst_;
  97.  
  98.     size_t compressed_size_ = 0;
  99.  
  100.     int block_size_ = 0;
  101.     int repeat_count_ = 0;
  102.     char last_char_;
  103.  
  104.     char block[max_block_size];
  105. };
  106.  
  107. struct EncodingResult {
  108.     bool opened;
  109.     size_t src_size;
  110.     size_t dst_size;
  111. };
  112.  
  113. inline EncodingResult EncodeRLE(std::string src_name, std::string dst_name) {
  114.     using namespace std;
  115.  
  116.     ifstream in(src_name, ios::binary);
  117.     if (!in) {
  118.         return {false, 0, 0};
  119.     }
  120.  
  121.     ofstream out(dst_name, ios::binary);
  122.  
  123.     CompressorRLE compressor(out);
  124.     size_t source_size = 0;
  125.  
  126.     do {
  127.         char buff[1024];
  128.         in.read(buff, sizeof buff);
  129.         size_t read = in.gcount();
  130.         source_size += read;
  131.  
  132.         for (size_t i = 0; i < read; ++i) {
  133.             compressor.PutChar(buff[i]);
  134.         }
  135.     } while (in);
  136.  
  137.     compressor.Finalize();
  138.  
  139.     return {true, source_size, compressor.GetCompressedSize()};
  140. }
  141. -----------------------------------------------------------------------
  142. decompressor.h
  143. -----------------------------------------------------------------------
  144. #pragma once
  145.  
  146. #include <fstream>
  147. #include <iostream>
  148. #include <string>
  149.  
  150. static const int BUFF_SIZE = 1024;
  151. static const int MAX_BLOCK_SIZE = 128;
  152.  
  153. enum BlockType : int {
  154.     Empty,
  155.     Compression,
  156.     NoCompression,
  157. };
  158.  
  159. class DeCompressorRLE {
  160. public:
  161.  
  162.     DeCompressorRLE(std::ostream& dst) : dst_(dst) {}
  163.  
  164.     BlockType get_block_type() {
  165.         return block_type_;
  166.     }
  167.  
  168.     void read_header(u_char header) {
  169.         bool block_type = header & 1;
  170.         data_size_ = (header >> 1) + 1 ;
  171.        
  172.         if (block_type) {
  173.             block_type_= Compression;
  174.         } else {
  175.             block_type_ = NoCompression;
  176.         }
  177.     }
  178.    
  179.     void write(bool primary = 0) {
  180.         write_data_ += data_size_;
  181.  
  182.         if (primary || BUFF_SIZE - MAX_BLOCK_SIZE <= write_data_) {
  183.             dst_.write(block, write_data_);
  184.             write_data_ = 0;
  185.         }
  186.        
  187.         add_data_size_ = 0;
  188.         data_size_ = 0;
  189.         block_type_ = Empty;
  190.     }
  191.    
  192.     void read_data(char data) {          
  193.         if (block_type_== Compression) {
  194.            
  195.             for (size_t i = 0; i < data_size_; ++i) {
  196.                 block[i + write_data_] = data;
  197.             }
  198.             write();
  199.            
  200.         } else if (block_type_ == NoCompression) {
  201.            
  202.             if (data_size_ > add_data_size_) {
  203.                 block[write_data_+add_data_size_++] = data;  
  204.             } else {
  205.                 write();
  206.                 read_header(data);
  207.             }
  208.         }    
  209.     }
  210.    
  211. private:
  212.     std::ostream& dst_;
  213.     char block[BUFF_SIZE] = {' '};
  214.    
  215.     int data_size_ = 0;
  216.     int add_data_size_ = 0;
  217.     int write_data_ = 0;
  218.    
  219.     BlockType block_type_ = Empty;
  220. };
  221.  
  222. inline bool DecodeRLE(const std::string& src_name, const std::string& dst_name) {
  223.     using namespace std;
  224.  
  225.     ifstream input(src_name, ios::in | ios::binary);
  226.    
  227.     if (!input) {
  228.         return false;
  229.     }
  230.  
  231.     ofstream output(dst_name, ios::out | ios::binary);
  232.  
  233.     DeCompressorRLE de_compressor_rle(output);
  234.  
  235.     do {
  236.         char buff[BUFF_SIZE];
  237.         input.read(buff, sizeof buff);
  238.         size_t read = input.gcount();
  239.  
  240.         for (size_t i = 0; i < read; ++i) {
  241.            
  242.             if (de_compressor_rle.get_block_type() != Empty) {
  243.                 de_compressor_rle.read_data(buff[i]);
  244.             } else {
  245.                 de_compressor_rle.read_header(buff[i]);
  246.             }
  247.         }
  248.        
  249.     } while (input);
  250.    
  251.     de_compressor_rle.write(true);
  252.     return true;
  253. }
  254. -----------------------------------------------------------------------
  255. main.cpp
  256. -----------------------------------------------------------------------
  257. #include "compressor.h"
  258. #include "decompressor.h"
  259.  
  260. #include <cassert>
  261. #include <fstream>
  262. #include <string>
  263. #include <string_view>
  264.  
  265. using namespace std;
  266.  
  267. string GetFileContents(string file) {
  268.     ifstream stream(file, ios::binary);
  269.  
  270.     stream.seekg(0, ios::end);
  271.     size_t sz = stream.tellg();
  272.  
  273.     stream.seekg(0, ios::beg);
  274.     string res(sz, '\0');
  275.  
  276.     if (stream.read(res.data(), sz)) {
  277.         return res;
  278.     }
  279.  
  280.     return {};
  281. }
  282.  
  283. void Test() {
  284.     ofstream("test.txt") << "abcdaaaaaabbbcdedecdec"sv << string(1000, 'x')
  285.                          << "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\xa0"
  286.                             "decdecdecasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdas"
  287.                             "dcdecasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasdcde"
  288.                             "casdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasdcdecasd"
  289.                             "asdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasddeccccccccc"
  290.                             "cccc"sv;
  291.     EncodeRLE("test.txt"s, "test.rle"s);
  292.     DecodeRLE("test.rle"s, "test2.txt"s);
  293.  
  294.     assert(GetFileContents("test.rle"s).size() < GetFileContents("test.txt"s).size() / 2);
  295.     assert(GetFileContents("test.txt"s) == GetFileContents("test2.txt"s));
  296. }
  297.  
  298. int main(int argc, const char** argv) {
  299.     if (argc == 1) {
  300.         Test();
  301.         return 0;
  302.     }
  303.  
  304.     if (argc != 4 || (argv[1] != "x"sv && argv[1] != "c"sv)) {
  305.         cout << "Usage: "sv << argv[0] << " c|x <in file> <out file>"sv << endl;
  306.         return 1;
  307.     }
  308.  
  309.     if (argv[1] == "c"sv) {
  310.         auto result = EncodeRLE(argv[2], argv[3]);
  311.         if (!result.opened) {
  312.             cout << "Error opening file"sv << endl;
  313.             return 2;
  314.         }
  315.  
  316.         cout << "Compressed "sv << result.src_size << " bytes => "sv << result.dst_size << " bytes"sv << endl;
  317.     } else {
  318.         if (!DecodeRLE(argv[2], argv[3])) {
  319.             cout << "Error decoding file"sv << endl;
  320.             return 3;
  321.         }
  322.  
  323.         cout << "Successfully decoded"sv << endl;
  324.     }
  325.  
  326.     return 0;
  327. }
  328.  
Advertisement
Add Comment
Please, Sign In to add comment