OpenMS
Base64.h
Go to the documentation of this file.
1 // --------------------------------------------------------------------------
2 // OpenMS -- Open-Source Mass Spectrometry
3 // --------------------------------------------------------------------------
4 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
5 // ETH Zurich, and Freie Universitaet Berlin 2002-2023.
6 //
7 // This software is released under a three-clause BSD license:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of any author or any participating institution
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 // For a full list of authors, refer to the file AUTHORS.
17 // --------------------------------------------------------------------------
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
22 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // --------------------------------------------------------------------------
31 // $Maintainer: Timo Sachsenberg $
32 // $Authors: Marc Sturm $
33 // --------------------------------------------------------------------------
34 
35 #pragma once
36 
37 #ifndef OPENMS_IS_BIG_ENDIAN
38 #if defined OPENMS_BIG_ENDIAN
39 #define OPENMS_IS_BIG_ENDIAN true
40 #else
41 #define OPENMS_IS_BIG_ENDIAN false
42 #endif
43 #endif
44 
45 #include <OpenMS/CONCEPT/Types.h>
48 #include <algorithm>
49 #include <iterator>
50 #include <cmath>
51 #include <vector>
52 
53 #include <QByteArray>
54 #include <zlib.h>
55 
56 #ifdef OPENMS_COMPILER_MSVC
57 #pragma comment(linker, "/export:compress")
58 #endif
59 
60 namespace OpenMS
61 {
67  class OPENMS_DLLAPI Base64
68  {
69 
70 public:
71 
73  Base64() = default;
74 
76  enum ByteOrder
77  {
79  BYTEORDER_LITTLEENDIAN
80  };
81 
89  template <typename FromType>
90  static void encode(std::vector<FromType> & in, ByteOrder to_byte_order, String & out, bool zlib_compression = false);
91 
97  template <typename ToType>
98  static void decode(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out, bool zlib_compression = false);
99 
107  template <typename FromType>
108  static void encodeIntegers(std::vector<FromType> & in, ByteOrder to_byte_order, String & out, bool zlib_compression = false);
109 
115  template <typename ToType>
116  static void decodeIntegers(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out, bool zlib_compression = false);
117 
130  static void encodeStrings(const std::vector<String> & in, String & out, bool zlib_compression = false, bool append_null_byte = true);
131 
141  static void decodeStrings(const String & in, std::vector<String> & out, bool zlib_compression = false);
142 
150  static void decodeSingleString(const String& in, QByteArray& base64_uncompressed, bool zlib_compression);
151 
152 private:
153 
156  {
157  double f;
159  };
160 
163  {
164  float f;
166  };
167 
168  static const char encoder_[];
169  static const char decoder_[];
171  template <typename ToType>
172  static void decodeUncompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out);
173 
175  template <typename ToType>
176  static void decodeCompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out);
177 
179  template <typename ToType>
180  static void decodeIntegersUncompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out);
181 
183  template <typename ToType>
184  static void decodeIntegersCompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out);
185  };
186 
188  inline UInt32 endianize32(const UInt32& n)
189  {
190  return ((n & 0x000000ff) << 24) |
191  ((n & 0x0000ff00) << 8) |
192  ((n & 0x00ff0000) >> 8) |
193  ((n & 0xff000000) >> 24);
194  }
195 
197  inline UInt64 endianize64(const UInt64& n)
198  {
199  return ((n >> 56) & 0x00000000000000FF) |
200  ((n >> 40) & 0x000000000000FF00) |
201  ((n >> 24) & 0x0000000000FF0000) |
202  ((n >> 8) & 0x00000000FF000000) |
203  ((n << 8) & 0x000000FF00000000) |
204  ((n << 24) & 0x0000FF0000000000) |
205  ((n << 40) & 0x00FF000000000000) |
206  ((n << 56) & 0xFF00000000000000);
207  }
208 
209  template <typename FromType>
210  void Base64::encode(std::vector<FromType> & in, ByteOrder to_byte_order, String & out, bool zlib_compression)
211  {
212  out.clear();
213  if (in.empty())
214  return;
215 
216  //initialize
217  const Size element_size = sizeof(FromType);
218  const Size input_bytes = element_size * in.size();
219  String compressed;
220  Byte * it;
221  Byte * end;
222  //Change endianness if necessary
224  {
225  if (element_size == 4)
226  {
227  for (Size i = 0; i < in.size(); ++i)
228  {
229  Reinterpreter32_ tmp;
230  tmp.f = in[i];
231  tmp.i = endianize32(tmp.i);
232  in[i] = tmp.f;
233  }
234  }
235  else
236  {
237  for (Size i = 0; i < in.size(); ++i)
238  {
239  Reinterpreter64_ tmp;
240  tmp.f = static_cast<double>(in[i]);
241  tmp.i = endianize64(tmp.i);
242  in[i] = tmp.f;
243  }
244  }
245  }
246 
247  //encode with compression
248  if (zlib_compression)
249  {
250  unsigned long sourceLen = (unsigned long)in.size();
251  unsigned long compressed_length = //compressBound((unsigned long)in.size());
252  sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; // taken from zlib's compress.c, as we cannot use compressBound*
253  //
254  // (*) compressBound is not defined in the QtCore lib, which forces the linker under windows to link in our zlib.
255  // This leads to multiply defined symbols as compress() is then defined twice.
256 
257  int zlib_error;
258  do
259  {
260  compressed.resize(compressed_length);
261  zlib_error = compress(reinterpret_cast<Bytef *>(&compressed[0]), &compressed_length, reinterpret_cast<Bytef *>(&in[0]), (unsigned long)input_bytes);
262 
263  switch (zlib_error)
264  {
265  case Z_MEM_ERROR:
266  throw Exception::OutOfMemory(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, compressed_length);
267  break;
268 
269  case Z_BUF_ERROR:
270  compressed_length *= 2;
271  }
272  }
273  while (zlib_error == Z_BUF_ERROR);
274 
275  if (zlib_error != Z_OK)
276  {
277  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Compression error?");
278  }
279 
280  String(compressed).swap(compressed);
281  it = reinterpret_cast<Byte *>(&compressed[0]);
282  end = it + compressed_length;
283  out.resize((Size)ceil(compressed_length / 3.) * 4); //resize output array in order to have enough space for all characters
284  }
285  //encode without compression
286  else
287  {
288  out.resize((Size)ceil(input_bytes / 3.) * 4); //resize output array in order to have enough space for all characters
289  it = reinterpret_cast<Byte *>(&in[0]);
290  end = it + input_bytes;
291  }
292 
293  Byte * to = reinterpret_cast<Byte *>(&out[0]);
294 
295 
296  Size written = 0;
297 
298  while (it != end)
299  {
300  Int int_24bit = 0;
301  Int padding_count = 0;
302 
303  // construct 24-bit integer from 3 bytes
304  for (Size i = 0; i < 3; i++)
305  {
306  if (it != end)
307  {
308  int_24bit |= *it++ << ((2 - i) * 8);
309  }
310  else
311  {
312  padding_count++;
313  }
314  }
315 
316  // write out 4 characters
317  for (Int i = 3; i >= 0; i--)
318  {
319  to[i] = encoder_[int_24bit & 0x3F];
320  int_24bit >>= 6;
321  }
322 
323  // fixup for padding
324  if (padding_count > 0)
325  to[3] = '=';
326  if (padding_count > 1)
327  to[2] = '=';
328 
329  to += 4;
330  written += 4;
331  }
332 
333  out.resize(written); //no more space is needed
334  }
335 
336  template <typename ToType>
337  void Base64::decode(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out, bool zlib_compression)
338  {
339  if (zlib_compression)
340  {
341  decodeCompressed_(in, from_byte_order, out);
342  }
343  else
344  {
345  decodeUncompressed_(in, from_byte_order, out);
346  }
347  }
348 
349  template <typename ToType>
350  void Base64::decodeCompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out)
351  {
352  out.clear();
353  if (in.empty()) return;
354 
355  const Size element_size = sizeof(ToType);
356 
357  String decompressed;
358 
359  QByteArray qt_byte_array = QByteArray::fromRawData(in.c_str(), (int) in.size());
360  QByteArray bazip = QByteArray::fromBase64(qt_byte_array);
361  QByteArray czip;
362  czip.resize(4);
363  czip[0] = (bazip.size() & 0xff000000) >> 24;
364  czip[1] = (bazip.size() & 0x00ff0000) >> 16;
365  czip[2] = (bazip.size() & 0x0000ff00) >> 8;
366  czip[3] = (bazip.size() & 0x000000ff);
367  czip += bazip;
368  QByteArray base64_uncompressed = qUncompress(czip);
369 
370  if (base64_uncompressed.isEmpty())
371  {
372  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Decompression error?");
373  }
374  decompressed.resize(base64_uncompressed.size());
375 
376  std::copy(base64_uncompressed.begin(), base64_uncompressed.end(), decompressed.begin());
377 
378  void* byte_buffer = reinterpret_cast<void *>(&decompressed[0]);
379  Size buffer_size = decompressed.size();
380 
381  const ToType * float_buffer = reinterpret_cast<const ToType *>(byte_buffer);
382  if (buffer_size % element_size != 0)
383  {
384  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Bad BufferCount?");
385  }
386 
387  Size float_count = buffer_size / element_size;
388 
389  // change endianness if necessary
390  if ((OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_LITTLEENDIAN) || (!OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_BIGENDIAN))
391  {
392  if (element_size == 4) // 32 bit
393  {
394  UInt32 * p = reinterpret_cast<UInt32 *>(byte_buffer);
395  std::transform(p, p + float_count, p, endianize32);
396  }
397  else // 64 bit
398  {
399  UInt64 * p = reinterpret_cast<UInt64 *>(byte_buffer);
400  std::transform(p, p + float_count, p, endianize64);
401  }
402  }
403 
404  // copy values
405  out.assign(float_buffer, float_buffer + float_count);
406  }
407 
408  template <typename ToType>
409  void Base64::decodeUncompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out)
410  {
411  out.clear();
412 
413  // The length of a base64 string is a always a multiple of 4 (always 3
414  // bytes are encoded as 4 characters)
415  if (in.size() < 4)
416  {
417  return;
418  }
419  if (in.size() % 4 != 0)
420  {
421  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Malformed base64 input, length is not a multiple of 4.");
422  }
423 
424  Size src_size = in.size();
425  // last one or two '=' are skipped if contained
426  int padding = 0;
427  if (in[src_size - 1] == '=') padding++;
428  if (in[src_size - 2] == '=') padding++;
429 
430  src_size -= padding;
431 
432  UInt a;
433  UInt b;
434 
435  UInt offset = 0;
436  int inc = 1;
437  UInt written = 0;
438 
439  const Size element_size = sizeof(ToType);
440 
441  // enough for either float or double
442  char element[8] = "\x00\x00\x00\x00\x00\x00\x00";
443 
444  // Parse little endian data in big endian OpenMS (or other way round)
445  if ((OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_LITTLEENDIAN) ||
446  (!OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_BIGENDIAN))
447  {
448  offset = (element_size - 1); // other endian
449  inc = -1;
450  }
451  else
452  {
453  offset = 0;
454  inc = 1;
455  }
456 
457  //reserve enough space in the output vector
458  out.reserve((UInt)(std::ceil((4.0 * src_size) / 3.0) + 6.0));
459 
460  // sort all read bytes correctly into a char[4] (double) or
461  // char[8] (float) and push_back when necessary.
462  for (Size i = 0; i < src_size; i += 4)
463  {
464  // decode 4 Base64-Chars to 3 Byte
465  // -------------------------------
466 
467  // decode the first two chars
468  a = decoder_[(int)in[i] - 43] - 62;
469  b = decoder_[(int)in[i + 1] - 43] - 62;
470  if (i + 1 >= src_size)
471  {
472  b = 0;
473  }
474  // write first byte (6 bits from a and 2 highest bits from b)
475  element[offset] = (unsigned char) ((a << 2) | (b >> 4));
476  written++;
477  offset = (offset + inc) % element_size;
478 
479  if (written % element_size == 0)
480  {
481  ToType * to_type = reinterpret_cast<ToType *>(&element[0]);
482  out.push_back((*to_type));
483  strcpy(element, "");
484  }
485 
486  // decode the third char
487  a = decoder_[(int)in[i + 2] - 43] - 62;
488  if (i + 2 >= src_size)
489  {
490  a = 0;
491  }
492  // write second byte (4 lowest bits from b and 4 highest bits from a)
493  element[offset] = (unsigned char) (((b & 15) << 4) | (a >> 2));
494  written++;
495  offset = (offset + inc) % element_size;
496 
497  if (written % element_size == 0)
498  {
499  ToType * to_type = reinterpret_cast<ToType *>(&element[0]);
500  out.push_back((*to_type));
501  strcpy(element, "");
502  }
503 
504  // decode the fourth char
505  b = decoder_[(int)in[i + 3] - 43] - 62;
506  if (i + 3 >= src_size)
507  {
508  b = 0;
509  }
510  // write third byte (2 lowest bits from a and 6 bits from b)
511  element[offset] = (unsigned char) (((a & 3) << 6) | b);
512  written++;
513  offset = (offset + inc) % element_size;
514 
515  if (written % element_size == 0)
516  {
517  ToType * to_type = reinterpret_cast<ToType *>(&element[0]);
518  out.push_back((*to_type));
519  strcpy(element, "");
520  }
521  }
522  }
523 
524  template <typename FromType>
525  void Base64::encodeIntegers(std::vector<FromType> & in, ByteOrder to_byte_order, String & out, bool zlib_compression)
526  {
527  out.clear();
528  if (in.empty())
529  return;
530 
531  //initialize
532  const Size element_size = sizeof(FromType);
533  const Size input_bytes = element_size * in.size();
534  String compressed;
535  Byte * it;
536  Byte * end;
537  //Change endianness if necessary
539  {
540  if (element_size == 4)
541  {
542  for (Size i = 0; i < in.size(); ++i)
543  {
544  UInt32 tmp = in[i];
545  tmp = endianize32(tmp);
546  in[i] = tmp;
547  }
548  }
549  else
550  {
551  for (Size i = 0; i < in.size(); ++i)
552  {
553  UInt64 tmp = in[i];
554  tmp = endianize64(tmp);
555  in[i] = tmp;
556  }
557  }
558  }
559 
560  //encode with compression (use Qt because of zlib support)
561  if (zlib_compression)
562  {
563  unsigned long sourceLen = (unsigned long)input_bytes;
564  unsigned long compressed_length = //compressBound((unsigned long)in.size());
565  sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; // taken from zlib's compress.c, as we cannot use compressBound*
566 
567  compressed.resize(compressed_length);
568  while (compress(reinterpret_cast<Bytef *>(&compressed[0]), &compressed_length, reinterpret_cast<Bytef *>(&in[0]), (unsigned long)input_bytes) != Z_OK)
569  {
570  compressed_length *= 2;
571  compressed.reserve(compressed_length);
572  }
573 
574 
575  String(compressed).swap(compressed);
576  it = reinterpret_cast<Byte *>(&compressed[0]);
577  end = it + compressed_length;
578  out.resize((Size)ceil(compressed_length / 3.) * 4); //resize output array in order to have enough space for all characters
579  }
580  //encode without compression
581  else
582  {
583  out.resize((Size)ceil(input_bytes / 3.) * 4); //resize output array in order to have enough space for all characters
584  it = reinterpret_cast<Byte *>(&in[0]);
585  end = it + input_bytes;
586  }
587 
588  Byte * to = reinterpret_cast<Byte *>(&out[0]);
589 
590 
591  Size written = 0;
592 
593  while (it != end)
594  {
595  Int int_24bit = 0;
596  Int padding_count = 0;
597 
598  // construct 24-bit integer from 3 bytes
599  for (Size i = 0; i < 3; i++)
600  {
601  if (it != end)
602  {
603  int_24bit |= *it++ << ((2 - i) * 8);
604  }
605  else
606  {
607  padding_count++;
608  }
609  }
610 
611  // write out 4 characters
612  for (Int i = 3; i >= 0; i--)
613  {
614  to[i] = encoder_[int_24bit & 0x3F];
615  int_24bit >>= 6;
616  }
617 
618  // fixup for padding
619  if (padding_count > 0)
620  to[3] = '=';
621  if (padding_count > 1)
622  to[2] = '=';
623 
624  to += 4;
625  written += 4;
626  }
627 
628  out.resize(written); //no more space is needed
629  }
630 
631  template <typename ToType>
632  void Base64::decodeIntegers(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out, bool zlib_compression)
633  {
634  if (zlib_compression)
635  {
636  decodeIntegersCompressed_(in, from_byte_order, out);
637  }
638  else
639  {
640  decodeIntegersUncompressed_(in, from_byte_order, out);
641  }
642  }
643 
644  template <typename ToType>
645  void Base64::decodeIntegersCompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out)
646  {
647  out.clear();
648  if (in.empty())
649  return;
650 
651  void * byte_buffer;
652  Size buffer_size;
653  const Size element_size = sizeof(ToType);
654 
655  String decompressed;
656 
657  QByteArray qt_byte_array = QByteArray::fromRawData(in.c_str(), (int) in.size());
658  QByteArray bazip = QByteArray::fromBase64(qt_byte_array);
659  QByteArray czip;
660  czip.resize(4);
661  czip[0] = (bazip.size() & 0xff000000) >> 24;
662  czip[1] = (bazip.size() & 0x00ff0000) >> 16;
663  czip[2] = (bazip.size() & 0x0000ff00) >> 8;
664  czip[3] = (bazip.size() & 0x000000ff);
665  czip += bazip;
666  QByteArray base64_uncompressed = qUncompress(czip);
667  if (base64_uncompressed.isEmpty())
668  {
669  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Decompression error?");
670  }
671  decompressed.resize(base64_uncompressed.size());
672 
673  std::copy(base64_uncompressed.begin(), base64_uncompressed.end(), decompressed.begin());
674 
675  byte_buffer = reinterpret_cast<void *>(&decompressed[0]);
676  buffer_size = decompressed.size();
677 
678  //change endianness if necessary
679  if ((OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_LITTLEENDIAN) || (!OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_BIGENDIAN))
680  {
681  if (element_size == 4)
682  {
683  const Int32 * float_buffer = reinterpret_cast<const Int32 *>(byte_buffer);
684  if (buffer_size % element_size != 0)
685  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Bad BufferCount?");
686  Size float_count = buffer_size / element_size;
687  UInt32 * p = reinterpret_cast<UInt32 *>(byte_buffer);
688  std::transform(p, p + float_count, p, endianize32);
689 
690  out.resize(float_count);
691  // do NOT use assign here, as it will give a lot of type conversion warnings on VS compiler
692  for (Size i = 0; i < float_count; ++i)
693  {
694  out[i] = (ToType) * float_buffer;
695  ++float_buffer;
696  }
697  }
698  else
699  {
700  const Int64 * float_buffer = reinterpret_cast<const Int64 *>(byte_buffer);
701 
702  if (buffer_size % element_size != 0)
703  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Bad BufferCount?");
704 
705  Size float_count = buffer_size / element_size;
706 
707  UInt64 * p = reinterpret_cast<UInt64 *>(byte_buffer);
708  std::transform(p, p + float_count, p, endianize64);
709 
710  out.resize(float_count);
711  // do NOT use assign here, as it will give a lot of type conversion warnings on VS compiler
712  for (Size i = 0; i < float_count; ++i)
713  {
714  out[i] = (ToType) * float_buffer;
715  ++float_buffer;
716  }
717  }
718  }
719  else
720  {
721  if (element_size == 4)
722  {
723  const Int * float_buffer = reinterpret_cast<const Int *>(byte_buffer);
724  if (buffer_size % element_size != 0)
725  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Bad BufferCount while decoding?");
726 
727  Size float_count = buffer_size / element_size;
728  out.resize(float_count);
729  // do NOT use assign here, as it will give a lot of type conversion warnings on VS compiler
730  for (Size i = 0; i < float_count; ++i)
731  {
732  out[i] = (ToType) * float_buffer;
733  ++float_buffer;
734  }
735  }
736  else
737  {
738  const Int64 * float_buffer = reinterpret_cast<const Int64 *>(byte_buffer);
739 
740  if (buffer_size % element_size != 0)
741  throw Exception::ConversionError(__FILE__, __LINE__, OPENMS_PRETTY_FUNCTION, "Bad BufferCount while decoding?");
742 
743  Size float_count = buffer_size / element_size;
744  out.resize(float_count);
745  // do NOT use assign here, as it will give a lot of type conversion warnings on VS compiler
746  for (Size i = 0; i < float_count; ++i)
747  {
748  out[i] = (ToType) * float_buffer;
749  ++float_buffer;
750  }
751  }
752  }
753 
754  }
755 
756  template <typename ToType>
757  void Base64::decodeIntegersUncompressed_(const String & in, ByteOrder from_byte_order, std::vector<ToType> & out)
758  {
759  out.clear();
760 
761  // The length of a base64 string is a always a multiple of 4 (always 3
762  // bytes are encoded as 4 characters)
763  if (in.size() < 4)
764  {
765  return;
766  }
767 
768  Size src_size = in.size();
769  // last one or two '=' are skipped if contained
770  int padding = 0;
771  if (in[src_size - 1] == '=') padding++;
772  if (in[src_size - 2] == '=') padding++;
773 
774  src_size -= padding;
775 
776  UInt a;
777  UInt b;
778 
779  UInt offset = 0;
780  int inc = 1;
781  UInt written = 0;
782 
783  const Size element_size = sizeof(ToType);
784 
785  // enough for either float or double
786  char element[8] = "\x00\x00\x00\x00\x00\x00\x00";
787 
788  if ((OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_LITTLEENDIAN) || (!OPENMS_IS_BIG_ENDIAN && from_byte_order == Base64::BYTEORDER_BIGENDIAN))
789  {
790  offset = (element_size - 1); // other endian
791  inc = -1;
792  }
793  else
794  {
795  offset = 0;
796  inc = 1;
797  }
798 
799  //reserve enough space in the output vector
800  out.reserve((UInt)(std::ceil((4.0 * src_size) / 3.0) + 6.0));
801 
802  // sort all read bytes correctly into a char[4] (double) or
803  // char[8] (float) and push_back when necessary.
804  for (Size i = 0; i < src_size; i += 4)
805  {
806 
807  // decode 4 Base64-Chars to 3 Byte
808  // -------------------------------
809 
810  // decode the first two chars
811  a = decoder_[(int)in[i] - 43] - 62;
812  b = decoder_[(int)in[i + 1] - 43] - 62;
813  if (i + 1 >= src_size)
814  {
815  b = 0;
816  }
817  // write first byte (6 bits from a and 2 highest bits from b)
818  element[offset] = (unsigned char) ((a << 2) | (b >> 4));
819  written++;
820  offset = (offset + inc) % element_size;
821 
822  if (written % element_size == 0)
823  {
824  ToType float_value;
825  if (element_size == 4)
826  {
827  Int32 * value = reinterpret_cast<Int32 *>(&element[0]);
828  float_value = (ToType) * value;
829  }
830  else
831  {
832  Int64 * value = reinterpret_cast<Int64 *>(&element[0]);
833  float_value = (ToType) * value;
834  }
835  out.push_back(float_value);
836  strcpy(element, "");
837  }
838 
839  // decode the third char
840  a = decoder_[(int)in[i + 2] - 43] - 62;
841  if (i + 2 >= src_size)
842  {
843  a = 0;
844  }
845  // write second byte (4 lowest bits from b and 4 highest bits from a)
846  element[offset] = (unsigned char) (((b & 15) << 4) | (a >> 2));
847  written++;
848  offset = (offset + inc) % element_size;
849 
850  if (written % element_size == 0)
851  {
852  ToType float_value;
853  if (element_size == 4)
854  {
855  Int32 * value = reinterpret_cast<Int32 *>(&element[0]);
856  float_value = (ToType) * value;
857  }
858  else
859  {
860  Int64 * value = reinterpret_cast<Int64 *>(&element[0]);
861  float_value = (ToType) * value;
862  }
863  out.push_back(float_value);
864  strcpy(element, "");
865  }
866 
867  // decode the fourth char
868  b = decoder_[(int)in[i + 3] - 43] - 62;
869  if (i + 3 >= src_size)
870  {
871  b = 0;
872  }
873  // write third byte (2 lowest bits from a and 6 bits from b)
874  element[offset] = (unsigned char) (((a & 3) << 6) | b);
875  written++;
876  offset = (offset + inc) % element_size;
877 
878  if (written % element_size == 0)
879  {
880  ToType float_value;
881  if (element_size == 4)
882  {
883  Int32 * value = reinterpret_cast<Int32 *>(&element[0]);
884  float_value = (ToType) * value;
885  }
886  else
887  {
888  Int64 * value = reinterpret_cast<Int64 *>(&element[0]);
889  float_value = (ToType) * value;
890  }
891  out.push_back(float_value);
892  strcpy(element, "");
893  }
894  }
895  }
896 
897 } //namespace OpenMS
898 
#define OPENMS_IS_BIG_ENDIAN
Definition: Base64.h:41
Class to encode and decode Base64.
Definition: Base64.h:68
static void decodeSingleString(const String &in, QByteArray &base64_uncompressed, bool zlib_compression)
Decodes a Base64 string to a QByteArray.
static void decode(const String &in, ByteOrder from_byte_order, std::vector< ToType > &out, bool zlib_compression=false)
Decodes a Base64 string to a vector of floating point numbers.
Definition: Base64.h:337
static void decodeIntegersCompressed_(const String &in, ByteOrder from_byte_order, std::vector< ToType > &out)
Decodes a compressed Base64 string to a vector of integer numbers.
Definition: Base64.h:645
double f
Definition: Base64.h:157
static const char decoder_[]
Definition: Base64.h:169
static void decodeCompressed_(const String &in, ByteOrder from_byte_order, std::vector< ToType > &out)
Decodes a compressed Base64 string to a vector of floating point numbers.
Definition: Base64.h:350
static void decodeIntegersUncompressed_(const String &in, ByteOrder from_byte_order, std::vector< ToType > &out)
Decodes a Base64 string to a vector of integer numbers.
Definition: Base64.h:757
static const char encoder_[]
Definition: Base64.h:168
static void decodeStrings(const String &in, std::vector< String > &out, bool zlib_compression=false)
Decodes a Base64 string to a vector of (null-terminated) strings.
static void decodeUncompressed_(const String &in, ByteOrder from_byte_order, std::vector< ToType > &out)
Decodes a Base64 string to a vector of floating point numbers.
Definition: Base64.h:409
Base64()=default
default constructor
static void encodeStrings(const std::vector< String > &in, String &out, bool zlib_compression=false, bool append_null_byte=true)
Encodes a vector of strings to a Base64 string.
UInt64 i
Definition: Base64.h:158
ByteOrder
Byte order type.
Definition: Base64.h:77
@ BYTEORDER_BIGENDIAN
Big endian type.
Definition: Base64.h:78
@ BYTEORDER_LITTLEENDIAN
Little endian type.
Definition: Base64.h:79
static void encode(std::vector< FromType > &in, ByteOrder to_byte_order, String &out, bool zlib_compression=false)
Encodes a vector of floating point numbers to a Base64 string.
Definition: Base64.h:210
static void decodeIntegers(const String &in, ByteOrder from_byte_order, std::vector< ToType > &out, bool zlib_compression=false)
Decodes a Base64 string to a vector of integer numbers.
Definition: Base64.h:632
UInt32 i
Definition: Base64.h:165
static void encodeIntegers(std::vector< FromType > &in, ByteOrder to_byte_order, String &out, bool zlib_compression=false)
Encodes a vector of integer point numbers to a Base64 string.
Definition: Base64.h:525
float f
Definition: Base64.h:164
Internal class needed for type-punning.
Definition: Base64.h:163
Internal class needed for type-punning.
Definition: Base64.h:156
Invalid conversion exception.
Definition: Exception.h:356
Out of memory exception.
Definition: Exception.h:461
A more convenient string class.
Definition: String.h:60
OPENMS_BYTE_TYPE Byte
Byte type.
Definition: Types.h:111
OPENMS_UINT32_TYPE UInt32
Unsigned integer type (32bit)
Definition: Types.h:63
OPENMS_UINT64_TYPE UInt64
Unsigned integer type (64bit)
Definition: Types.h:77
int Int
Signed integer type.
Definition: Types.h:102
OPENMS_INT32_TYPE Int32
Signed integer type (32bit)
Definition: Types.h:56
OPENMS_INT64_TYPE Int64
Signed integer type (64bit)
Definition: Types.h:70
unsigned int UInt
Unsigned integer type.
Definition: Types.h:94
size_t Size
Size type e.g. used as variable which can hold result of size()
Definition: Types.h:127
Main OpenMS namespace.
Definition: FeatureDeconvolution.h:48
UInt32 endianize32(const UInt32 &n)
Endianizes a 32 bit type from big endian to little endian and vice versa.
Definition: Base64.h:188
UInt64 endianize64(const UInt64 &n)
Endianizes a 64 bit type from big endian to little endian and vice versa.
Definition: Base64.h:197