| OpenMS 2.5.0

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-2020.
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>
46 #include <OpenMS/CONCEPT/Exception.h>
47 #include <OpenMS/DATASTRUCTURES/String.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 {
78 BYTEORDER_BIGENDIAN,
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
155 union Reinterpreter64_
156 {
157 double f;
158 UInt64 i;
159 };
160
162 union Reinterpreter32_
163 {
164 float f;
165 UInt32 i;
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
223 if ((OPENMS_IS_BIG_ENDIAN && to_byte_order == Base64::BYTEORDER_LITTLEENDIAN) || (!OPENMS_IS_BIG_ENDIAN && to_byte_order == Base64::BYTEORDER_BIGENDIAN))
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 == "") 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
538 if ((OPENMS_IS_BIG_ENDIAN && to_byte_order == Base64::BYTEORDER_LITTLEENDIAN) || (!OPENMS_IS_BIG_ENDIAN && to_byte_order == Base64::BYTEORDER_BIGENDIAN))
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 == "")
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
OpenMS::UInt32
OPENMS_UINT32_TYPE UInt32
Unsigned integer type (32bit)
Definition: Types.h:63
OpenMS::Base64::encoder_
static const char encoder_[]
Definition: Base64.h:168
OpenMS::String
A more convenient string class.
Definition: String.h:58
OpenMS::Base64::decodeIntegersCompressed_
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
OpenMS::Base64::decodeUncompressed_
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
OpenMS::UInt64
OPENMS_UINT64_TYPE UInt64
Unsigned integer type (64bit)
Definition: Types.h:77
OpenMS::Byte
OPENMS_BYTE_TYPE Byte
Byte type.
Definition: Types.h:111
OpenMS::Base64::encode
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
OpenMS::endianize32
UInt32 endianize32(const UInt32 &n)
Endianizes a 32 bit type from big endian to little endian and vice versa.
Definition: Base64.h:188
OpenMS::Base64::Reinterpreter32_::f
float f
Definition: Base64.h:164
Exception.h
OpenMS::Base64::decoder_
static const char decoder_[]
Definition: Base64.h:169
OpenMS::Base64::Reinterpreter64_
Internal class needed for type-punning.
Definition: Base64.h:155
OpenMS::Base64::Reinterpreter32_
Internal class needed for type-punning.
Definition: Base64.h:162
OpenMS::Base64::Reinterpreter32_::i
UInt32 i
Definition: Base64.h:165
OpenMS::Int32
OPENMS_INT32_TYPE Int32
Signed integer type (32bit)
Definition: Types.h:56
Types.h
OpenMS::Base64::decode
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
OpenMS::endianize64
UInt64 endianize64(const UInt64 &n)
Endianizes a 64 bit type from big endian to little endian and vice versa.
Definition: Base64.h:197
OpenMS::Base64::Reinterpreter64_::f
double f
Definition: Base64.h:157
OpenMS::Base64::decodeIntegersUncompressed_
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
OPENMS_IS_BIG_ENDIAN
#define OPENMS_IS_BIG_ENDIAN
Definition: Base64.h:41
String.h
OpenMS::Base64
Class to encode and decode Base64.
Definition: Base64.h:67
OpenMS
Main OpenMS namespace.
Definition: FeatureDeconvolution.h:46
OpenMS::Base64::encodeIntegers
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
OpenMS::Base64::decodeCompressed_
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
OpenMS::UInt
unsigned int UInt
Unsigned integer type.
Definition: Types.h:94
OpenMS::Base64::BYTEORDER_LITTLEENDIAN
Little endian type.
Definition: Base64.h:79
OpenMS::Base64::ByteOrder
ByteOrder
Byte order type.
Definition: Base64.h:76
OpenMS::Base64::BYTEORDER_BIGENDIAN
Big endian type.
Definition: Base64.h:78
OpenMS::Base64::Reinterpreter64_::i
UInt64 i
Definition: Base64.h:158
int
OpenMS::Exception::ConversionError
Invalid conversion exception.
Definition: Exception.h:362
OpenMS::Int64
OPENMS_INT64_TYPE Int64
Signed integer type (64bit)
Definition: Types.h:70
OpenMS::Base64::decodeIntegers
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
OpenMS::Size
size_t Size
Size type e.g. used as variable which can hold result of size()
Definition: Types.h:127
OpenMS::Exception::OutOfMemory
Out of memory exception.
Definition: Exception.h:471