From 11f0868d01838b8fc91e2409309db50942b62b65 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sun, 1 Mar 2026 19:56:04 +0100 Subject: =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0?= =?UTF-8?q?=20=D1=87=D0=B5=D1=82=D0=B2=D0=B5=D1=80=D1=82=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B4=D0=B0=D1=87=D0=B0=20=D0=BF=D1=8F=D1=82=D0=BE?= =?UTF-8?q?=D0=B9=20=D0=B3=D0=BB=D0=B0=D0=B2=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../5/4_sound/main.cpp" | 157 +++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 "\320\227\320\260\320\275\320\270\320\274\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \320\277\321\200\320\276\320\263\321\200\320\260\320\274\320\274\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265/5/4_sound/main.cpp" (limited to 'Занимательное программирование/5/4_sound/main.cpp') diff --git "a/\320\227\320\260\320\275\320\270\320\274\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \320\277\321\200\320\276\320\263\321\200\320\260\320\274\320\274\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265/5/4_sound/main.cpp" "b/\320\227\320\260\320\275\320\270\320\274\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \320\277\321\200\320\276\320\263\321\200\320\260\320\274\320\274\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265/5/4_sound/main.cpp" new file mode 100644 index 0000000..b12bdae --- /dev/null +++ "b/\320\227\320\260\320\275\320\270\320\274\320\260\321\202\320\265\320\273\321\214\320\275\320\276\320\265 \320\277\321\200\320\276\320\263\321\200\320\260\320\274\320\274\320\270\321\200\320\276\320\262\320\260\320\275\320\270\320\265/5/4_sound/main.cpp" @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "huffman.hpp" + +int show_usage() +{ + std::cerr << "Usage: sound (compress|decompress) input_file output_file." << std::endl; + return 1; +} + +std::array read_header(std::ifstream& input_file) +{ + std::array wav_header; + + input_file.read(wav_header.data(), wav_header.size()); + + return wav_header; +} + +std::list read_first_context(std::istreambuf_iterator& input_iterator) +{ + std::list result; + + result.push_back(*input_iterator); + ++input_iterator; + result.push_back(*input_iterator); + ++input_iterator; + + return result; +} + +int fc(const std::list& 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 wav_header = read_header(input_file); + + if (input_file.gcount() != 44) + { + // Not enough bytes available to read the header. + return 2; + } + std::istreambuf_iterator wav_iterator(input_file), input_end; + std::list 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 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 wav_header = read_header(input_file); + + if (input_file.gcount() != 44) + { + // Not enough bytes available to read the header. + return 2; + } + std::istreambuf_iterator wav_iterator(input_file), input_end; + std::list context = read_first_context(wav_iterator); + std::stringstream encoding_stream; + std::vector 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; +} -- cgit v1.2.3