Skip to content

Commit

Permalink
Fix C++ generator to pass Base64 tests
Browse files Browse the repository at this point in the history
This patch includes all the changes needed so that we pass the Base64
tests in the SDK.
  • Loading branch information
mristin committed Feb 7, 2024
1 parent 256cc8a commit 5b0c8c4
Show file tree
Hide file tree
Showing 5 changed files with 8 additions and 199 deletions.
4 changes: 4 additions & 0 deletions aas_core_codegen/cpp/stringification/_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,10 @@ def _generate_base64_decode_implementation() -> List[Stripped]:
> {function_name}(
{I}const std::string& text
) {{
{I}if (text.empty()) {{
{II}return std::vector<std::uint8_t>();
{I}}}
{I}const std::size_t len = text.size();
{I}std::size_t len_wo_pad = len;
Expand Down
114 changes: 0 additions & 114 deletions aas_core_codegen/cpp/wstringification/_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,118 +457,6 @@ def _generate_enum_to_wstring_implementation(
)


def _generate_base64_encode_definition() -> Stripped:
"""Generate the definition of a stringification of bytes as base64 wstring."""
function_name = cpp_naming.function_name(Identifier("base64_encode"))
return Stripped(
f"""\
/**
* Encode the \\p bytes with base64 to a std::wstring.
*
* \\param bytes to be encoded
* \\return base64-encoding of \\p bytes
*/
std::wstring {function_name}(
{I}const std::vector<std::uint8_t>& bytes
);"""
)


def _generate_base64_encode_implementation() -> List[Stripped]:
"""Generate the implementation of a stringification of bytes as base64 wstring."""
function_name = cpp_naming.function_name(Identifier("base64_encode"))

wchar_base64_table = cpp_naming.constant_name(Identifier("wchar_base64_table"))

return [
Stripped(
"""\
// The following encoder has been adapted from Jouni Malinen <[email protected]> to work with
// std::wstring. The original source code is available at:
// https://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c"""
),
Stripped(
f"""\
static const wchar_t {wchar_base64_table}[65](
{I}L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
);"""
),
Stripped(
f"""\
std::wstring {function_name}(
{I}const std::vector<std::uint8_t>& bytes
) {{
{I}// See: https://cplusplus.com/reference/vector/vector/data/.
{I}// The data is guaranteed to be a continuous block in memory.
{I}const unsigned char* src(
{II}bytes.data()
{I});
{I}const std::size_t len = bytes.size();
{I}// 3-byte blocks to 4-byte
{I}const std::size_t olen = 4 * ((len + 2) / 3);
{I}// Integer overflow?
{I}if (olen < len) {{
{II}throw std::invalid_argument(
{III}common::Concat(
{IIII}"The calculation of the output length overflowed. "
{IIII}"The length was: ",
{IIII}std::to_string(len),
{IIII}", but the output length was calculated as: ",
{IIII}std::to_string(olen)
{III})
{II});
{I}}}
{I}std::wstring out_wstring;
{I}out_wstring.resize(olen);
{I}wchar_t* out(
{II}static_cast<wchar_t*>(
{III}&out_wstring[0]
{II})
{I});
{I}const unsigned char* end = src + len;
{I}const unsigned char* in = src;
{I}wchar_t* pos = out;
{I}while (end - in >= 3) {{
{II}*pos++ = {wchar_base64_table}[in[0] >> 2];
{II}*pos++ = {wchar_base64_table}[((in[0] & 0x03) << 4) | (in[1] >> 4)];
{II}*pos++ = {wchar_base64_table}[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
{II}*pos++ = {wchar_base64_table}[in[2] & 0x3f];
{II}in += 3;
{I}}}
{I}if (end - in) {{
{II}*pos++ = {wchar_base64_table}[in[0] >> 2];
{II}if (end - in == 1) {{
{III}*pos++ = {wchar_base64_table}[(in[0] & 0x03) << 4];
{III}*pos++ = L'=';
{II}}} else {{
{III}*pos++ = {wchar_base64_table}[
{IIII}((in[0] & 0x03) << 4) | (in[1] >> 4)
{III}];
{III}*pos++ = {wchar_base64_table}[(in[1] & 0x0f) << 2];
{II}}}
{II}*pos++ = L'=';
{I}}}
{I}return out_wstring;
}}"""
),
]


# NOTE (mristin, 2023-07-12):
# The SDK does not use base64-decoding *from* wide strings, so we omit that direction
# here following YAGNI.

# fmt: off
@ensure(
lambda result:
Expand Down Expand Up @@ -622,7 +510,6 @@ def generate_header(

blocks.extend(
[
_generate_base64_encode_definition(),
Stripped(
"""\
} // namespace wstringification
Expand Down Expand Up @@ -682,7 +569,6 @@ def generate_implementation(

blocks.extend(
[
*_generate_base64_encode_implementation(),
cpp_common.generate_namespace_closing(namespace),
cpp_common.WARNING,
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,10 @@ common::expected<
> Base64Decode(
const std::string& text
) {
if (text.empty()) {
return std::vector<std::uint8_t>();
}

const std::size_t len = text.size();
std::size_t len_wo_pad = len;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1511,81 +1511,6 @@ std::wstring to_wstring(
}
}

// The following encoder has been adapted from Jouni Malinen <[email protected]> to work with
// std::wstring. The original source code is available at:
// https://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c

static const wchar_t kWcharBase64Table[65](
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
);

std::wstring Base64Encode(
const std::vector<std::uint8_t>& bytes
) {
// See: https://cplusplus.com/reference/vector/vector/data/.
// The data is guaranteed to be a continuous block in memory.
const unsigned char* src(
bytes.data()
);

const std::size_t len = bytes.size();

// 3-byte blocks to 4-byte
const std::size_t olen = 4 * ((len + 2) / 3);

// Integer overflow?
if (olen < len) {
throw std::invalid_argument(
common::Concat(
"The calculation of the output length overflowed. "
"The length was: ",
std::to_string(len),
", but the output length was calculated as: ",
std::to_string(olen)
)
);
}

std::wstring out_wstring;
out_wstring.resize(olen);

wchar_t* out(
static_cast<wchar_t*>(
&out_wstring[0]
)
);

const unsigned char* end = src + len;

const unsigned char* in = src;
wchar_t* pos = out;

while (end - in >= 3) {
*pos++ = kWcharBase64Table[in[0] >> 2];
*pos++ = kWcharBase64Table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = kWcharBase64Table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = kWcharBase64Table[in[2] & 0x3f];
in += 3;
}

if (end - in) {
*pos++ = kWcharBase64Table[in[0] >> 2];

if (end - in == 1) {
*pos++ = kWcharBase64Table[(in[0] & 0x03) << 4];
*pos++ = L'=';
} else {
*pos++ = kWcharBase64Table[
((in[0] & 0x03) << 4) | (in[1] >> 4)
];
*pos++ = kWcharBase64Table[(in[1] & 0x0f) << 2];
}
*pos++ = L'=';
}

return out_wstring;
}

} // namespace wstringification
} // namespace aas_3_0
} // namespace aas_core
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,16 +438,6 @@ std::wstring to_wstring(
types::DataTypeIec61360 literal
);

/**
* Encode the \p bytes with base64 to a std::wstring.
*
* \param bytes to be encoded
* \return base64-encoding of \p bytes
*/
std::wstring Base64Encode(
const std::vector<std::uint8_t>& bytes
);

} // namespace wstringification
/**@}*/

Expand Down

0 comments on commit 5b0c8c4

Please sign in to comment.