Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTASCIIArmor.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTASCIIArmor.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "stdafx.hpp"
134 
135 #include "crypto/OTASCIIArmor.hpp"
136 #include "crypto/OTCrypto.hpp"
137 #include "crypto/OTEnvelope.hpp"
138 #include "OTLog.hpp"
139 #include "OTStorage.hpp"
140 
141 #include <fstream>
142 
143 #include <zlib.h>
144 
145 namespace opentxs
146 {
147 
148 const char* OT_BEGIN_ARMORED = "-----BEGIN OT ARMORED";
149 const char* OT_END_ARMORED = "-----END OT ARMORED";
150 
151 const char* OT_BEGIN_ARMORED_escaped = "- -----BEGIN OT ARMORED";
152 const char* OT_END_ARMORED_escaped = "- -----END OT ARMORED";
153 
154 const char* OT_BEGIN_SIGNED = "-----BEGIN SIGNED";
155 const char* OT_BEGIN_SIGNED_escaped = "- -----BEGIN SIGNED";
156 
157 std::unique_ptr<OTDB::OTPacker> OTASCIIArmor::s_pPacker;
158 
160 {
161  if (nullptr ==
162  s_pPacker) { // WARNING: Do not change OTDB_DEFAULT_PACKER below
163  // unless you also change SetAndPackData() since it
164  // ASSUMES this.
165  s_pPacker.reset(OTDB::OTPacker::Create(
166  OTDB_DEFAULT_PACKER)); // Protobuf is the only one that works on all
167  // platforms right now.
168  OT_ASSERT(nullptr != s_pPacker);
169  }
170 
171  return s_pPacker.get();
172 }
173 
174 // Let's say you don't know if the input string is raw base64, or if it has
175 // bookends
176 // on it like -----BEGIN BLAH BLAH ...
177 // And if it DOES have Bookends, you don't know if they are escaped: -
178 // -----BEGIN ...
179 // Let's say you just want an easy function that will figure that crap out, and
180 // load the
181 // contents up properly into an OTASCIIArmor object. (That's what this function
182 // will do.)
183 //
184 // str_bookend is a default.
185 // So you could make it more specific like, -----BEGIN ENCRYPTED KEY (or
186 // whatever.)
187 //
188 // static
190  const OTString& strInput,
191  std::string str_bookend)
192 {
193 
194  if (strInput.Contains(str_bookend)) // YES there are bookends around this.
195  {
196  const std::string str_escaped("- " + str_bookend);
197 
198  const bool bEscaped = strInput.Contains(str_escaped);
199 
200  OTString strLoadFrom(strInput);
201 
202  if (!ascArmor.LoadFromString(strLoadFrom, bEscaped)) // removes the
203  // bookends so we
204  // have JUST the
205  // coded part.
206  {
207  // otErr << "%s: Failure loading string into OTASCIIArmor
208  // object:\n\n%s\n\n",
209  // __FUNCTION__, strInput.Get());
210  return false;
211  }
212  }
213  else
214  ascArmor.Set(strInput.Get());
215 
216  return true;
217 }
218 
219 // initializes blank.
221  : OTString()
222 {
223 }
224 
225 // encodes
227  : OTString(/*Don't pass here, since we're encoding.*/)
228 {
229  SetString(strValue);
230 }
231 
232 // encodes
234  : OTString()
235 {
236  SetData(theValue);
237 }
238 
239 // encodes
241  : OTString()
242 {
243  SetData(theValue);
244 }
245 
246 // Copies (already encoded)
248  : OTString(dynamic_cast<const OTString&>(strValue))
249 {
250 }
251 
252 // assumes envelope contains encrypted data;
253 // grabs that data in base64-form onto *this.
255  : OTString()
256 {
257  theEnvelope.GetAsciiArmoredData(*this);
258 }
259 
260 // copies (already encoded)
261 OTASCIIArmor::OTASCIIArmor(const char* szValue)
262  : OTString(szValue)
263 {
264 }
265 
266 // copies, assumes already encoded.
268 {
269  Set(szValue);
270  return *this;
271 }
272 
273 // encodes
275 {
276  if ((&strValue) != (&(dynamic_cast<const OTString&>(*this)))) {
277  SetString(strValue);
278  }
279  return *this;
280 }
281 
282 // encodes
284 {
285  SetData(theValue);
286  return *this;
287 }
288 
289 // assumes is already encoded and just copies the encoded text
291 {
292  if ((&strValue) != this) // prevent self-assignment
293  {
294  OTString::operator=(dynamic_cast<const OTString&>(strValue));
295  }
296  return *this;
297 }
298 
299 // Source for these two functions: http://panthema.net/2007/0328-ZLibString.html
300 
303 std::string compress_string(const std::string& str,
304  int32_t compressionlevel = Z_BEST_COMPRESSION)
305 {
306  z_stream zs; // z_stream is zlib's control structure
307  memset(&zs, 0, sizeof(zs));
308 
309  if (deflateInit(&zs, compressionlevel) != Z_OK)
310  throw(std::runtime_error("deflateInit failed while compressing."));
311 
312  zs.next_in = (Bytef*)str.data();
313  zs.avail_in = static_cast<uInt>(str.size()); // set the z_stream's input
314 
315  int32_t ret;
316  char outbuffer[32768];
317  std::string outstring;
318 
319  // retrieve the compressed bytes blockwise
320  do {
321  zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
322  zs.avail_out = sizeof(outbuffer);
323 
324  ret = deflate(&zs, Z_FINISH);
325 
326  if (outstring.size() < zs.total_out) {
327  // append the block to the output string
328  outstring.append(outbuffer, zs.total_out - outstring.size());
329  }
330  } while (ret == Z_OK);
331 
332  deflateEnd(&zs);
333 
334  if (ret != Z_STREAM_END) { // an error occurred that was not EOF
335  std::ostringstream oss;
336  oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
337  throw(std::runtime_error(oss.str()));
338  }
339 
340  return outstring;
341 }
342 
344 std::string decompress_string(const std::string& str)
345 {
346  z_stream zs; // z_stream is zlib's control structure
347  memset(&zs, 0, sizeof(zs));
348 
349  if (inflateInit(&zs) != Z_OK)
350  throw(std::runtime_error("inflateInit failed while decompressing."));
351 
352  zs.next_in = (Bytef*)str.data();
353  zs.avail_in = static_cast<uInt>(str.size());
354 
355  int32_t ret;
356  char outbuffer[32768];
357  std::string outstring;
358 
359  // get the decompressed bytes blockwise using repeated calls to inflate
360  do {
361  zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
362  zs.avail_out = sizeof(outbuffer);
363 
364  ret = inflate(&zs, 0);
365 
366  if (outstring.size() < zs.total_out) {
367  outstring.append(outbuffer, zs.total_out - outstring.size());
368  }
369 
370  } while (ret == Z_OK);
371 
372  inflateEnd(&zs);
373 
374  if (ret != Z_STREAM_END) { // an error occurred that was not EOF
375  std::ostringstream oss;
376  oss << "Exception during zlib decompression: (" << ret << ")";
377  if (zs.msg != nullptr) {
378  oss << " " << zs.msg;
379  }
380  throw(std::runtime_error(oss.str()));
381  }
382 
383  return outstring;
384 }
385 
397 //
399  OTString& strData, bool bLineBreaks) const // bLineBreaks=true
400 {
401  size_t outSize = 0;
402  uint8_t* pData = nullptr;
403 
404  strData.Release();
405 
406  if (GetLength() < 1) {
407  return true;
408  }
409 
410  pData = OTCrypto::It()->Base64Decode(Get(), &outSize, bLineBreaks);
411  // pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0));
412 
413  if (pData) {
414 
415  std::string str_decoded(pData, pData + outSize);
416 
417  delete[] pData;
418  pData = nullptr;
419 
420  std::string str_uncompressed = "";
421  try {
422  str_uncompressed = decompress_string(str_decoded);
423  }
424  catch (const std::runtime_error&) {
425  otErr << "Failed decompressing string in "
426  "OTASCIIArmor::GetAndUnpackString.\n";
427  return false;
428  }
429 
430  // PUT THE PACKED BUFFER HERE, AND UNPACK INTO strData
431 
432  OTDB::OTPacker* pPacker =
433  OTASCIIArmor::GetPacker(); // No need to check for failure, since
434  // this already ASSERTS. No need to
435  // cleanup either.
436 
437  std::unique_ptr<OTDB::PackedBuffer> pBuffer(pPacker->CreateBuffer());
438  OT_ASSERT(nullptr != pBuffer);
439 
440  pBuffer->SetData(
441  reinterpret_cast<const uint8_t*>(str_uncompressed.data()),
442  str_uncompressed.size());
443 
444  std::unique_ptr<OTDB::OTDBString> pOTDBString(
445  dynamic_cast<OTDB::OTDBString*>(
447  OT_ASSERT(nullptr != pOTDBString);
448 
449  bool bUnpacked = pPacker->Unpack(*pBuffer, *pOTDBString);
450 
451  if (!bUnpacked) {
452  otErr << "Failed unpacking string in "
453  "OTASCIIArmor::GetAndUnpackString.\n";
454 
455  return false;
456  }
457 
458  // This enforces the null termination. (using the 2nd parameter as
459  // nEnforcedMaxLength)
460  strData.Set(pOTDBString->m_string.c_str(),
461  static_cast<uint32_t>(pOTDBString->m_string.length()));
462 
463  return true;
464  }
465  else {
466  otErr << "OTASCIIArmor::GetAndUnpackString: nullptr pData while "
467  "base64-decoding pData.\n";
468  return false;
469  }
470 }
471 
472 // If adding packing STILL didn't make us binary compatible, then I need to try
473 // this next:
474 // Do the compression, THEN PACK...
475 // On the other way, UNPACK, THEN Uncompress.
476 //
477 // Right now I'm doing packing before compression, and unpacking after
478 // uncompression.
479 // Basically if that doesn't work (even though zlib appears to care about
480 // endian/platform)
481 // then switch the, (though that seems to make less logical sense to me.)
482 // Maybe have to pack before both? Seems crazy.
483 
485  bool bLineBreaks) const // bLineBreaks=true
486 {
487  return GetAndUnpackString(strData, bLineBreaks);
488 }
489 
490 bool OTASCIIArmor::GetStringMap(std::map<std::string, std::string>& the_map,
491  bool bLineBreaks) const
492 {
493  return GetAndUnpackStringMap(the_map, bLineBreaks);
494 }
495 
497  std::map<std::string, std::string>& the_map, bool bLineBreaks) const
498 {
499  size_t outSize = 0;
500  uint8_t* pData = nullptr;
501 
502  the_map.clear();
503 
504  if (GetLength() < 1) return true;
505 
506  pData = OTCrypto::It()->Base64Decode(Get(), &outSize, bLineBreaks);
507 
508  if (pData) {
509 
510  OTDB::OTPacker* pPacker =
511  OTASCIIArmor::GetPacker(); // No need to check for failure, since
512  // this already ASSERTS. No need to
513  // cleanup either.
514 
515  std::unique_ptr<OTDB::PackedBuffer> pBuffer(
516  pPacker->CreateBuffer()); // Need to clean this up.
517  OT_ASSERT(nullptr != pBuffer);
518 
519  pBuffer->SetData(static_cast<const uint8_t*>(pData), outSize);
520  delete[] pData;
521  pData = nullptr;
522 
523  std::unique_ptr<OTDB::StringMap> pStringMap(
524  dynamic_cast<OTDB::StringMap*>(
526  OT_ASSERT(nullptr != pStringMap);
527 
528  bool bUnpacked = pPacker->Unpack(*pBuffer, *pStringMap);
529 
530  if (!bUnpacked) {
531  otErr << "Failed unpacking data in "
532  "OTASCIIArmor::GetAndUnpackStringMap.\n";
533  delete[] pData;
534  pData = nullptr;
535  return false;
536  }
537 
538  the_map = pStringMap->the_map;
539 
540  delete[] pData;
541  pData = nullptr;
542  return true;
543  }
544  else {
545  otErr << "Error while base64_decoding in "
546  "OTASCIIArmor::GetAndUnpackStringMap.\n";
547  return false;
548  }
549 }
550 
552  const std::map<std::string, std::string>& the_map, bool bLineBreaks)
553 {
554  return SetAndPackStringMap(the_map, bLineBreaks);
555 }
556 
558  const std::map<std::string, std::string>& the_map, bool bLineBreaks)
559 {
560  char* pString = nullptr;
561 
562  Release();
563 
564  if (the_map.empty()) return true;
565 
566  OTDB::OTPacker* pPacker =
567  OTASCIIArmor::GetPacker(); // No need to check for failure, since this
568  // already ASSERTS. No need to cleanup
569  // either.
570 
571  // Here I use the default storage context to create the object (the string
572  // map.)
573  // I also originally created OTASCIIArmor::GetPacker() using
574  // OTDB_DEFAULT_PACKER,
575  // so I know everything is compatible.
576  //
577  std::unique_ptr<OTDB::StringMap> pStringMap(dynamic_cast<OTDB::StringMap*>(
579 
580  OT_ASSERT(nullptr !=
581  pStringMap); // Beyond this point, responsible to delete
582  // pStringMap.
583 
584  pStringMap->the_map = the_map;
585 
586  std::unique_ptr<OTDB::PackedBuffer> pBuffer(pPacker->Pack(
587  *pStringMap)); // Now we PACK our data before compressing/encoding it.
588 
589  if (nullptr == pBuffer) {
590  otErr << "Failed packing data in OTASCIIArmor::SetAndPackStringMap. \n";
591  return false;
592  }
593 
594  const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData());
595  const size_t theSize = pBuffer->GetSize();
596 
597  if (nullptr != pUint)
598  pString = OTCrypto::It()->Base64Encode(
599  pUint, static_cast<int32_t>(theSize), bLineBreaks);
600  // pString = OT_base64_encode(pUint, static_cast<int32_t> (theSize),
601  // (bLineBreaks ? 1 : 0));
602  else {
603  otErr << "Error while base64_encoding in "
604  "OTASCIIArmor::SetAndPackStringMap.\n";
605  return false;
606  }
607 
608  if (nullptr != pString) {
609  Set(pString);
610  delete[] pString;
611  pString = nullptr;
612  return true;
613  }
614  else {
615  otErr << "Error while base64_encoding in "
616  "OTASCIIArmor::SetAndPackStringMap.\n";
617  return false;
618  }
619 }
620 
621 // This function will base64 DECODE the string contents
622 // and return them as binary in theData
624  bool bLineBreaks) const // linebreaks=true
625 {
626  return GetAndUnpackData(theData, bLineBreaks);
627 }
628 
629 // This function will base64 DECODE the string contents
630 // and return them as binary in theData
631 // Additionally it will decompress and unpack the data!
632 //
634  bool bLineBreaks) const // linebreaks=true
635 {
636  size_t outSize = 0;
637  uint8_t* pData = nullptr;
638 
639  theData.Release();
640 
641  if (GetLength() < 1) return true;
642 
643  pData = OTCrypto::It()->Base64Decode(Get(), &outSize, bLineBreaks);
644  // pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0));
645 
646  if (pData) {
647 
648  OTDB::OTPacker* pPacker =
649  OTASCIIArmor::GetPacker(); // No need to check for failure, since
650  // this already ASSERTS. No need to
651  // cleanup either.
652 
653  std::unique_ptr<OTDB::PackedBuffer> pBuffer(pPacker->CreateBuffer());
654  OT_ASSERT(nullptr != pBuffer);
655 
656  pBuffer->SetData(static_cast<const uint8_t*>(pData), outSize);
657  delete[] pData;
658  pData = nullptr;
659 
660  std::unique_ptr<OTDB::Blob> pBlob(dynamic_cast<OTDB::Blob*>(
662  OT_ASSERT(nullptr != pBlob);
663 
664  bool bUnpacked = pPacker->Unpack(*pBuffer, *pBlob);
665 
666  if (!bUnpacked) {
667  otErr
668  << "Failed unpacking data in OTASCIIArmor::GetAndUnpackData.\n";
669  delete[] pData;
670  pData = nullptr;
671  return false;
672  }
673 
674  theData.Assign(pBlob->m_memBuffer.data(),
675  static_cast<uint32_t>(pBlob->m_memBuffer.size()));
676  delete[] pData;
677  pData = nullptr;
678  return true;
679  }
680  else {
681  otErr << "Error while base64_decoding in "
682  "OTASCIIArmor::GetAndUnpackData.\n";
683  return false;
684  }
685 }
686 
687 // This function will base64 ENCODE theData,
688 // and then Set() that as the string contents.
689 bool OTASCIIArmor::SetData(const OTData& theData, bool bLineBreaks)
690 {
691  return SetAndPackData(theData, bLineBreaks);
692 }
693 
694 // This function will base64 ENCODE theData,
695 // and then Set() that as the string contents.
696 // Additionally it will pack and compress the data!
697 //
698 bool OTASCIIArmor::SetAndPackData(const OTData& theData, bool bLineBreaks)
699 {
700  char* pString = nullptr;
701 
702  Release();
703 
704  if (theData.GetSize() < 1) return true;
705 
706  OTDB::OTPacker* pPacker =
707  OTASCIIArmor::GetPacker(); // No need to check for failure, since this
708  // already ASSERTS. No need to cleanup
709  // either.
710 
711  // Here I use the default storage context to create the object (the blob.)
712  // I also originally created OTASCIIArmor::GetPacker() using
713  // OTDB_DEFAULT_PACKER,
714  // so I know everything is compatible.
715  //
716  std::unique_ptr<OTDB::Blob> pBlob(
717  dynamic_cast<OTDB::Blob*>(OTDB::CreateObject(OTDB::STORED_OBJ_BLOB)));
718 
719  OT_ASSERT(nullptr !=
720  pBlob); // Beyond this point, responsible to delete pBlob.
721 
722  pBlob->m_memBuffer.assign(
723  static_cast<const uint8_t*>(theData.GetPointer()),
724  static_cast<const uint8_t*>(theData.GetPointer()) + theData.GetSize());
725 
726  std::unique_ptr<OTDB::PackedBuffer> pBuffer(pPacker->Pack(
727  *pBlob)); // Now we PACK our data before compressing/encoding it.
728 
729  if (nullptr == pBuffer) {
730  otErr << "Failed packing data in OTASCIIArmor::SetAndPackData. \n";
731  return false;
732  }
733 
734  const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData());
735  const size_t theSize = pBuffer->GetSize();
736 
737  if (nullptr != pUint)
738  pString = OTCrypto::It()->Base64Encode(
739  pUint, static_cast<int32_t>(theSize), bLineBreaks);
740  // pString = OT_base64_encode(pUint, static_cast<int32_t> (theSize),
741  // (bLineBreaks ? 1 : 0));
742  else {
743  otErr
744  << "Error while base64_encoding in OTASCIIArmor::SetAndPackData.\n";
745  return false;
746  }
747 
748  if (nullptr != pString) {
749  Set(pString);
750  delete[] pString;
751  pString = nullptr;
752  return true;
753  }
754  else {
755  otErr
756  << "Error while base64_encoding in OTASCIIArmor::SetAndPackData.\n";
757  return false;
758  }
759 }
760 
771 //
773  bool bLineBreaks) //=true
774 {
775  Release();
776 
777  if (strData.GetLength() < 1) return true;
778 
779  OTDB::OTPacker* pPacker =
780  OTASCIIArmor::GetPacker(); // No need to check for failure, since this
781  // already ASSERTS. No need to cleanup
782  // either.
783 
784  // Here I use the default storage context to create the object (the blob.)
785  // I also originally created OTASCIIArmor::GetPacker() using
786  // OTDB_DEFAULT_PACKER,
787  // so I know everything is compatible.
788  //
789  std::unique_ptr<OTDB::OTDBString> pOTDBString(
790  dynamic_cast<OTDB::OTDBString*>(
792 
793  OT_ASSERT(nullptr != pOTDBString);
794 
795  const uint32_t theStringSize32 = strData.GetLength();
796  const size_t theStringSize =
797  theStringSize32; // might need a cast here. // todo make sure this will
798  // handle sizes as big as I need.
799 
800  pOTDBString->m_string.assign(strData.Get(), // const char *
801  theStringSize);
802 
803  std::unique_ptr<OTDB::PackedBuffer> pBuffer(
804  pPacker->Pack(*pOTDBString)); // Now we PACK our string before
805  // compressing/encoding it.
806 
807  if (nullptr == pBuffer) {
808  otErr << "Failed packing string in OTASCIIArmor::SetAndPackString. \n";
809  return false;
810  }
811 
812  std::string str_packed(reinterpret_cast<const char*>(pBuffer->GetData()),
813  pBuffer->GetSize());
814 
815  std::string str_compressed = compress_string(str_packed);
816 
817  // Success
818  if (str_compressed.size()) {
819  // Now let's base-64 encode it...
820  // TODO: remove static cast, add check for longer than 'int32_t' length?
821  // (da2ce7)
822  char* pString = OTCrypto::It()->Base64Encode(
823  (const uint8_t*)(str_compressed.data()),
824  static_cast<int32_t>(str_compressed.size()), bLineBreaks);
825 
826  if (pString) {
827  Set(pString);
828  delete[] pString;
829  pString = nullptr;
830  return true;
831  }
832  else {
833  otErr << "OTASCIIArmor::" << __FUNCTION__ << ": pString nullptr.\n";
834  }
835  }
836  else {
837  otErr << "OTASCIIArmor::" << __FUNCTION__ << ": nDestLen 0.\n";
838  }
839 
840  return false;
841 }
842 
843 // This version is fully functional, and performs compression in addition to
844 // base64-encoding.
845 //
846 bool OTASCIIArmor::SetString(const OTString& strData, bool bLineBreaks) //=true
847 {
848 
849  return SetAndPackString(strData, bLineBreaks);
850 }
851 
852 // This code reads up the file, discards the bookends, and saves only the
853 // gibberish itself.
854 bool OTASCIIArmor::LoadFromFile(const OTString& foldername,
855  const OTString& filename)
856 {
857  OT_ASSERT(foldername.Exists());
858  OT_ASSERT(filename.Exists());
859 
860  if (!OTDB::Exists(foldername.Get(), filename.Get())) {
861  otErr << "OTASCIIArmor::LoadFromFile: File does not exist: "
862  << foldername << "" << OTLog::PathSeparator() << "" << filename
863  << "\n";
864  return false;
865  }
866 
867  OTString strFileContents(OTDB::QueryPlainString(
868  foldername.Get(), filename.Get())); // <=== LOADING FROM DATA STORE.
869 
870  if (strFileContents.GetLength() < 2) {
871  otErr << "OTASCIIArmor::LoadFromFile: Error reading file: "
872  << foldername << OTLog::PathSeparator() << filename << "\n";
873  return false;
874  }
875 
876  return LoadFromString(strFileContents);
877 }
878 
879 bool OTASCIIArmor::LoadFromExactPath(const std::string& filename)
880 {
881  std::ifstream fin(filename.c_str(), std::ios::binary);
882 
883  if (!fin.is_open()) {
884  otWarn << "OTASCIIArmor::LoadFromExactPath: Failed opening file: "
885  << filename << "\n";
886  return false;
887  }
888 
889  return LoadFrom_ifstream(fin);
890 }
891 
892 // This code reads up the file, discards the bookends, and saves only the
893 // gibberish itself.
894 bool OTASCIIArmor::LoadFrom_ifstream(std::ifstream& fin)
895 {
896  std::stringstream buffer;
897  buffer << fin.rdbuf();
898 
899  std::string contents(buffer.str());
900 
901  OTString theString;
902  theString.Set(contents.c_str());
903 
904  return LoadFromString(theString);
905 }
906 
907 bool OTASCIIArmor::SaveToExactPath(const std::string& filename)
908 {
909  std::ofstream fout(filename.c_str(), std::ios::out | std::ios::binary);
910 
911  if (!fout.is_open()) {
912  otWarn << "OTASCIIArmor::SaveToExactPath: Failed opening file: "
913  << filename << "\n";
914  return false;
915  }
916 
917  return SaveTo_ofstream(fout);
918 }
919 
920 bool OTASCIIArmor::SaveTo_ofstream(std::ofstream& fout)
921 {
922  OTString strOutput;
923  std::string str_type("DATA"); // -----BEGIN OT ARMORED DATA-----
924 
925  if (WriteArmoredString(strOutput, str_type) && strOutput.Exists()) {
926  // WRITE IT TO THE FILE
927  //
928  fout << strOutput;
929 
930  if (fout.fail()) {
931  otErr << __FUNCTION__ << ": Failed saving to file.\n Contents:\n\n"
932  << strOutput << "\n\n";
933  return false;
934  }
935 
936  return true;
937  }
938 
939  return false;
940 }
941 
942 // const char * OT_BEGIN_ARMORED = "-----BEGIN OT ARMORED";
943 // const char * OT_END_ARMORED = "-----END OT ARMORED";
944 
946  const OTString& foldername, const OTString& filename,
947  const // for "-----BEGIN OT LEDGER-----", str_type would contain "LEDGER"
948  std::string str_type, // There's no default, to force you to enter the right
949  // string.
950  bool bEscaped) const
951 {
952  OT_ASSERT(foldername.Exists());
953  OT_ASSERT(filename.Exists());
954 
955  OTString strOutput;
956 
957  if (WriteArmoredString(strOutput, str_type, bEscaped) &&
958  strOutput.Exists()) {
959  // WRITE IT TO THE FILE
960  // StorePlainString will attempt to create all the folders leading up to
961  // the path
962  // for the output file.
963  //
964  bool bSaved = OTDB::StorePlainString(strOutput.Get(), foldername.Get(),
965  filename.Get());
966 
967  if (!bSaved) {
968  otErr << "OTASCIIArmor::WriteArmoredFile"
969  << ": Failed saving to file: %s%s%s\n\n Contents:\n\n"
970  << strOutput << "\n\n",
971  foldername.Get(), OTLog::PathSeparator(), filename.Get();
972  return false;
973  }
974 
975  return true;
976  }
977 
978  return false;
979 }
980 
981 // const char * OT_BEGIN_ARMORED = "-----BEGIN OT ARMORED";
982 // const char * OT_END_ARMORED = "-----END OT ARMORED";
983 
985  OTString& strOutput,
986  const // for "-----BEGIN OT LEDGER-----", str_type would contain "LEDGER"
987  std::string str_type, // There's no default, to force you to enter the right
988  // string.
989  bool bEscaped) const
990 {
991  const char* szEscape = "- ";
992 
993  OTString strTemp;
994  strTemp.Format(
995  "%s%s %s-----\n" // "%s-----BEGIN OT ARMORED %s-----\n"
996  "Version: Open Transactions %s\n"
997  "Comment: "
998  "http://github.com/FellowTraveler/Open-Transactions/wiki\n\n" // todo
999  // hardcoding.
1000  "%s" // Should already have a newline at the bottom.
1001  "%s%s %s-----\n\n", // "%s-----END OT ARMORED %s-----\n"
1002  bEscaped ? szEscape : "",
1003  OT_BEGIN_ARMORED, str_type.c_str(), // "%s%s %s-----\n"
1004  OTLog::Version(), // "Version: Open Transactions %s\n"
1005  /* No variable */ // "Comment:
1006  // http://github.com/FellowTraveler/Open-Transactions/wiki\n\n",
1007  Get(), // "%s" <==== CONTENTS OF THIS OBJECT BEING
1008  // WRITTEN...
1009  bEscaped ? szEscape : "", OT_END_ARMORED,
1010  str_type.c_str()); // "%s%s %s-----\n"
1011 
1012  strOutput.Concatenate("%s", strTemp.Get());
1013 
1014  return true;
1015 }
1016 
1017 // This code reads up the string, discards the bookends, and saves only the
1018 // gibberish itself.
1019 // the bEscaped option allows you to load a normal ASCII-Armored file if off,
1020 // and allows
1021 // you to load an escaped ASCII-armored file (such as inside the contracts when
1022 // the public keys
1023 // are escaped with a "- " before the rest of the ------- starts.)
1024 //
1026  bool bEscaped,
1027  const // This szOverride sub-string determines
1028  // where the content starts, when loading.
1029  std::string str_override) // Default is
1030  // "-----BEGIN"
1031 {
1032  // Should never be 0 size, as default is "-----BEGIN"
1033  // But if you want to load a private key, try "-----BEGIN ENCRYPTED PRIVATE"
1034  // instead.
1035  // *smile*
1036  const std::string str_end_line =
1037  "-----END"; // Someday maybe allow parameterized option for this.
1038 
1039  const int32_t nBufSize = 2100; // todo: hardcoding
1040  const int32_t nBufSize2 = 2048; // todo: hardcoding
1041 
1042  char buffer1[2100]; // todo: hardcoding
1043 
1044  std::fill(&buffer1[0], &buffer1[(nBufSize - 1)], 0); // Initializing to 0.
1045 
1046  bool bContentMode = false; // "Currently IN content mode."
1047  bool bHaveEnteredContentMode =
1048  false; // "Have NOT YET entered content mode."
1049 
1050  // Clear out whatever string might have been in there before.
1051  Release();
1052 
1053  // Load up the string from theStr,
1054  // (bookended by "-----BEGIN ... -----" and "END-----" messages)
1055  bool bIsEOF = false;
1056  theStr.reset(); // So we can call theStr.sgets(). Making sure position is at
1057  // start of string.
1058 
1059  do {
1060  bIsEOF = !(theStr.sgets(buffer1, nBufSize2)); // 2048
1061 
1062  std::string line = buffer1;
1063  const char* pConstBuf = line.c_str();
1064  char* pBuf = (char*)pConstBuf;
1065 
1066  // It's not a blank line.
1067  if (line.length() < 2) {
1068  continue;
1069  }
1070 
1071  // if we're on a dashed line...
1072  else if (line.at(0) == '-' && line.at(2) == '-' && line.at(3) == '-' &&
1073  (bEscaped ? (line.at(1) == ' ') : (line.at(1) == '-'))) {
1074  // If I just hit a dash, that means there are only two options:
1075 
1076  // a. I have not yet entered content mode, and potentially just now
1077  // entering it for the first time.
1078  if (!bHaveEnteredContentMode) {
1079  // str_override defaults to: "-----BEGIN" (If you want to load
1080  // a private key instead,
1081  // Try passing "-----BEGIN ENCRYPTED PRIVATE" instead of going
1082  // with the default.)
1083  //
1084  if (line.find(str_override) != std::string::npos &&
1085  line.at(0) == '-' && line.at(2) == '-' &&
1086  line.at(3) == '-' &&
1087  (bEscaped ? (line.at(1) == ' ') : (line.at(1) == '-'))) {
1088  // otErr << "Reading ascii-armored
1089  // contents...";
1090  bHaveEnteredContentMode = true;
1091  bContentMode = true;
1092  continue;
1093  }
1094  else {
1095  continue;
1096  }
1097  }
1098 
1099  // b. I am now LEAVING content mode!
1100  else if (bContentMode &&
1101  // str_end_line is "-----END"
1102  (line.find(str_end_line) != std::string::npos)) {
1103  // otErr << "Finished reading ascii-armored
1104  // contents.\n";
1105  // otErr << "Finished reading ascii-armored
1106  // contents:\n%s(END DATA)\n", Get());
1107  bContentMode = false;
1108  continue;
1109  }
1110  }
1111 
1112  // Else we're on a normal line, not a dashed line.
1113  else {
1114  if (bHaveEnteredContentMode && bContentMode) {
1115  if (line.compare(0, 8, "Version:") == 0) {
1116  // otErr << "Skipping version line...\n";
1117  continue;
1118  }
1119  if (line.compare(0, 8, "Comment:") == 0) {
1120  // otErr << "Skipping comment line...\n";
1121  continue;
1122  }
1123  }
1124  }
1125 
1126  // Here we save the line to member variables, if appropriate
1127  if (bContentMode) {
1128  Concatenate("%s\n", pBuf);
1129  }
1130  } while (!bIsEOF && (bContentMode || !bHaveEnteredContentMode));
1131 
1132  // reset the string position back to 0
1133  theStr.reset();
1134 
1135  if (!bHaveEnteredContentMode) {
1136  otErr << "Error in OTASCIIArmor::LoadFromString: EOF before "
1137  "ascii-armored "
1138  "content found, in:\n\n" << theStr << "\n\n";
1139  return false;
1140  }
1141  else if (bContentMode) {
1142  otErr
1143  << "Error in OTASCIIArmor::LoadFromString: EOF while still reading "
1144  "content, in:\n\n" << theStr << "\n\n";
1145  return false;
1146  }
1147  else
1148  return true;
1149 }
1150 
1152 {
1153  // ~OTString called automatically, which calls Release().
1154 }
1155 
1156 } // namespace opentxs
static EXPORT OTCrypto * It()
Definition: OTCrypto.cpp:630
EXPORT OTString & operator=(OTString rhs)
Definition: OTString.cpp:1011
EXPORT bool StorePlainString(std::string strContents, std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:698
EXPORT Storable * CreateObject(StoredObjectType eType)
Definition: OTStorage.cpp:530
EXPORT bool LoadFromExactPath(const std::string &filename)
EXPORT bool Unpack(PackedBuffer &inBuf, Storable &outObj)
Definition: OTStorage.cpp:972
EXPORT bool SetAndPackString(const OTString &theData, bool bLineBreaks=true)
const char * OT_BEGIN_ARMORED_escaped
PackedBuffer * Pack(Storable &inObj)
Definition: OTStorage.cpp:930
const char * OT_BEGIN_SIGNED_escaped
std::vector< uint8_t > m_memBuffer
Definition: OTStorage.hpp:956
EXPORT bool GetAndUnpackStringMap(std::map< std::string, std::string > &the_map, bool bLineBreaks=true) const
virtual EXPORT ~OTASCIIArmor()
#define OTDB_DEFAULT_PACKER
Definition: OTStorage.hpp:167
const char * OT_END_ARMORED
EXPORT bool GetStringMap(std::map< std::string, std::string > &the_map, bool bLineBreaks=true) const
static EXPORT const char * PathSeparator()
Definition: OTLog.cpp:408
std::string compress_string(const std::string &str, int32_t compressionlevel=Z_BEST_COMPRESSION)
const char * OT_END_ARMORED_escaped
EXPORT uint32_t GetLength() const
Definition: OTString.cpp:1040
EXPORT void Concatenate(const char *arg,...)
Definition: OTString.cpp:1334
EXPORT bool WriteArmoredString(OTString &strOutput, const std::string str_type, bool bEscaped=false) const
EXPORT bool Exists() const
Definition: OTString.cpp:1035
EXPORT bool SetString(const OTString &theData, bool bLineBreaks=true)
static EXPORT bool LoadFromString(OTASCIIArmor &ascArmor, const OTString &strInput, std::string str_bookend="-----BEGIN")
EXPORT bool LoadFromFile(const OTString &foldername, const OTString &filename)
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
EXPORT bool SaveToExactPath(const std::string &filename)
EXPORT bool SetAndPackData(const OTData &theData, bool bLineBreaks=true)
static EXPORT const char * Version()
Definition: OTLog.cpp:399
std::string decompress_string(const std::string &str)
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
EXPORT OTASCIIArmor & operator=(const char *szValue)
EXPORT std::string QueryPlainString(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:728
EXPORT bool SaveTo_ofstream(std::ofstream &fout)
EXPORT bool GetAsciiArmoredData(OTASCIIArmor &theArmoredText, bool bLineBreaks=true) const
Definition: OTEnvelope.cpp:162
bool sgets(char *buffer, uint32_t size)
Definition: OTString.cpp:1380
EXPORT bool GetAndUnpackData(OTData &theData, bool bLineBreaks=true) const
const char * OT_BEGIN_SIGNED
#define OT_ASSERT(x)
Definition: Assert.hpp:150
virtual bool Base64Encode(const OTData &theInput, OTString &strOutput, bool bLineBreaks=true) const
Definition: OTCrypto.cpp:710
static OTPacker * Create(PackType ePackType)
Definition: OTStorage.cpp:889
EXPORT bool LoadFrom_ifstream(std::ifstream &fin)
static OTDB::OTPacker * GetPacker()
EXPORT bool GetData(OTData &theData, bool bLineBreaks=true) const
OTLOG_IMPORT OTLogStream otWarn
EXPORT bool WriteArmoredFile(const OTString &foldername, const OTString &filename, const std::string str_type, bool bEscaped=false) const
EXPORT const char * Get() const
Definition: OTString.cpp:1045
OTLOG_IMPORT OTLogStream otErr
const void * GetPointer() const
Definition: OTData.hpp:162
virtual PackedBuffer * CreateBuffer()=0
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
Definition: OTStorage.cpp:584
virtual bool Base64Decode(const OTString &strInput, OTData &theOutput, bool bLineBreaks=true) const
Definition: OTCrypto.cpp:740
EXPORT bool Contains(const char *compare) const
Definition: OTString.cpp:1137
EXPORT bool SetData(const OTData &theData, bool bLineBreaks=true)
EXPORT bool GetString(OTString &theData, bool bLineBreaks=true) const
EXPORT bool SetStringMap(const std::map< std::string, std::string > &the_map, bool bLineBreaks=true)
virtual EXPORT void Release()
Definition: OTString.cpp:765
uint32_t GetSize() const
Definition: OTData.hpp:174
EXPORT bool GetAndUnpackString(OTString &theData, bool bLineBreaks=true) const
const char * OT_BEGIN_ARMORED
EXPORT bool SetAndPackStringMap(const std::map< std::string, std::string > &the_map, bool bLineBreaks=true)