34 #include <unordered_map>
43 const CodeType dms {std::numeric_limits<CodeType>::max()};
58 return std::hash<std::string>()(std::string(vc.cbegin(), vc.cend()));
68 std::vector<char>
operator + (std::vector<char> vc,
char c)
79 void compress(std::istream &is, std::ostream &os)
84 const auto reset_dictionary = [&dictionary] {
87 const long int minc = std::numeric_limits<char>::min();
88 const long int maxc = std::numeric_limits<char>::max();
90 for (
long int c = minc; c <= maxc; ++c)
94 const CodeType dictionary_size = dictionary.size();
96 dictionary[{
static_cast<char> (c)}] = dictionary_size;
108 if (dictionary.size() == globals::dms)
113 if (dictionary.count(s) == 0)
117 const CodeType dictionary_size = dictionary.size();
119 dictionary[s] = dictionary_size;
121 os.write(reinterpret_cast<const char *> (&dictionary.at(s)),
sizeof (CodeType));
127 os.write(reinterpret_cast<const char *> (&dictionary.at(s)),
sizeof (CodeType));
137 std::vector<std::vector<char>> dictionary;
140 const auto reset_dictionary = [&dictionary] {
142 dictionary.reserve(globals::dms);
144 const long int minc = std::numeric_limits<char>::min();
145 const long int maxc = std::numeric_limits<char>::max();
147 for (
long int c = minc; c <= maxc; ++c)
148 dictionary.push_back({static_cast<char> (c)});
156 while (is.read(reinterpret_cast<char *> (&k), sizeof (CodeType)))
159 if (dictionary.size() == globals::dms)
162 if (k > dictionary.size())
163 throw std::runtime_error(
"invalid compressed code");
165 if (k == dictionary.size())
166 dictionary.push_back(s + s.front());
169 dictionary.push_back(s + dictionary.at(k).front());
171 os.write(&dictionary.at(k).front(), dictionary.at(k).size());
172 s = dictionary.at(k);
175 if (!is.eof() || is.gcount() != 0)
176 throw std::runtime_error(
"corrupted compressed file");
187 std::cerr <<
"\nERROR: " << s <<
'\n';
191 std::cerr <<
"\nUsage:\n";
192 std::cerr <<
"\tprogram -flag input_file output_file\n\n";
193 std::cerr <<
"Where `flag' is either `c' for compressing, or `d' for decompressing, and\n";
194 std::cerr <<
"`input_file' and `output_file' are distinct files.\n\n";
195 std::cerr <<
"Examples:\n";
196 std::cerr <<
"\tlzw_v2.exe -c license.txt license.lzw\n";
197 std::cerr <<
"\tlzw_v2.exe -d license.lzw new_license.txt\n";
200 std::cerr << std::endl;
210 int main(
int argc,
char *argv[])
225 if (std::string(argv[1]) ==
"-c")
228 if (std::string(argv[1]) ==
"-d")
229 m = Mode::Decompress;
232 print_usage(std::string(
"flag `") + argv[1] +
"' is not recognized.");
236 const std::size_t buffer_size {1024 * 1024};
239 const std::unique_ptr<char[]> input_buffer(
new char[buffer_size]);
240 const std::unique_ptr<char[]> output_buffer(
new char[buffer_size]);
242 std::ifstream input_file;
243 std::ofstream output_file;
245 input_file.rdbuf()->pubsetbuf(input_buffer.get(), buffer_size);
246 input_file.open(argv[2], std::ios_base::binary);
248 if (!input_file.is_open())
250 print_usage(std::string(
"input_file `") + argv[2] +
"' could not be opened.");
254 output_file.rdbuf()->pubsetbuf(output_buffer.get(), buffer_size);
255 output_file.open(argv[3], std::ios_base::binary);
257 if (!output_file.is_open())
259 print_usage(std::string(
"output_file `") + argv[3] +
"' could not be opened.");
265 input_file.exceptions(std::ios_base::badbit);
266 output_file.exceptions(std::ios_base::badbit | std::ios_base::failbit);
268 if (m == Mode::Compress)
271 if (m == Mode::Decompress)
274 catch (
const std::ios_base::failure &f)
276 print_usage(std::string(
"File input/output failure: ") + f.what() +
'.',
false);
279 catch (
const std::exception &e)
281 print_usage(std::string(
"Caught exception: ") + e.what() +
'.',
false);