aboutsummaryrefslogtreecommitdiff
path: root/Занимательное программирование/5/4_sound/main.cpp
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-03-01 19:56:04 +0100
committerEugen Wissner <belka@caraus.de>2026-03-01 19:56:04 +0100
commit11f0868d01838b8fc91e2409309db50942b62b65 (patch)
tree6059d248f724c7e74e03b7b9114f7d429a4d8e32 /Занимательное программирование/5/4_sound/main.cpp
parent1768f21de7b75c98c932fcd734218d348b1b0060 (diff)
downloadbook-exercises-11f0868d01838b8fc91e2409309db50942b62b65.tar.gz
Добавлена четвертая задача пятой главы
Diffstat (limited to 'Занимательное программирование/5/4_sound/main.cpp')
-rw-r--r--Занимательное программирование/5/4_sound/main.cpp157
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;
+}