shred.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #include <iostream>
  2. #include <sstream>
  3. #include <string>
  4. #include <deque>
  5. #include <map>
  6. #include <functional>
  7. #include <algorithm>
  8. #include "simple/file.hpp"
  9. #include "simple/file/string_stack.h"
  10. #include "simple/support/enum.hpp"
  11. #include "simple/support/misc.hpp"
  12. using namespace std;
  13. using namespace std::literals;
  14. using namespace simple;
  15. using namespace file::operators;
  16. using file::string_stack::pop;
  17. using file::string_stack::drop;
  18. using file::string_stack::push;
  19. using string_stack = file::string_stack::manipulator;
  20. static const string info_ext = "info"s;
  21. static const string piece_ext = "piece"s;
  22. static const string ext_delim = "."s;
  23. static constexpr file::size_type default_piece_size = 256 * 1024;
  24. enum class Options
  25. {
  26. PieceSize,
  27. Terminator,
  28. Invalid
  29. };
  30. using Option = support::mapped_enum<Options, Options::Invalid, 2>;
  31. template <> Option::guts::map_type Option::guts::map
  32. {{
  33. { "-s"s, "--size"s },
  34. { "--"s, "--files"s }
  35. }};
  36. string to_hex_string(int n)
  37. {
  38. stringstream s;
  39. s << hex << n;
  40. return s.str();
  41. }
  42. // why use bind when got lambdas? hmm?
  43. using namespace placeholders;
  44. auto popext = bind(pop, _1, ext_delim);
  45. auto pushext = bind(push, _1, _2, ext_delim);
  46. auto dropext = bind(drop, _1, ext_delim);
  47. // // well there are your lambdas... like em?
  48. // auto popext = [&](auto& _1){ return pop(_1, ext_delim); };
  49. // auto pushext = [&](auto& _1, auto& _2){ push(_1, _2, ext_delim); };
  50. // auto dropext = [&](auto& _1){ drop(_1, ext_delim); };
  51. void shred(string path, file::size_type piece_size = default_piece_size)
  52. {
  53. auto victim = file::bropex(path);
  54. auto victim_size = file::size(victim);
  55. string name = pop(path);
  56. string ext = popext(name); // TODO: separating the extension is ugly and problematic
  57. if(name.empty())
  58. swap(name, ext);
  59. push(path, name);
  60. pushext(path, info_ext);
  61. auto info = file::wopex(path);
  62. drop(path);
  63. { auto extension = string_stack(name, ext_delim).push(ext);
  64. info << name << '\n'
  65. << victim_size << '\n';
  66. }
  67. file::buffer_type piece;
  68. for(int i = 1; victim_size; ++i, victim_size -= piece.size())
  69. {
  70. auto name_stack = string_stack(name, ext_delim).push(to_hex_string(i), piece_ext);
  71. auto path_stack = string_stack(path).push(name);
  72. piece.resize(min(victim_size, piece_size));
  73. victim.read(piece.data(), piece.size());
  74. file::bwopex(path) <<= piece;
  75. info << name << '\n';
  76. }
  77. }
  78. void process_arguments(deque<string> args)
  79. {
  80. args.pop_front();
  81. auto piece_size = default_piece_size;
  82. while(!args.empty())
  83. {
  84. switch(Option(args.front()))
  85. {
  86. case Options::PieceSize:
  87. args.pop_front();
  88. if(args.empty())
  89. return;
  90. piece_size = support::ston<file::size_type>(args.front());
  91. break;
  92. case Options::Terminator:
  93. args.pop_front();
  94. for(auto& arg : args)
  95. shred(arg, piece_size);
  96. return;
  97. default:
  98. shred(args.front(), piece_size);
  99. break;
  100. }
  101. args.pop_front();
  102. }
  103. }
  104. void process_input()
  105. {
  106. auto piece_size = default_piece_size;
  107. string input;
  108. while(getline(cin, input))
  109. {
  110. piece_size = std::strtoull(input.c_str(), nullptr, 0);
  111. piece_size = piece_size ? piece_size : default_piece_size;
  112. while(getline(cin, input) && !input.empty())
  113. shred(input, piece_size);
  114. }
  115. }
  116. int main(int argc, char const * argv[]) try
  117. {
  118. process_arguments( {argv, argv + argc} );
  119. if(argc < 2)
  120. process_input();
  121. return 0;
  122. }
  123. catch(...)
  124. {
  125. if(errno)
  126. std::perror("Oh nooo!");
  127. throw;
  128. }