Move to embedded base64
Base64 encode/decode is a relatively simple algorithm, and currently
libcper takes a dependency on libb64 for this. libb64 does not have
methods for determining the encoded size or decoded size, and rely on
the user to provide the right buffer sizes, which libcper currently
approximates as 2X the input size (which is incorrect).
This commit removes the libb64 dependency entirely, and inlines a
libcper specific base64 encoder and decoder, using EDK2-allowed types.
The implementation itself is unique to libcper and makes the following
design decisions.
1. Malloc is performed within the base64_<> functions. This reduces the
number of malloc calls total, and removes the need for separately
determining the output size.
2. Arguments are passed in by EDK2-types under the assumption that this
will keep compatibility with EDK2 implementations.
3. Incremental parsing is not supported. CPER records are expected to
be algorithmically small, and buffered such that the entire value
fits in memory. This was already an assumption, but dropping the
support for incremental encoding significantly reduces the amount of
code to support it. It could be added back in the future if needed.
Change-Id: Idb010db105067ea317dbee05c2663511ab3c6611
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/base64.c b/base64.c
new file mode 100644
index 0000000..fb26100
--- /dev/null
+++ b/base64.c
@@ -0,0 +1,149 @@
+#include "base64.h"
+#include "edk/BaseTypes.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+static const UINT8 encode_table[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+CHAR8 *base64_encode(const UINT8 *src, INT32 len, INT32 *out_len)
+{
+ CHAR8 *out;
+ CHAR8 *out_pos;
+ const UINT8 *src_end;
+ const UINT8 *in_pos;
+
+ if (!out_len) {
+ return NULL;
+ }
+
+ // 3 byte blocks to 4 byte blocks plus up to 2 bytes of padding
+ *out_len = 4 * ((len + 2) / 3);
+
+ // Handle overflows
+ if (*out_len < len) {
+ return NULL;
+ }
+
+ out = malloc(*out_len);
+ if (out == NULL) {
+ return NULL;
+ }
+
+ src_end = src + len;
+ in_pos = src;
+ out_pos = out;
+ while (src_end - in_pos >= 3) {
+ *out_pos++ = encode_table[in_pos[0] >> 2];
+ *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) |
+ (in_pos[1] >> 4)];
+ *out_pos++ = encode_table[((in_pos[1] & 0x0f) << 2) |
+ (in_pos[2] >> 6)];
+ *out_pos++ = encode_table[in_pos[2] & 0x3f];
+ in_pos += 3;
+ }
+
+ if (src_end - in_pos) {
+ *out_pos++ = encode_table[in_pos[0] >> 2];
+ if (src_end - in_pos == 1) {
+ *out_pos++ = encode_table[(in_pos[0] & 0x03) << 4];
+ *out_pos++ = '=';
+ } else {
+ *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) |
+ (in_pos[1] >> 4)];
+ *out_pos++ = encode_table[(in_pos[1] & 0x0f) << 2];
+ }
+ *out_pos++ = '=';
+ }
+
+ return out;
+}
+
+// Base64 decode table. Invalid values are specified with 0x80.
+UINT8 decode_table[256] =
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x3e\x80\x80\x80\x3f"
+ "\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x80\x80\x80\x00\x80\x80"
+ "\x80\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e"
+ "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x80\x80\x80\x80\x80"
+ "\x80\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28"
+ "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80";
+
+/**
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+UINT8 *base64_decode(const CHAR8 *src, INT32 len, INT32 *out_len)
+{
+ UINT8 *out;
+ UINT8 *pos;
+ UINT8 block[4];
+ UINT8 tmp;
+ INT32 block_index;
+ INT32 src_index;
+ UINT32 pad_count = 0;
+
+ if (!out_len) {
+ return NULL;
+ }
+
+ // Malloc might be up to 2 larger dependent on padding
+ *out_len = len / 4 * 3;
+ pos = out = malloc(*out_len);
+ if (out == NULL) {
+ return NULL;
+ }
+
+ block_index = 0;
+ for (src_index = 0; src_index < len; src_index++) {
+ tmp = decode_table[(UINT8)src[src_index]];
+ if (tmp == 0x80) {
+ free(out);
+ return NULL;
+ }
+
+ if (src[src_index] == '=') {
+ pad_count++;
+ }
+
+ block[block_index] = tmp;
+ block_index++;
+ if (block_index == 4) {
+ *pos++ = (block[0] << 2) | (block[1] >> 4);
+ *pos++ = (block[1] << 4) | (block[2] >> 2);
+ *pos++ = (block[2] << 6) | block[3];
+ if (pad_count > 0) {
+ if (pad_count == 1) {
+ pos--;
+ } else if (pad_count == 2) {
+ pos -= 2;
+ } else {
+ /* Invalid pad_counting */
+ free(out);
+ return NULL;
+ }
+ break;
+ }
+ block_index = 0;
+ }
+ }
+
+ *out_len = pos - out;
+ return out;
+}
diff --git a/base64.h b/base64.h
new file mode 100644
index 0000000..171f535
--- /dev/null
+++ b/base64.h
@@ -0,0 +1,13 @@
+#include "edk/BaseTypes.h"
+
+/**
+ * base64_decode
+ * Caller is responsible for freeing the returned buffer.
+ */
+UINT8 *base64_decode(const CHAR8 *src, INT32 len, INT32 *out_len);
+
+/**
+ * base64_encode
+ * Caller is responsible for freeing the returned buffer.
+ */
+CHAR8 *base64_encode(const UINT8 *src, INT32 len, INT32 *out_len);
diff --git a/cper-parse.c b/cper-parse.c
index 7214b15..d0ddedb 100644
--- a/cper-parse.c
+++ b/cper-parse.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "edk/Cper.h"
#include "cper-parse.h"
#include "cper-utils.h"
@@ -335,20 +335,19 @@
if (!section_converted) {
//Output the data as formatted base64.
result = json_object_new_object();
- char *encoded = malloc(2 * descriptor->SectionLength);
- size_t encoded_len = 0;
- if (!encoded) {
+
+ int32_t encoded_len = 0;
+ char *encoded = base64_encode(
+ section, descriptor->SectionLength, &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
} else {
- base64_encode(section, descriptor->SectionLength,
- encoded, &encoded_len, 0);
json_object_object_add(result, "data",
json_object_new_string_len(
encoded, encoded_len));
free(encoded);
}
}
-
//Free section memory, return result.
free(section);
return result;
diff --git a/ir-parse.c b/ir-parse.c
index 3f6cfef..0287337 100644
--- a/ir-parse.c
+++ b/ir-parse.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "edk/Cper.h"
#include "cper-parse.h"
#include "cper-utils.h"
@@ -171,14 +171,15 @@
//If unknown GUID, so read as a base64 unknown section.
if (!section_converted) {
json_object *encoded = json_object_object_get(section, "data");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(
+ json_object_get_string(encoded),
+ json_object_get_string_len(encoded), &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded),
- decoded, &decoded_len, 0);
fwrite(decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
diff --git a/meson.build b/meson.build
index 80d46b2..1f9287b 100644
--- a/meson.build
+++ b/meson.build
@@ -58,27 +58,8 @@
json_c_dep = dependency('json-c', required: true, fallback: ['json-c', 'json_c_dep'])
-libb64 = cc.find_library('base64', has_headers: 'libbase64.h', required: false)
-if not libb64.found()
- opt_var = cmake.subproject_options()
- opt_var.add_cmake_defines(
- {
- 'BUILD_SHARED_LIBS': library_is_share,
- 'BASE64_BUILD_CLI': false,
- 'BASE64_WITH_AVX': false,
- 'BASE64_WITH_AVX2': false,
- 'BASE64_WITH_AVX512': false,
- 'BASE64_WITH_SSSE3': false,
- 'BASE64_WITH_SSE41': false,
- 'BASE64_WITH_SSE42': false,
- },
- )
-
- libb64_ex = cmake.subproject('libb64', options: opt_var)
- libb64 = libb64_ex.dependency('base64')
-endif
-
libcper_parse_sources = [
+ 'base64.c',
'cper-parse.c',
'ir-parse.c',
'cper-utils.c',
@@ -98,7 +79,6 @@
c_args: '-Wno-address-of-packed-member',
dependencies: [
json_c_dep,
- libb64,
],
install: true,
install_dir: get_option('libdir'),
@@ -119,7 +99,6 @@
dependencies: [
libcper_parse,
json_c_dep,
- libb64,
],
install: true,
install_dir: get_option('libdir'),
diff --git a/sections/cper-section-arm.c b/sections/cper-section-arm.c
index eba2c8f..b0b14d1 100644
--- a/sections/cper-section-arm.c
+++ b/sections/cper-section-arm.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-arm.h"
@@ -121,21 +121,19 @@
json_object *vendor_specific = json_object_new_object();
size_t input_size =
(uint8_t *)section + record->SectionLength - cur_pos;
- char *encoded = malloc(2 * input_size);
- size_t encoded_len = 0;
- if (!encoded) {
- printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)cur_pos, input_size,
- encoded, &encoded_len, 0);
- json_object_object_add(vendor_specific, "data",
- json_object_new_string_len(
- encoded, encoded_len));
- free(encoded);
-
- json_object_object_add(section_ir, "vendorSpecificInfo",
- vendor_specific);
+ int32_t encoded_len = 0;
+ char *encoded =
+ base64_encode(cur_pos, input_size, &encoded_len);
+ if (encoded == NULL) {
+ return NULL;
}
+ json_object_object_add(vendor_specific, "data",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
+
+ json_object_object_add(section_ir, "vendorSpecificInfo",
+ vendor_specific);
}
return section_ir;
@@ -441,19 +439,19 @@
default:
//Unknown register array type, add as base64 data instead.
register_array = json_object_new_object();
- char *encoded = malloc(2 * header->RegisterArraySize);
- size_t encoded_len = 0;
- if (!encoded) {
+ int32_t encoded_len = 0;
+ char *encoded = base64_encode((UINT8 *)cur_pos,
+ header->RegisterArraySize,
+ &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)cur_pos,
- header->RegisterArraySize, encoded,
- &encoded_len, 0);
- json_object_object_add(register_array, "data",
- json_object_new_string_len(
- encoded, encoded_len));
- free(encoded);
+ return NULL;
}
+ json_object_object_add(register_array, "data",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
+
break;
}
json_object_object_add(context_ir, "registerArray", register_array);
@@ -549,20 +547,17 @@
json_object_object_get(vendor_specific_info, "data");
int vendor_specific_len =
json_object_get_string_len(vendor_info_string);
- char *decoded = malloc(vendor_specific_len);
- size_t decoded_len = 0;
- if (!decoded) {
- printf("Failed to allocate decode output buffer. \n");
- } else {
- base64_decode(
- json_object_get_string(vendor_info_string),
- vendor_specific_len, decoded, &decoded_len, 0);
- //Write out to file.
- fwrite(decoded, decoded_len, 1, out);
- fflush(out);
- free(decoded);
- }
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(
+ json_object_get_string(vendor_info_string),
+ vendor_specific_len, &decoded_len);
+
+ //Write out to file.
+ fwrite(decoded, decoded_len, 1, out);
+ fflush(out);
+ free(decoded);
}
//Free remaining resources.
@@ -903,15 +898,16 @@
{
//Get base64 represented data.
json_object *encoded = json_object_object_get(registers, "data");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
-
//Flush out to stream.
fwrite(&decoded, decoded_len, 1, out);
fflush(out);
diff --git a/sections/cper-section-ccix-per.c b/sections/cper-section-ccix-per.c
index 8e43c6d..f6ffd39 100644
--- a/sections/cper-section-ccix-per.c
+++ b/sections/cper-section-ccix-per.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-ccix-per.h"
@@ -39,13 +39,13 @@
int remaining_length =
ccix_error->Length - sizeof(EFI_CCIX_PER_LOG_DATA);
if (remaining_length > 0) {
- char *encoded = malloc(2 * remaining_length);
- size_t encoded_len = 0;
- if (!encoded) {
+ int32_t encoded_len = 0;
+
+ char *encoded = base64_encode((UINT8 *)cur_pos,
+ remaining_length, &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
} else {
- base64_encode((const char *)cur_pos, remaining_length,
- encoded, &encoded_len, 0);
json_object_object_add(section_ir, "ccixPERLog",
json_object_new_string_len(
encoded, encoded_len));
@@ -83,19 +83,18 @@
//Write CCIX PER log itself to stream.
json_object *encoded = json_object_object_get(section, "ccixPERLog");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
fwrite(decoded, decoded_len, 1, out);
fflush(out);
+ free(decoded);
}
-
//Free resources.
- free(decoded);
free(section_cper);
}
diff --git a/sections/cper-section-cxl-component.c b/sections/cper-section-cxl-component.c
index 9976df2..343611f 100644
--- a/sections/cper-section-cxl-component.c
+++ b/sections/cper-section-cxl-component.c
@@ -6,7 +6,7 @@
**/
#include <stdio.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-cxl-component.h"
@@ -63,21 +63,22 @@
cxl_error->Length - sizeof(EFI_CXL_COMPONENT_EVENT_HEADER);
if (remaining_len > 0) {
json_object *event_log = json_object_new_object();
- char *encoded = malloc(2 * remaining_len);
- size_t encoded_len = 0;
- if (!encoded) {
- printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)cur_pos, remaining_len,
- encoded, &encoded_len, 0);
- json_object_object_add(event_log, "data",
- json_object_new_string_len(
- encoded, encoded_len));
- free(encoded);
- json_object_object_add(
- section_ir, "cxlComponentEventLog", event_log);
+ int32_t encoded_len = 0;
+
+ char *encoded = base64_encode((UINT8 *)cur_pos, remaining_len,
+ &encoded_len);
+ if (encoded == NULL) {
+ printf("Failed to allocate encode output buffer. \n");
+ return NULL;
}
+ json_object_object_add(event_log, "data",
+ json_object_new_string_len(encoded,
+ encoded_len));
+
+ free(encoded);
+ json_object_object_add(section_ir, "cxlComponentEventLog",
+ event_log);
}
return section_ir;
@@ -129,14 +130,16 @@
json_object *event_log =
json_object_object_get(section, "cxlComponentEventLog");
json_object *encoded = json_object_object_get(event_log, "data");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
fwrite(decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
diff --git a/sections/cper-section-cxl-protocol.c b/sections/cper-section-cxl-protocol.c
index 7aef836..88ed2e9 100644
--- a/sections/cper-section-cxl-protocol.c
+++ b/sections/cper-section-cxl-protocol.c
@@ -6,7 +6,7 @@
**/
#include <stdio.h>
#include <string.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-cxl-protocol.h"
@@ -92,6 +92,7 @@
cxl_protocol_error->DeviceId.SlotNumber));
json_object_object_add(section_ir, "deviceID", device_id);
+ char *encoded;
//Device serial & capability structure (if CXL 1.1 device).
if (cxl_protocol_error->CxlAgentType ==
CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
@@ -103,20 +104,20 @@
//The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
//(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
//to be a way to differentiate these, so this is left as a b64 dump.
- char *encoded = malloc(2 * 60);
- size_t encoded_len = 0;
- if (!encoded) {
+
+ int32_t encoded_len = 0;
+
+ encoded = base64_encode(
+ (UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
+ 60, &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)cxl_protocol_error
- ->CapabilityStructure.PcieCap,
- 60, encoded, &encoded_len, 0);
- json_object_object_add(section_ir,
- "capabilityStructure",
- json_object_new_string_len(
- encoded, encoded_len));
- free(encoded);
+ return NULL;
}
+ json_object_object_add(section_ir, "capabilityStructure",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
}
//CXL DVSEC & error log length.
@@ -131,35 +132,39 @@
//For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
//For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
const char *cur_pos = (const char *)(cxl_protocol_error + 1);
- char *encoded = malloc(2 * cxl_protocol_error->CxlDvsecLength);
- size_t encoded_len = 0;
- if (!encoded) {
- printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode(cur_pos, cxl_protocol_error->CxlDvsecLength,
- encoded, &encoded_len, 0);
- json_object_object_add(section_ir, "cxlDVSEC",
- json_object_new_string_len(encoded,
- encoded_len));
+ int32_t encoded_len = 0;
- free(encoded);
+ encoded = base64_encode((UINT8 *)cur_pos,
+ cxl_protocol_error->CxlDvsecLength,
+ &encoded_len);
+ if (encoded == NULL) {
+ return NULL;
}
+ json_object_object_add(section_ir, "cxlDVSEC",
+ json_object_new_string_len(encoded,
+ encoded_len));
+
+ free(encoded);
+
cur_pos += cxl_protocol_error->CxlDvsecLength;
//CXL Error Log
//This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
- encoded = malloc(2 * cxl_protocol_error->CxlErrorLogLength);
+
encoded_len = 0;
- if (!encoded) {
+ encoded = base64_encode((UINT8 *)cur_pos,
+ cxl_protocol_error->CxlErrorLogLength,
+ &encoded_len);
+
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode(cur_pos, cxl_protocol_error->CxlErrorLogLength,
- encoded, &encoded_len, 0);
- json_object_object_add(section_ir, "cxlErrorLog",
- json_object_new_string_len(encoded,
- encoded_len));
- free(encoded);
+ return NULL;
}
+ json_object_object_add(section_ir, "cxlErrorLog",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
+
return section_ir;
}
@@ -223,20 +228,23 @@
json_object_object_get(device_id, "slotNumber"));
//If CXL 1.1 device, the serial number & PCI capability structure.
+ UINT8 *decoded;
if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
section_cper->DeviceSerial = json_object_get_uint64(
json_object_object_get(section, "deviceSerial"));
json_object *encoded =
json_object_object_get(section, "capabilityStructure");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+
+ int32_t decoded_len = 0;
+
+ decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded),
- decoded, &decoded_len, 0);
memcpy(section_cper->CapabilityStructure.PcieCap,
decoded, decoded_len);
free(decoded);
@@ -255,14 +263,15 @@
//DVSEC out to stream.
json_object *encoded = json_object_object_get(section, "cxlDVSEC");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+
+ int32_t decoded_len = 0;
+
+ decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
fwrite(decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
@@ -270,14 +279,14 @@
//Error log out to stream.
encoded = json_object_object_get(section, "cxlErrorLog");
- decoded = malloc(json_object_get_string_len(encoded));
decoded_len = 0;
- if (!decoded) {
+
+ decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
fwrite(decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
diff --git a/sections/cper-section-dmar-iommu.c b/sections/cper-section-dmar-iommu.c
index 0158a0b..b813a6e 100644
--- a/sections/cper-section-dmar-iommu.c
+++ b/sections/cper-section-dmar-iommu.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-dmar-iommu.h"
@@ -31,32 +31,33 @@
//IOMMU event log entry.
//The format of these entries differ widely by the type of error.
- char *encoded = malloc(2 * 16);
- size_t encoded_len = 0;
- if (!encoded) {
+ int32_t encoded_len = 0;
+
+ char *encoded = base64_encode((UINT8 *)iommu_error->EventLogEntry, 16,
+ &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)iommu_error->EventLogEntry, 16,
- encoded, &encoded_len, 0);
- json_object_object_add(section_ir, "eventLogEntry",
- json_object_new_string_len(encoded,
- encoded_len));
- free(encoded);
+
+ return NULL;
}
+ json_object_object_add(section_ir, "eventLogEntry",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
//Device table entry (as base64).
- encoded = malloc(2 * 32);
encoded_len = 0;
- if (!encoded) {
+
+ encoded = base64_encode((UINT8 *)iommu_error->DeviceTableEntry, 32,
+ &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)iommu_error->DeviceTableEntry, 32,
- encoded, &encoded_len, 0);
- json_object_object_add(section_ir, "deviceTableEntry",
- json_object_new_string_len(encoded,
- encoded_len));
- free(encoded);
+ return NULL;
}
+ json_object_object_add(section_ir, "deviceTableEntry",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
//Page table entries.
json_object_object_add(section_ir, "pageTableEntry_Level6",
@@ -92,28 +93,27 @@
//IOMMU event log entry.
json_object *encoded = json_object_object_get(section, "eventLogEntry");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
memcpy(section_cper->EventLogEntry, decoded, decoded_len);
free(decoded);
}
-
//Device table entry.
encoded = json_object_object_get(section, "deviceTableEntry");
- decoded = malloc(json_object_get_string_len(encoded));
decoded_len = 0;
- if (!decoded) {
+
+ decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
memcpy(section_cper->DeviceTableEntry, decoded, decoded_len);
free(decoded);
}
diff --git a/sections/cper-section-dmar-vtd.c b/sections/cper-section-dmar-vtd.c
index 5f4bad9..f954094 100644
--- a/sections/cper-section-dmar-vtd.c
+++ b/sections/cper-section-dmar-vtd.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-dmar-vtd.h"
@@ -82,27 +82,22 @@
json_object_object_add(section_ir, "faultRecord", fault_record_ir);
//Root entry.
- char *encoded = malloc(2 * 16);
- size_t encoded_len = 0;
- if (!encoded) {
- printf("Failed to allocate encode output buffer. \n");
- } else {
- base64_encode((const char *)vtd_error->RootEntry, 16, encoded,
- &encoded_len, 0);
- json_object_object_add(section_ir, "rootEntry",
- json_object_new_string_len(encoded,
- encoded_len));
- free(encoded);
- }
+ int32_t encoded_len = 0;
+
+ char *encoded =
+ base64_encode((UINT8 *)vtd_error->RootEntry, 16, &encoded_len);
+ json_object_object_add(section_ir, "rootEntry",
+ json_object_new_string_len(encoded,
+ encoded_len));
+ free(encoded);
//Context entry.
- encoded = malloc(2 * 16);
encoded_len = 0;
- if (!encoded) {
+ encoded = base64_encode((UINT8 *)vtd_error->ContextEntry, 16,
+ &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
} else {
- base64_encode((const char *)vtd_error->ContextEntry, 16,
- encoded, &encoded_len, 0);
json_object_object_add(section_ir, "contextEntry",
json_object_new_string_len(encoded,
encoded_len));
@@ -183,27 +178,29 @@
//Root entry.
json_object *encoded = json_object_object_get(section, "rootEntry");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
memcpy(section_cper->RootEntry, decoded, decoded_len);
free(decoded);
}
+
//Context entry.
encoded = json_object_object_get(section, "contextEntry");
- decoded = malloc(json_object_get_string_len(encoded));
decoded_len = 0;
- if (!decoded) {
+
+ decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
+
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
memcpy(section_cper->ContextEntry, decoded, decoded_len);
free(decoded);
}
diff --git a/sections/cper-section-ia32x64.c b/sections/cper-section-ia32x64.c
index e3ea1b8..bb07da6 100644
--- a/sections/cper-section-ia32x64.c
+++ b/sections/cper-section-ia32x64.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-ia32x64.h"
@@ -390,15 +390,13 @@
//No parseable data, just dump as base64 and shift the head to the next item.
*cur_pos = (void *)(context_info + 1);
- char *encoded = malloc(2 * context_info->ArraySize);
- size_t encoded_len = 0;
- if (!encoded) {
+ int32_t encoded_len = 0;
+ char *encoded = base64_encode((UINT8 *)*cur_pos,
+ context_info->ArraySize,
+ &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
} else {
- base64_encode((const char *)*cur_pos,
- context_info->ArraySize, encoded,
- &encoded_len, 0);
-
register_array = json_object_new_object();
json_object_object_add(register_array, "data",
json_object_new_string_len(
@@ -819,14 +817,13 @@
//Unknown/structure is not defined.
json_object *encoded =
json_object_object_get(register_array, "data");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+ int32_t decoded_len = 0;
+ const char *j_string = json_object_get_string(encoded);
+ int j_size = json_object_get_string_len(encoded);
+ UINT8 *decoded = base64_decode(j_string, j_size, &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded),
- decoded, &decoded_len, 0);
fwrite(decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
diff --git a/sections/cper-section-pcie.c b/sections/cper-section-pcie.c
index fe82b16..1c6534f 100644
--- a/sections/cper-section-pcie.c
+++ b/sections/cper-section-pcie.c
@@ -7,7 +7,7 @@
#include <stdio.h>
#include <string.h>
#include <json.h>
-#include "libbase64.h"
+#include "base64.h"
#include "../edk/Cper.h"
#include "../cper-utils.h"
#include "cper-section-pcie.h"
@@ -103,38 +103,39 @@
//The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
//(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
//to be a way to differentiate these, so this is left as a b64 dump.
- char *encoded = malloc(2 * 60);
- size_t encoded_len = 0;
- if (!encoded) {
+ int32_t encoded_len = 0;
+
+ char *encoded = base64_encode((UINT8 *)pcie_error->Capability.PcieCap,
+ 60, &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
} else {
- base64_encode((const char *)pcie_error->Capability.PcieCap, 60,
- encoded, &encoded_len, 0);
json_object *capability = json_object_new_object();
json_object_object_add(capability, "data",
json_object_new_string_len(encoded,
encoded_len));
free(encoded);
+
json_object_object_add(section_ir, "capabilityStructure",
capability);
}
//AER information.
json_object *aer_capability_ir = json_object_new_object();
- encoded = malloc(2 * 96);
encoded_len = 0;
- if (!encoded) {
+
+ encoded = base64_encode((UINT8 *)pcie_error->AerInfo.PcieAer, 96,
+ &encoded_len);
+ if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
} else {
- base64_encode((const char *)pcie_error->AerInfo.PcieAer, 96,
- encoded, &encoded_len, 0);
json_object_object_add(aer_capability_ir, "data",
json_object_new_string_len(encoded,
encoded_len));
free(encoded);
- json_object_object_add(section_ir, "aerInfo",
- aer_capability_ir);
}
+ json_object_object_add(section_ir, "aerInfo", aer_capability_ir);
+
return section_ir;
}
@@ -206,14 +207,15 @@
json_object *capability =
json_object_object_get(section, "capabilityStructure");
json_object *encoded = json_object_object_get(capability, "data");
- char *decoded = malloc(json_object_get_string_len(encoded));
- size_t decoded_len = 0;
- if (!decoded) {
+
+ int32_t decoded_len = 0;
+
+ UINT8 *decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
memcpy(section_cper->Capability.PcieCap, decoded, decoded_len);
free(decoded);
}
@@ -221,14 +223,15 @@
//AER capability structure.
json_object *aer_info = json_object_object_get(section, "aerInfo");
encoded = json_object_object_get(aer_info, "data");
- decoded = malloc(json_object_get_string_len(encoded));
decoded_len = 0;
- if (!decoded) {
+
+ decoded = base64_decode(json_object_get_string(encoded),
+ json_object_get_string_len(encoded),
+ &decoded_len);
+
+ if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
- base64_decode(json_object_get_string(encoded),
- json_object_get_string_len(encoded), decoded,
- &decoded_len, 0);
memcpy(section_cper->AerInfo.PcieAer, decoded, decoded_len);
free(decoded);
}
diff --git a/subprojects/libb64.wrap b/subprojects/libb64.wrap
deleted file mode 100644
index 3797ca7..0000000
--- a/subprojects/libb64.wrap
+++ /dev/null
@@ -1,6 +0,0 @@
-[wrap-git]
-url = https://github.com/aklomp/base64
-revision = 8bdda2d47caf8b066999c5bd01069e55bcd0d396
-
-[provide]
-libb64 = libb64_dep
diff --git a/tests/base64_test.cpp b/tests/base64_test.cpp
new file mode 100644
index 0000000..b762b8e
--- /dev/null
+++ b/tests/base64_test.cpp
@@ -0,0 +1,26 @@
+extern "C" {
+#include "base64.h"
+}
+
+#include "gtest/gtest.h"
+#include "gmock/gmock.h"
+
+TEST(Base64Encode, Good)
+{
+ int32_t encoded_len = 0;
+ std::array<uint8_t, 1> data = { 'f' };
+ char *encoded = base64_encode(data.data(), data.size(), &encoded_len);
+ EXPECT_EQ(encoded_len, 4);
+ ASSERT_EQ(std::string_view(encoded, encoded_len), "Zg==");
+ free(encoded);
+}
+
+TEST(Base64Decode, Good)
+{
+ int32_t decoded_len = 0;
+ std::string_view data{ "Zg==" };
+ UINT8 *decoded = base64_decode(data.data(), data.size(), &decoded_len);
+ EXPECT_EQ(decoded_len, 1);
+ ASSERT_EQ(decoded[0], 'f');
+ free(decoded);
+}
diff --git a/tests/meson.build b/tests/meson.build
index 21c443d..9efc7ae 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -22,6 +22,7 @@
sources = [
'ir-tests.cpp',
'test-utils.cpp',
+ 'base64_test.cpp',
]
test_include_dirs = ['.', '..']