Preparations for rdb image API: base64 encoder and decoder without Qt

This commit is contained in:
Matthias Koefferlein 2022-05-29 21:50:23 +02:00
parent b8fa458ad6
commit 84cf60dbb7
5 changed files with 287 additions and 0 deletions

View File

@ -10,6 +10,7 @@ FORMS =
SOURCES = \
tlAssert.cc \
tlBase64.cc \
tlClassRegistry.cc \
tlCopyOnWrite.cc \
tlDataMapping.cc \
@ -56,6 +57,7 @@ SOURCES = \
HEADERS = \
tlAlgorithm.h \
tlAssert.h \
tlBase64.h \
tlClassRegistry.h \
tlCopyOnWrite.h \
tlDataMapping.h \

139
src/tl/tl/tlBase64.cc Normal file
View File

@ -0,0 +1,139 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlBase64.h"
#include "tlException.h"
#include "tlInternational.h"
namespace tl
{
namespace {
class EncoderTable
{
public:
EncoderTable ()
{
char charset[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (unsigned int i = 0; i < 256; ++i) {
m_char2bin[i] = 0xff;
}
for (unsigned int i = 0; i < 64; ++i) {
m_bin2char[i] = charset[i];
m_char2bin[(unsigned int) charset[i]] = i;
}
}
inline char c (unsigned char b) const { return m_bin2char[b]; }
inline unsigned char b (char c) const { return m_char2bin[(unsigned char) c]; }
private:
char m_bin2char[64];
unsigned char m_char2bin[256];
};
}
static EncoderTable s_enc;
std::vector<unsigned char> from_base64 (const char *s)
{
size_t sz = 0;
for (const char *t = s; *t; ++t) {
++sz;
}
unsigned int sh = 0;
std::vector<unsigned char> data;
data.reserve ((sz * 6 + 7) / 8);
for (const char *t = s; *t; ++t) {
if ((unsigned char) *t <= ' ') {
// ignore white space characters
} else if (*t == '=') {
// padding/termination
if (data.empty () || data.back () != 0) {
throw tl::Exception (tl::to_string (tr ("Error decoding base64 data: padding character does not match zero byte")));
}
data.pop_back ();
break;
} else {
unsigned char b = s_enc.b (*t);
if (b >= 64) {
throw tl::Exception (tl::to_string (tr ("Error decoding base64 data: invalid character '%c'")), *t);
}
sh += 2;
if (sh == 8) {
data.back () |= b;
sh = 0;
} else if (sh == 2) {
data.push_back (b << 2);
} else {
data.back () |= (b >> (8 - sh));
data.push_back (b << sh);
}
}
}
return data;
}
std::string to_base64 (const unsigned char *data, size_t size)
{
std::string s;
s.reserve (((size + 2) / 3) * 4);
size_t bits = size * 8;
for (size_t b = 0; b < bits; b += 6) {
size_t bit = b % 8;
size_t byte = b / 8;
if (bit <= 2) {
s += s_enc.c ((data [byte] >> (2 - bit)) & 0x3f);
} else if (b + 8 < bits) {
s += s_enc.c (((data [byte] << (bit - 2)) | (data [byte + 1] >> (10 - bit))) & 0x3f);
} else {
s += s_enc.c ((data [byte] << (bit - 2)) & 0x3f);
s += '=';
if (bit == 6) {
s += '=';
}
}
}
return s;
}
}

47
src/tl/tl/tlBase64.h Normal file
View File

@ -0,0 +1,47 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_tlBase64
#define HDR_tlBase64
#include "tlCommon.h"
#include <string>
#include <vector>
namespace tl
{
/**
* Converts a base64-encoded string into binary data
*/
TL_PUBLIC std::vector<unsigned char> from_base64 (const char *s);
/**
* Converts binary data into a base64-encoded string
*/
TL_PUBLIC std::string to_base64 (const unsigned char *data, size_t size);
}
#endif

View File

@ -0,0 +1,98 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlBase64.h"
#include "tlUnitTest.h"
TEST(1)
{
std::vector<unsigned char> r = tl::from_base64 ("");
EXPECT_EQ (r.empty (), true);
r = tl::from_base64 ("YQ==");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "a");
r = tl::from_base64 ("YQ==");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "a");
r = tl::from_base64 ("YWI=");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "ab");
r = tl::from_base64 ("YWJj");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "abc");
r = tl::from_base64 ("YWJjZA==");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "abcd");
r = tl::from_base64 ("YWJjZA=");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "abcd");
r = tl::from_base64 ("SGVsbG8sIHdvcmxkIQo=");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "Hello, world!\n");
r = tl::from_base64 ("SGVsbG\n8sIHd \tvcmxkIQo=");
EXPECT_EQ (std::string ((const char *) r.begin ().operator-> (), r.size ()), "Hello, world!\n");
try {
r = tl::from_base64 ("YWJjZ==");
EXPECT_EQ (true, false);
} catch (tl::Exception &ex) {
EXPECT_EQ (ex.msg (), "Error decoding base64 data: padding character does not match zero byte");
}
try {
r = tl::from_base64 ("YW#jZA==");
EXPECT_EQ (true, false);
} catch (tl::Exception &ex) {
EXPECT_EQ (ex.msg (), "Error decoding base64 data: invalid character '#'");
}
}
TEST(2)
{
std::string s, r;
s = "";
r = tl::to_base64 ((const unsigned char *) s.c_str (), s.size ());
EXPECT_EQ (r, "");
s = "a";
r = tl::to_base64 ((const unsigned char *) s.c_str (), s.size ());
EXPECT_EQ (r, "YQ==");
s = "ab";
r = tl::to_base64 ((const unsigned char *) s.c_str (), s.size ());
EXPECT_EQ (r, "YWI=");
s = "abc";
r = tl::to_base64 ((const unsigned char *) s.c_str (), s.size ());
EXPECT_EQ (r, "YWJj");
s = "abcd";
r = tl::to_base64 ((const unsigned char *) s.c_str (), s.size ());
EXPECT_EQ (r, "YWJjZA==");
s = "Hello, world!\n";
r = tl::to_base64 ((const unsigned char *) s.c_str (), s.size ());
EXPECT_EQ (r, "SGVsbG8sIHdvcmxkIQo=");
}

View File

@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
tlAlgorithmTests.cc \
tlBase64Tests.cc \
tlClassRegistryTests.cc \
tlCommandLineParserTests.cc \
tlCopyOnWriteTests.cc \