diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-03-01 19:56:04 +0100 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-03-01 19:56:04 +0100 |
| commit | 11f0868d01838b8fc91e2409309db50942b62b65 (patch) | |
| tree | 6059d248f724c7e74e03b7b9114f7d429a4d8e32 /Занимательное программирование/5/4_sound/main.cpp | |
| parent | 1768f21de7b75c98c932fcd734218d348b1b0060 (diff) | |
| download | book-exercises-11f0868d01838b8fc91e2409309db50942b62b65.tar.gz | |
Добавлена четвертая задача пятой главы
Diffstat (limited to 'Занимательное программирование/5/4_sound/main.cpp')
| -rw-r--r-- | Занимательное программирование/5/4_sound/main.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/Занимательное программирование/5/4_sound/main.cpp b/Занимательное программирование/5/4_sound/main.cpp new file mode 100644 index 0000000..b12bdae --- /dev/null +++ b/Занимательное программирование/5/4_sound/main.cpp @@ -0,0 +1,157 @@ +#include <iostream> +#include <fstream> +#include <cstring> +#include <array> +#include <list> +#include <vector> +#include <cstdint> +#include <sstream> +#include "huffman.hpp" + +int show_usage() +{ + std::cerr << "Usage: sound (compress|decompress) input_file output_file." << std::endl; + return 1; +} + +std::array<char, 44> read_header(std::ifstream& input_file) +{ + std::array<char, 44> wav_header; + + input_file.read(wav_header.data(), wav_header.size()); + + return wav_header; +} + +std::list<char> read_first_context(std::istreambuf_iterator<char>& input_iterator) +{ + std::list<char> result; + + result.push_back(*input_iterator); + ++input_iterator; + result.push_back(*input_iterator); + ++input_iterator; + + return result; +} + +int fc(const std::list<char>& context) +{ + auto c1 = context.front(); + auto c2 = context.back(); + + return c1 + (c1 - c2); +} + +int archive(const char *input_name, const char *output_name) +{ + std::ifstream input_file{ input_name, std::ios::binary | std::ios::in }; + input_file.exceptions(std::ios::badbit | std::ios::failbit); + + std::array<char, 44> wav_header = read_header(input_file); + + if (input_file.gcount() != 44) + { + // Not enough bytes available to read the header. + return 2; + } + std::istreambuf_iterator<char> wav_iterator(input_file), input_end; + std::list<char> context = read_first_context(wav_iterator); + + std::ofstream output_file{ output_name, std::ios::binary | std::ios::trunc | std::ios::in }; + output_file.exceptions(std::ios::badbit | std::ios::failbit); + + output_file.write(wav_header.data(), wav_header.size()); + output_file.write(&context.front(), 1); + output_file.write(&context.back(), 1); + + std::vector<std::uint8_t> encoding; + + while (wav_iterator != input_end) + { + int guess = fc(context); + int error = *wav_iterator - guess; + + // Update the context. + context.pop_back(); + context.push_back(*wav_iterator); + + encoding.push_back(error >> 8); + encoding.push_back(error); + + ++wav_iterator; + } + compress(encoding, output_file); + return 0; +} + +int unarchive(const char *input_name, const char *output_name) +{ + std::ifstream input_file{ input_name, std::ios::binary | std::ios::in }; + input_file.exceptions(std::ios::badbit | std::ios::failbit); + + std::array<char, 44> wav_header = read_header(input_file); + + if (input_file.gcount() != 44) + { + // Not enough bytes available to read the header. + return 2; + } + std::istreambuf_iterator<char> wav_iterator(input_file), input_end; + std::list<char> context = read_first_context(wav_iterator); + std::stringstream encoding_stream; + std::vector<std::uint8_t> encoded_wav{ wav_iterator, input_end }; + + decompress(encoded_wav, encoding_stream); + + std::ofstream output_file{ output_name, std::ios::binary | std::ios::trunc | std::ios::in }; + output_file.exceptions(std::ios::badbit | std::ios::failbit); + + output_file.write(wav_header.data(), wav_header.size()); + output_file.write(&context.front(), 1); + output_file.write(&context.back(), 1); + + std::string encoding = encoding_stream.str(); + auto current_encoding = std::cbegin(encoding); + + while (current_encoding != std::cend(encoding)) + { + std::uint8_t first_byte = *current_encoding; + ++current_encoding; + std::uint8_t second_byte = *current_encoding; + ++current_encoding; + int error = (first_byte << 8) | second_byte; + + int guess = fc(context); + char element = error + guess; + + // Update the context. + context.pop_back(); + context.push_back(element); + + output_file.write(&element, 1); + } + + return 0; +} + +int main(int argc, char **argv) +{ + if (argc != 4) + { + return show_usage(); + } + if (std::strcmp(argv[1], "compress") == 0) + { + return archive(argv[2], argv[3]); + } + else if (std::strcmp(argv[1], "decompress") == 0) + { + return unarchive(argv[2], argv[3]); + } + else + { + return show_usage(); + } + return 0; +} |
