Advertisement
kutuzzzov

Урок 5 Бинарные файлы

May 25th, 2023
1,293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.58 KB | None | 0 0
  1. // main.cpp
  2.  
  3. #include "compressor.h"
  4. #include "decompressor.h"
  5.  
  6. #include <cassert>
  7. #include <fstream>
  8. #include <string>
  9. #include <string_view>
  10.  
  11. using namespace std;
  12.  
  13. // эта функция нужна для теста
  14. string GetFileContents(string file) {
  15.     ifstream stream(file, ios::binary);
  16.  
  17.     stream.seekg(0, ios::end);
  18.     size_t sz = stream.tellg();
  19.  
  20.     stream.seekg(0, ios::beg);
  21.     string res(sz, '\0');
  22.  
  23.     if (stream.read(res.data(), sz)) {
  24.         return res;
  25.     }
  26.  
  27.     return {};
  28. }
  29.  
  30. void Test() {
  31.     ofstream("test.txt") << "abcdaaaaaabbbcdedecdec"sv << string(1000, 'x')
  32.                          << "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\xa0"
  33.                             "decdecdecasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdas"
  34.                             "dcdecasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasdcde"
  35.                             "casdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasdcdecasd"
  36.                             "asdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasddeccccccccc"
  37.                             "cccc"sv;
  38.     EncodeRLE("test.txt"s, "test.rle"s);
  39.     DecodeRLE("test.rle"s, "test2.txt"s);
  40.  
  41.     assert(GetFileContents("test.rle"s).size() < GetFileContents("test.txt"s).size() / 2);
  42.     assert(GetFileContents("test.txt"s) == GetFileContents("test2.txt"s));
  43. }
  44.  
  45. int main(int argc, const char** argv) {
  46.     if (argc == 1) {
  47.         Test();
  48.         return 0;
  49.     }
  50.  
  51.     if (argc != 4 || (argv[1] != "x"sv && argv[1] != "c"sv)) {
  52.         cout << "Usage: "sv << argv[0] << " c|x <in file> <out file>"sv << endl;
  53.         return 1;
  54.     }
  55.  
  56.     if (argv[1] == "c"sv) {
  57.         auto result = EncodeRLE(argv[2], argv[3]);
  58.         if (!result.opened) {
  59.             cout << "Error opening file"sv << endl;
  60.             return 2;
  61.         }
  62.  
  63.         cout << "Compressed "sv << result.src_size << " bytes => "sv << result.dst_size << " bytes"sv << endl;
  64.     } else {
  65.         if (!DecodeRLE(argv[2], argv[3])) {
  66.             cout << "Error decoding file"sv << endl;
  67.             return 3;
  68.         }
  69.  
  70.         cout << "Successfully decoded"sv << endl;
  71.     }
  72.  
  73.     return 0;
  74. }
  75.  
  76. // ---------------------
  77. // compressor.h
  78.  
  79. #pragma once
  80.  
  81. // Этот файл содержит компрессор RLE, не меняйте его.
  82. // Можете изучить устройство компрессора, чтобы лучше понять формат сжатого файла.
  83. // Сжатие и разжатие должно давать исходный файл
  84.  
  85. #include <fstream>
  86. #include <iostream>
  87. #include <string>
  88.  
  89. class CompressorRLE {
  90. public:
  91.     static const int max_block_size = 128;
  92.     static const int min_repeats_for_special_block = 3;
  93.  
  94.     CompressorRLE(std::ostream& dst)
  95.         : dst_(dst) {
  96.     }
  97.  
  98.     void PutChar(char c) {
  99.         if (block_size_ > 0 && c == last_char_) {
  100.             ++repeat_count_;
  101.             if (repeat_count_ >= max_block_size - 1) {
  102.                 FinalizeRepeats();
  103.             }
  104.             return;
  105.         }
  106.  
  107.         FinalizeRepeats();
  108.         AddCharToBlock(c);
  109.     }
  110.  
  111.     void Finalize() {
  112.         FinalizeRepeats();
  113.         WriteBlock0(block, block_size_);
  114.     }
  115.  
  116.     size_t GetCompressedSize() const {
  117.         return compressed_size_;
  118.     }
  119.  
  120. private:
  121.     void FinalizeRepeats() {
  122.         if (repeat_count_ == 0) {
  123.             return;
  124.         }
  125.  
  126.         // если недостаточно повторов для специального блока
  127.         if (repeat_count_ < min_repeats_for_special_block) {
  128.             for (; repeat_count_ > 0; --repeat_count_) {
  129.                 AddCharToBlock(last_char_);
  130.             }
  131.             return;
  132.         }
  133.  
  134.         // если достаточно повторов
  135.         WriteBlock0(block, block_size_ - 1);
  136.         WriteBlock1(last_char_, repeat_count_ + 1);
  137.         block_size_ = 0;
  138.         repeat_count_ = 0;
  139.     };
  140.  
  141.     void AddCharToBlock(char c) {
  142.         block[block_size_++] = c;
  143.         if (block_size_ >= max_block_size) {
  144.             WriteBlock0(block, block_size_);
  145.             block_size_ = 0;
  146.         }
  147.         last_char_ = c;
  148.     }
  149.  
  150.     void WriteBlock0(char* data, int size) {
  151.         if (size == 0) {
  152.             return;
  153.         }
  154.  
  155.         unsigned char zero = static_cast<unsigned char>(((size - 1) << 1) + 0);
  156.         dst_.put(zero);
  157.         dst_.write(data, size);
  158.  
  159.         compressed_size_ += 1 + static_cast<size_t>(size);
  160.     }
  161.  
  162.     void WriteBlock1(char data, int size) {
  163.         if (size == 0) {
  164.             return;
  165.         }
  166.  
  167.         unsigned char zero = static_cast<unsigned char>(((size - 1) << 1) + 1);
  168.         dst_.put(zero);
  169.         dst_.put(data);
  170.  
  171.         compressed_size_ += 2;
  172.     }
  173.  
  174. private:
  175.     std::ostream& dst_;
  176.  
  177.     size_t compressed_size_ = 0;
  178.  
  179.     int block_size_ = 0;
  180.     int repeat_count_ = 0;
  181.     char last_char_;
  182.  
  183.     char block[max_block_size];
  184. };
  185.  
  186. struct EncodingResult {
  187.     bool opened;
  188.     size_t src_size;
  189.     size_t dst_size;
  190. };
  191.  
  192. inline EncodingResult EncodeRLE(std::string src_name, std::string dst_name) {
  193.     using namespace std;
  194.  
  195.     ifstream in(src_name, ios::binary);
  196.     if (!in) {
  197.         return {false, 0, 0};
  198.     }
  199.  
  200.     ofstream out(dst_name, ios::binary);
  201.  
  202.     CompressorRLE compressor(out);
  203.     size_t source_size = 0;
  204.  
  205.     do {
  206.         char buff[1024];
  207.         in.read(buff, sizeof buff);
  208.         size_t read = in.gcount();
  209.         source_size += read;
  210.  
  211.         for (size_t i = 0; i < read; ++i) {
  212.             compressor.PutChar(buff[i]);
  213.         }
  214.     } while (in);
  215.  
  216.     compressor.Finalize();
  217.  
  218.     return {true, source_size, compressor.GetCompressedSize()};
  219. }
  220. // -----------------------
  221.  
  222. // decompressor.h
  223.  
  224. #pragma once
  225.  
  226. #include <string>
  227. #include <fstream>
  228.  
  229. using namespace std;
  230.  
  231. // напишите эту функцию
  232. inline bool DecodeRLE(const std::string& src_name, const std::string& dst_name) {
  233.     ifstream src(src_name, std::ios::in | std::ios::binary);
  234.     if (!src) {
  235.         return false;
  236.     }
  237.     ofstream dest(dst_name, std::ios::out | std::ios::binary);
  238.     do {
  239.         unsigned char header = src.get();
  240.         bool series_flag = (header & 1);
  241.         size_t data_size = static_cast<size_t>(header >> 1) + 1;
  242.         if (!series_flag && !src.eof()) {
  243.             char buff[128];
  244.             src.read(buff, data_size);
  245.             size_t readed = src.gcount();
  246.             dest.write(buff, readed);
  247.         }
  248.         else if (!src.eof()){
  249.             unsigned char symbol = src.get();
  250.             string str(data_size, symbol);
  251.             dest.write(str.data(), data_size);
  252.         }
  253.     } while (src);
  254.     return true;
  255. }
  256.  
  257.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement