Fabcoin Core  0.16.2
P2P Digital Currency
main.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #include <clocale>
23 #include <fstream>
24 #include <iostream>
25 #include <boost/algorithm/string.hpp>
26 #include <boost/filesystem.hpp>
28 #include <libdevcore/CommonIO.h>
29 #include <libdevcore/RLP.h>
30 #include <libdevcore/SHA3.h>
31 #include <libdevcrypto/Common.h>
32 #include <libdevcrypto/CryptoPP.h>
33 using namespace std;
34 using namespace dev;
35 namespace js = json_spirit;
36 
37 void help()
38 {
39  cout
40  << "Usage rlp <mode> [OPTIONS]" << endl
41  << "Modes:" << endl
42  << " create <json> Given a simplified JSON string, output the RLP." << endl
43  << " render [ <file> | -- ] Render the given RLP. Options:" << endl
44  << " --indent <string> Use string as the level indentation (default ' ')." << endl
45  << " --hex-ints Render integers in hex." << endl
46  << " --string-ints Render integers in the same way as strings." << endl
47  << " --ascii-strings Render data as C-style strings or hex depending on content being ASCII." << endl
48  << " --force-string Force all data to be rendered as C-style strings." << endl
49  << " --force-escape When rendering as C-style strings, force all characters to be escaped." << endl
50  << " --force-hex Force all data to be rendered as raw hex." << endl
51  << " list [ <file> | -- ] List the items in the RLP list by hash and size." << endl
52  << " extract [ <file> | -- ] Extract all items in the RLP list, named by hash." << endl
53  << " assemble [ <manifest> | <base path> ] <file> ... Given a manifest & files, output the RLP." << endl
54  << " -D,--dapp Dapp-building mode; equivalent to --encrypt --64." << endl
55  << endl
56  << "General options:" << endl
57  << " -e,--encrypt Encrypt the RLP data prior to output." << endl
58  << " -L,--lenience Try not to bomb out early if possible." << endl
59  << " -x,--hex,--base-16 Treat input RLP as hex encoded data." << endl
60  << " -k,--keccak Output Keccak-256 hash only." << endl
61  << " --64,--base-64 Treat input RLP as base-64 encoded data." << endl
62  << " -b,--bin,--base-256 Treat input RLP as raw binary data." << endl
63  << " -q,--quiet Don't place additional information on stderr." << endl
64  << " -h,--help Print this help message and exit." << endl
65  << " -V,--version Show the version and exit." << endl
66  ;
67  exit(0);
68 }
69 
70 void version()
71 {
72  cout << "rlp version " << dev::Version << endl;
73  exit(0);
74 }
75 
76 /*
77 The equivalent of setlocale(LC_ALL, ā€œCā€) is called before any user code is run.
78 If the user has an invalid environment setting then it is possible for the call
79 to set locale to fail, so there are only two possible actions, the first is to
80 throw a runtime exception and cause the program to quit (default behaviour),
81 or the second is to modify the environment to something sensible (least
82 surprising behaviour).
83 
84 The follow code produces the least surprising behaviour. It will use the user
85 specified default locale if it is valid, and if not then it will modify the
86 environment the process is running in to use a sensible default. This also means
87 that users do not need to install language packs for their OS.
88 */
90 {
91 #if __unix__
92  if (!std::setlocale(LC_ALL, ""))
93  {
94  setenv("LC_ALL", "C", 1);
95  }
96 #endif
97 }
98 
99 enum class Mode {
101  ListArchive,
103  Render,
104  Create
105 };
106 
107 enum class Encoding {
108  Auto,
109  Hex,
110  Base64,
111  Binary,
112  Keccak,
113 };
114 
115 bool isAscii(string const& _s)
116 {
117  // Always hex-encode anything beginning with 0x to avoid ambiguity.
118  if (_s.size() >= 2 && _s.substr(0, 2) == "0x")
119  return false;
120 
121  for (char c: _s)
122  if (c < 32)
123  return false;
124  return true;
125 }
126 
128 {
129 public:
130  struct Prefs
131  {
132  string indent;
133  bool hexInts = false;
134  bool stringInts = true;
135  bool hexPrefix = true;
136  bool forceString = false;
137  bool escapeAll = false;
138  bool forceHex = true;
139  };
140 
141  RLPStreamer(ostream& _out, Prefs _p): m_out(_out), m_prefs(_p) {}
142 
143  void output(RLP const& _d, unsigned _level = 0)
144  {
145  if (_d.isNull())
146  m_out << "null";
147  else if (_d.isInt() && !m_prefs.stringInts)
148  if (m_prefs.hexInts)
149  m_out << (m_prefs.hexPrefix ? "0x" : "") << toHex(toCompactBigEndian(_d.toInt<bigint>(RLP::LaissezFaire), 1), 1);
150  else
151  m_out << _d.toInt<bigint>(RLP::LaissezFaire);
152  else if (_d.isData() || (_d.isInt() && m_prefs.stringInts))
153  if (m_prefs.forceString || (!m_prefs.forceHex && isAscii(_d.toString())))
154  m_out << escaped(_d.toString(), m_prefs.escapeAll);
155  else
156  m_out << "\"" << (m_prefs.hexPrefix ? "0x" : "") << toHex(_d.toBytes()) << "\"";
157  else if (_d.isList())
158  {
159  m_out << "[";
160  string newline = "\n";
161  for (unsigned i = 0; i < _level + 1; ++i)
162  newline += m_prefs.indent;
163  int j = 0;
164  for (auto i: _d)
165  {
166  m_out << (j++ ?
167  (m_prefs.indent.empty() ? ", " : ("," + newline)) :
168  (m_prefs.indent.empty() ? " " : newline));
169  output(i, _level + 1);
170  }
171  newline = newline.substr(0, newline.size() - m_prefs.indent.size());
172  m_out << (m_prefs.indent.empty() ? (j ? " ]" : "]") : (j ? newline + "]" : "]"));
173  }
174  }
175 
176 private:
177  std::ostream& m_out;
179 };
180 
181 void putOut(bytes _out, Encoding _encoding, bool _encrypt, bool _quiet)
182 {
183  dev::h256 h = dev::sha3(_out);
184  if (_encrypt)
185  crypto::Secp256k1PP::get()->encrypt(toPublic(Secret(h)), _out);
186  if (!_quiet)
187  cerr << "Keccak of RLP: " << h.hex() << endl;
188 
189  switch (_encoding)
190  {
191  case Encoding::Hex: case Encoding::Auto:
192  cout << toHex(_out) << endl;
193  break;
194  case Encoding::Base64:
195  cout << toBase64(&_out) << endl;
196  break;
197  case Encoding::Binary:
198  cout.write((char const*)_out.data(), _out.size());
199  break;
200  case Encoding::Keccak:
201  cout << sha3(_out).hex() << endl;
202  break;
203  }
204 }
205 
206 int main(int argc, char** argv)
207 {
209  Encoding encoding = Encoding::Auto;
211  string inputFile;
212  strings otherInputs;
213  bool lenience = false;
214  bool quiet = false;
215  bool encrypt = false;
216  RLPStreamer::Prefs prefs;
217 
218  for (int i = 1; i < argc; ++i)
219  {
220  string arg = argv[i];
221  if (arg == "-h" || arg == "--help")
222  help();
223  else if (arg == "render")
224  mode = Mode::Render;
225  else if (arg == "create")
226  mode = Mode::Create;
227  else if ((arg == "-i" || arg == "--indent") && i + 1 < argc)
228  prefs.indent = argv[++i];
229  else if (arg == "--hex-ints")
230  prefs.hexInts = true;
231  else if (arg == "--string-ints")
232  prefs.stringInts = true;
233  else if (arg == "--ascii-strings")
234  prefs.forceString = prefs.forceHex = false;
235  else if (arg == "--force-string")
236  prefs.forceString = true;
237  else if (arg == "--force-hex")
238  prefs.forceHex = true, prefs.forceString = false;
239  else if (arg == "--force-escape")
240  prefs.escapeAll = true;
241  else if (arg == "-n" || arg == "--nice")
242  prefs.forceString = true, prefs.stringInts = false, prefs.forceHex = false, prefs.indent = " ";
243  else if (arg == "list")
244  mode = Mode::ListArchive;
245  else if (arg == "extract")
246  mode = Mode::ExtractArchive;
247  else if (arg == "assemble")
248  mode = Mode::AssembleArchive;
249  else if (arg == "-L" || arg == "--lenience")
250  lenience = true;
251  else if (arg == "-D" || arg == "--dapp")
252  encrypt = true, encoding = Encoding::Base64;
253  else if (arg == "-V" || arg == "--version")
254  version();
255  else if (arg == "-q" || arg == "--quiet")
256  quiet = true;
257  else if (arg == "-x" || arg == "--hex" || arg == "--base-16")
258  encoding = Encoding::Hex;
259  else if (arg == "-k" || arg == "--keccak")
260  encoding = Encoding::Keccak;
261  else if (arg == "--64" || arg == "--base-64")
262  encoding = Encoding::Base64;
263  else if (arg == "-b" || arg == "--bin" || arg == "--base-256")
264  encoding = Encoding::Binary;
265  else if (arg == "-e" || arg == "--encrypt")
266  encrypt = true;
267  else if (inputFile.empty())
268  inputFile = arg;
269  else
270  otherInputs.push_back(arg);
271  }
272 
273  bytes in;
274  if (inputFile == "--")
275  for (int i = cin.get(); i != -1; i = cin.get())
276  in.push_back((byte)i);
277  else if (boost::filesystem::is_regular_file(inputFile))
278  in = contents(inputFile);
279  else
280  in = asBytes(inputFile);
281 
282  bytes b;
283 
284  if (mode != Mode::Create && mode != Mode::AssembleArchive)
285  {
286  if (encoding == Encoding::Auto)
287  {
288  encoding = Encoding::Hex;
289  for (char b: in)
290  if (b != '\n' && b != ' ' && b != '\t')
291  {
292  if (encoding == Encoding::Hex && (b < '0' || b > '9' ) && (b < 'a' || b > 'f' ) && (b < 'A' || b > 'F' ))
293  {
294 // cerr << "'" << b << "':" << (int)b << endl;
295  encoding = Encoding::Base64;
296  }
297  if (encoding == Encoding::Base64 && (b < '0' || b > '9' ) && (b < 'a' || b > 'z' ) && (b < 'A' || b > 'Z' ) && b != '+' && b != '/')
298  {
299  encoding = Encoding::Binary;
300  break;
301  }
302  }
303  }
304  switch (encoding)
305  {
306  case Encoding::Hex:
307  {
308  string s = asString(in);
309  boost::algorithm::replace_all(s, " ", "");
310  boost::algorithm::replace_all(s, "\n", "");
311  boost::algorithm::replace_all(s, "\t", "");
312  b = fromHex(s);
313  break;
314  }
315  case Encoding::Base64:
316  {
317  string s = asString(in);
318  boost::algorithm::replace_all(s, " ", "");
319  boost::algorithm::replace_all(s, "\n", "");
320  boost::algorithm::replace_all(s, "\t", "");
321  b = fromBase64(s);
322  break;
323  }
324  default:
325  swap(b, in);
326  break;
327  }
328  }
329 
330  try
331  {
332  RLP rlp(b);
333  switch (mode)
334  {
335  case Mode::ListArchive:
336  {
337  if (!rlp.isList())
338  {
339  cout << "Error: Invalid format; RLP data is not a list." << endl;
340  exit(1);
341  }
342  cout << rlp.itemCount() << " items:" << endl;
343  for (auto i: rlp)
344  {
345  if (!i.isData())
346  {
347  cout << "Error: Invalid format; RLP list item is not data." << endl;
348  if (!lenience)
349  exit(1);
350  }
351  cout << " " << i.size() << " bytes: " << sha3(i.data()) << endl;
352  }
353  break;
354  }
356  {
357  if (!rlp.isList())
358  {
359  cout << "Error: Invalid format; RLP data is not a list." << endl;
360  exit(1);
361  }
362  cout << rlp.itemCount() << " items:" << endl;
363  for (auto i: rlp)
364  {
365  if (!i.isData())
366  {
367  cout << "Error: Invalid format; RLP list item is not data." << endl;
368  if (!lenience)
369  exit(1);
370  }
371  ofstream fout;
372  fout.open(toString(sha3(i.data())));
373  fout.write(reinterpret_cast<char const*>(i.data().data()), i.data().size());
374  }
375  break;
376  }
378  {
379  if (boost::filesystem::is_directory(inputFile))
380  {
381  js::mArray entries;
382  auto basePath = boost::filesystem::canonical(boost::filesystem::path(inputFile)).string();
383  for (string& i: otherInputs)
384  {
385  js::mObject entry;
386  strings parsed;
387  boost::algorithm::split(parsed, i, boost::is_any_of(","));
388  i = parsed[0];
389  for (unsigned j = 1; j < parsed.size(); ++j)
390  {
391  strings nv;
392  boost::algorithm::split(nv, parsed[j], boost::is_any_of(":"));
393  if (nv.size() == 2)
394  entry[nv[0]] = nv[1];
395  else{} // TODO: error
396  }
397  if (!entry.count("path"))
398  {
399  std::string path = boost::filesystem::canonical(boost::filesystem::path(parsed[0])).string().substr(basePath.size());
400  if (path == "/index.html")
401  path = "/";
402  entry["path"] = path;
403  }
404  entry["hash"] = toHex(dev::sha3(contents(parsed[0])).ref());
405  entries.push_back(entry);
406  }
407  js::mObject o;
408  o["entries"] = entries;
409  auto os = js::write_string(js::mValue(o), false);
410  in = asBytes(os);
411  }
412 
413  strings addedInputs;
414  for (auto i: otherInputs)
415  if (!boost::filesystem::is_regular_file(i))
416  cerr << "Skipped " << i << std::endl;
417  else
418  addedInputs.push_back(i);
419 
420  RLPStream r(addedInputs.size() + 1);
421  r.append(in);
422  for (auto i: addedInputs)
423  r.append(contents(i));
424  putOut(r.out(), encoding, encrypt, quiet);
425  break;
426  }
427  case Mode::Render:
428  {
429  RLPStreamer s(cout, prefs);
430  s.output(rlp);
431  cout << endl;
432  break;
433  }
434  case Mode::Create:
435  {
436  vector<js::mValue> v(1);
437  try {
438  js::read_string(asString(in), v[0]);
439  }
440  catch (...)
441  {
442  cerr << "Error: Invalid format; bad JSON." << endl;
443  exit(1);
444  }
445  RLPStream out;
446  while (!v.empty())
447  {
448  auto vb = v.back();
449  v.pop_back();
450  switch (vb.type())
451  {
452  case js::array_type:
453  {
454  js::mArray a = vb.get_array();
455  out.appendList(a.size());
456  for (int i = a.size() - 1; i >= 0; --i)
457  v.push_back(a[i]);
458  break;
459  }
460  case js::str_type:
461  {
462  string const& s = vb.get_str();
463  if (s.size() >= 2 && s.substr(0, 2) == "0x")
464  out << fromHex(s);
465  else
466  {
467  // assume it's a normal JS escaped string.
468  bytes ss;
469  ss.reserve(s.size());
470  for (unsigned i = 0; i < s.size(); ++i)
471  if (s[i] == '\\' && i + 1 < s.size())
472  {
473  if (s[++i] == 'x' && i + 2 < s.size())
474  ss.push_back(fromHex(s.substr(i, 2))[0]);
475  }
476  else if (s[i] != '\\')
477  ss.push_back((byte)s[i]);
478  out << ss;
479  }
480  break;
481  }
482  case js::int_type:
483  out << vb.get_int();
484  break;
485  default:
486  cerr << "ERROR: Unsupported type in JSON." << endl;
487  if (!lenience)
488  exit(1);
489  }
490  }
491  putOut(out.out(), encoding, encrypt, quiet);
492  break;
493  }
494  default:;
495  }
496  }
497  catch (...)
498  {
499  cerr << "Error: Invalid format; bad RLP." << endl;
500  exit(1);
501  }
502 
503  return 0;
504 }
Encoding
Definition: main.cpp:107
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void help()
Definition: main.cpp:39
std::string toHex(T const &_data, int _w=2, HexPrefix _prefix=HexPrefix::DontAdd)
Definition: CommonData.h:54
bool isNull() const
No value.
Definition: RLP.h:103
uint8_t byte
Definition: Common.h:57
vector_ref< _T const > ref(_T const &_t)
Definition: vector_ref.h:115
bool isInt() const
Integer value. Must not have a leading zero.
Definition: RLP.cpp:132
void swap(dev::eth::Watch &_a, dev::eth::Watch &_b)
Definition: Interface.h:284
bool isList() const
List value.
Definition: RLP.h:112
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
Definition: RLP.h:467
size_t itemCount() const
Definition: RLP.h:118
RLPStream & append(unsigned _s)
Append given datum to the byte stream.
Definition: RLP.h:395
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<>> bigint
Definition: Common.h:121
#define h(i)
Definition: sha.cpp:736
bytes const & out() const
Read the byte stream.
Definition: RLP.h:433
evm_mode mode
Definition: SmartVM.cpp:47
SecureFixedHash< 32 > Secret
Definition: Common.h:35
#define c(i)
for(size_t i=trim;i< len;i++) hash[i-trim]
std::vector< std::string > strings
Definition: Common.h:147
std::hash for asio::adress
Definition: Common.h:323
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
bool isData() const
String value.
Definition: RLP.h:109
void version()
Definition: main.cpp:53
std::string escaped(std::string const &_s, bool _all=true)
Escapes a string into the C-string representation.
Definition: CommonData.cpp:60
void putOut(bytes _out, Encoding _encoding, bool _encrypt, bool _quiet)
Definition: main.cpp:181
Public toPublic(Secret const &_secret)
Convert a secret key into the public key equivalent.
Definition: Common.cpp:67
#define a(i)
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:99
bool read_string(const String_type &s, Value_type &value)
void setDefaultOrCLocale()
Definition: main.cpp:72
mConfig::Array_type mArray
int main(int argc, char **argv)
Definition: main.cpp:149
RLPStreamer(ostream &_out, Prefs _p)
Definition: main.cpp:141
std::vector< byte > bytes
Definition: Common.h:75
bytes toCompactBigEndian(T _val, unsigned _min=0)
Convenience function for toBigEndian.
Definition: CommonData.h:141
bool isAscii(string const &_s)
Definition: main.cpp:115
RLPStream & appendList(size_t _items)
Appends a list.
Definition: RLP.cpp:276
bytes asBytes(std::string const &_b)
Converts a string to a byte array containing the string&#39;s (byte) data.
Definition: CommonData.h:92
Keccak message digest base class.
Definition: keccak.h:41
#define b(i, j)
std::string toBase64(bytesConstRef _in)
Definition: Base64.cpp:49
mConfig::Object_type mObject
Prefs m_prefs
Definition: main.cpp:178
Value_type::String_type write_string(const Value_type &value, bool pretty)
void encrypt(Public const &_k, bytesConstRef _plain, bytes &o_cipher)
Encrypts plain text using Public key.
Definition: Common.cpp:102
bytes fromBase64(std::string const &_in)
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
std::string toString(int _flags=LaissezFaire) const
Converts to string.
Definition: RLP.h:199
char const * Version
Definition: Common.cpp:36
std::ostream & m_out
Definition: main.cpp:177
Mode
Definition: main.cpp:82
_T toInt(int _flags=Strict) const
Converts to int of type given; if isString(), decodes as big-endian bytestream.
Definition: RLP.h:275
Class for writing to an RLP bytestream.
Definition: RLP.h:383
bytes contents(std::string const &_file)
Retrieve and returns the contents of the given file.
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
std::string asString(bytes const &_b)
Converts byte array to a string containing the same (binary) data.
Definition: CommonData.h:79
bytes toBytes(int _flags=LaissezFaire) const
Converts to bytearray.
Definition: RLP.h:195
void output(RLP const &_d, unsigned _level=0)
Definition: main.cpp:143
std::string hex() const
Definition: FixedHash.h:130