Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // main.cpp
- #include "compressor.h"
- #include "decompressor.h"
- #include <cassert>
- #include <fstream>
- #include <string>
- #include <string_view>
- using namespace std;
- // эта функция нужна для теста
- string GetFileContents(string file) {
- ifstream stream(file, ios::binary);
- stream.seekg(0, ios::end);
- size_t sz = stream.tellg();
- stream.seekg(0, ios::beg);
- string res(sz, '\0');
- if (stream.read(res.data(), sz)) {
- return res;
- }
- return {};
- }
- void Test() {
- ofstream("test.txt") << "abcdaaaaaabbbcdedecdec"sv << string(1000, 'x')
- << "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\xa0"
- "decdecdecasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdas"
- "dcdecasdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasdcde"
- "casdasdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasdcdecasd"
- "asdasdasdasdasdasdasdasdasdasdasdasdasdasdassdasdassdasddeccccccccc"
- "cccc"sv;
- EncodeRLE("test.txt"s, "test.rle"s);
- DecodeRLE("test.rle"s, "test2.txt"s);
- assert(GetFileContents("test.rle"s).size() < GetFileContents("test.txt"s).size() / 2);
- assert(GetFileContents("test.txt"s) == GetFileContents("test2.txt"s));
- }
- int main(int argc, const char** argv) {
- if (argc == 1) {
- Test();
- return 0;
- }
- if (argc != 4 || (argv[1] != "x"sv && argv[1] != "c"sv)) {
- cout << "Usage: "sv << argv[0] << " c|x <in file> <out file>"sv << endl;
- return 1;
- }
- if (argv[1] == "c"sv) {
- auto result = EncodeRLE(argv[2], argv[3]);
- if (!result.opened) {
- cout << "Error opening file"sv << endl;
- return 2;
- }
- cout << "Compressed "sv << result.src_size << " bytes => "sv << result.dst_size << " bytes"sv << endl;
- } else {
- if (!DecodeRLE(argv[2], argv[3])) {
- cout << "Error decoding file"sv << endl;
- return 3;
- }
- cout << "Successfully decoded"sv << endl;
- }
- return 0;
- }
- // ---------------------
- // compressor.h
- #pragma once
- // Этот файл содержит компрессор RLE, не меняйте его.
- // Можете изучить устройство компрессора, чтобы лучше понять формат сжатого файла.
- // Сжатие и разжатие должно давать исходный файл
- #include <fstream>
- #include <iostream>
- #include <string>
- class CompressorRLE {
- public:
- static const int max_block_size = 128;
- static const int min_repeats_for_special_block = 3;
- CompressorRLE(std::ostream& dst)
- : dst_(dst) {
- }
- void PutChar(char c) {
- if (block_size_ > 0 && c == last_char_) {
- ++repeat_count_;
- if (repeat_count_ >= max_block_size - 1) {
- FinalizeRepeats();
- }
- return;
- }
- FinalizeRepeats();
- AddCharToBlock(c);
- }
- void Finalize() {
- FinalizeRepeats();
- WriteBlock0(block, block_size_);
- }
- size_t GetCompressedSize() const {
- return compressed_size_;
- }
- private:
- void FinalizeRepeats() {
- if (repeat_count_ == 0) {
- return;
- }
- // если недостаточно повторов для специального блока
- if (repeat_count_ < min_repeats_for_special_block) {
- for (; repeat_count_ > 0; --repeat_count_) {
- AddCharToBlock(last_char_);
- }
- return;
- }
- // если достаточно повторов
- WriteBlock0(block, block_size_ - 1);
- WriteBlock1(last_char_, repeat_count_ + 1);
- block_size_ = 0;
- repeat_count_ = 0;
- };
- void AddCharToBlock(char c) {
- block[block_size_++] = c;
- if (block_size_ >= max_block_size) {
- WriteBlock0(block, block_size_);
- block_size_ = 0;
- }
- last_char_ = c;
- }
- void WriteBlock0(char* data, int size) {
- if (size == 0) {
- return;
- }
- unsigned char zero = static_cast<unsigned char>(((size - 1) << 1) + 0);
- dst_.put(zero);
- dst_.write(data, size);
- compressed_size_ += 1 + static_cast<size_t>(size);
- }
- void WriteBlock1(char data, int size) {
- if (size == 0) {
- return;
- }
- unsigned char zero = static_cast<unsigned char>(((size - 1) << 1) + 1);
- dst_.put(zero);
- dst_.put(data);
- compressed_size_ += 2;
- }
- private:
- std::ostream& dst_;
- size_t compressed_size_ = 0;
- int block_size_ = 0;
- int repeat_count_ = 0;
- char last_char_;
- char block[max_block_size];
- };
- struct EncodingResult {
- bool opened;
- size_t src_size;
- size_t dst_size;
- };
- inline EncodingResult EncodeRLE(std::string src_name, std::string dst_name) {
- using namespace std;
- ifstream in(src_name, ios::binary);
- if (!in) {
- return {false, 0, 0};
- }
- ofstream out(dst_name, ios::binary);
- CompressorRLE compressor(out);
- size_t source_size = 0;
- do {
- char buff[1024];
- in.read(buff, sizeof buff);
- size_t read = in.gcount();
- source_size += read;
- for (size_t i = 0; i < read; ++i) {
- compressor.PutChar(buff[i]);
- }
- } while (in);
- compressor.Finalize();
- return {true, source_size, compressor.GetCompressedSize()};
- }
- // -----------------------
- // decompressor.h
- #pragma once
- #include <string>
- #include <fstream>
- using namespace std;
- // напишите эту функцию
- inline bool DecodeRLE(const std::string& src_name, const std::string& dst_name) {
- ifstream src(src_name, std::ios::in | std::ios::binary);
- if (!src) {
- return false;
- }
- ofstream dest(dst_name, std::ios::out | std::ios::binary);
- do {
- unsigned char header = src.get();
- bool series_flag = (header & 1);
- size_t data_size = static_cast<size_t>(header >> 1) + 1;
- if (!series_flag && !src.eof()) {
- char buff[128];
- src.read(buff, data_size);
- size_t readed = src.gcount();
- dest.write(buff, readed);
- }
- else if (!src.eof()){
- unsigned char symbol = src.get();
- string str(data_size, symbol);
- dest.write(str.data(), data_size);
- }
- } while (src);
- return true;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement