mirror of
https://gitlab.com/d3tn/ud3tn.git
synced 2026-08-14 12:43:26 +02:00
If the write method of the CLA fails, the serailizers will now return early and this failure is handled properly by the TX task. In the case of the BPv6 serializer, we add the necessary flow control to the `write_bytes` macro, to prevent needing a conditional for every write* or serialize* statement. Signed-off-by: Felix Walter <felix.walter@d3tn.com>
589 lines
14 KiB
C
589 lines
14 KiB
C
// SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
|
|
/**
|
|
* Unit Test for BPbis serializer
|
|
*
|
|
* Raw CBOR data is loaded from "test_bundle7Data.c".
|
|
*/
|
|
|
|
#include "bundle7/serializer.h"
|
|
#include "bundle7/eid.h"
|
|
#include "bundle7/hopcount.h"
|
|
#include "bundle7/bundle_age.h"
|
|
#include "bundle7/bundle7.h"
|
|
|
|
#include "platform/hal_io.h"
|
|
|
|
#include "ud3tn/bundle.h"
|
|
#include "ud3tn/result.h"
|
|
|
|
#include "testud3tn_unity.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h> // malloc(), free()
|
|
#include <string.h> // memcpy()
|
|
|
|
|
|
TEST_GROUP(bundle7Serializer);
|
|
|
|
extern uint8_t cbor_simple_bundle[];
|
|
extern size_t len_simple_bundle;
|
|
|
|
static size_t output_bytes;
|
|
|
|
|
|
TEST_SETUP(bundle7Serializer)
|
|
{
|
|
output_bytes = 0;
|
|
}
|
|
|
|
TEST_TEAR_DOWN(bundle7Serializer)
|
|
{
|
|
}
|
|
|
|
|
|
static enum ud3tn_result write(void *cla_obj, const void *data,
|
|
const size_t len)
|
|
{
|
|
char buf[32];
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(
|
|
output_bytes + len <= len_simple_bundle,
|
|
"CBOR too long");
|
|
|
|
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
|
|
|
|
if (len)
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
|
|
cbor_simple_bundle + output_bytes,
|
|
data, len, buf);
|
|
|
|
output_bytes += len;
|
|
|
|
return UD3TN_OK;
|
|
}
|
|
|
|
|
|
static struct bundle *create_simple_bundle(void)
|
|
{
|
|
struct bundle *bundle = bundle_init();
|
|
|
|
TEST_ASSERT_NOT_NULL(bundle);
|
|
|
|
bundle->protocol_version = 7;
|
|
bundle->proc_flags = BUNDLE_FLAG_MUST_NOT_BE_FRAGMENTED
|
|
| BUNDLE_FLAG_REPORT_DELIVERY
|
|
// this is a RFC 5050 flag and should be ignored
|
|
// by the serializer
|
|
| BUNDLE_V6_FLAG_NORMAL_PRIORITY;
|
|
bundle->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
|
|
bundle->destination = strdup("dtn:GS2");
|
|
bundle->source = strdup("ipn:243.350");
|
|
bundle->report_to = strdup("dtn:none");
|
|
|
|
bundle->creation_timestamp_ms = 658489863000; // 2020-11-12T09:51:03
|
|
bundle->sequence_number = 0;
|
|
bundle->lifetime_ms = 86400;
|
|
|
|
struct bundle_block_list *prev;
|
|
struct bundle_block_list *entry;
|
|
struct bundle_block *block;
|
|
|
|
// Previous node block
|
|
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PREVIOUS_NODE);
|
|
entry = bundle_block_entry_create(block);
|
|
|
|
bundle->blocks = entry;
|
|
prev = entry;
|
|
|
|
// CBOR: [1, "GS4"]
|
|
uint8_t previous_node[6] = {
|
|
0x82, 0x01, 0x63, 0x47, 0x53, 0x34
|
|
};
|
|
|
|
block->number = 2;
|
|
block->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
block->length = sizeof(previous_node);
|
|
block->data = malloc(sizeof(previous_node));
|
|
TEST_ASSERT_NOT_NULL(block->data);
|
|
memcpy(block->data, previous_node, sizeof(previous_node));
|
|
|
|
// Hop count block
|
|
block = bundle_block_create(BUNDLE_BLOCK_TYPE_HOP_COUNT);
|
|
entry = bundle_block_entry_create(block);
|
|
|
|
prev->next = entry;
|
|
prev = entry;
|
|
|
|
// CBOR: [30, 0]
|
|
uint8_t hop_count[4] = { 0x82, 0x18, 0x1e, 0x00 };
|
|
|
|
block->number = 3;
|
|
block->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
block->length = sizeof(hop_count);
|
|
block->data = malloc(sizeof(hop_count));
|
|
TEST_ASSERT_NOT_NULL(block->data);
|
|
memcpy(block->data, hop_count, sizeof(hop_count));
|
|
|
|
// Bundle age block
|
|
block = bundle_block_create(BUNDLE_BLOCK_TYPE_BUNDLE_AGE);
|
|
entry = bundle_block_entry_create(block);
|
|
|
|
prev->next = entry;
|
|
prev = entry;
|
|
|
|
// CBOR: 0
|
|
uint8_t bundle_age[1] = { 0x00 };
|
|
|
|
block->number = 4;
|
|
block->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
block->length = sizeof(bundle_age);
|
|
block->data = malloc(sizeof(bundle_age));
|
|
TEST_ASSERT_NOT_NULL(block->data);
|
|
memcpy(block->data, bundle_age, sizeof(bundle_age));
|
|
|
|
// Payload
|
|
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
|
|
entry = bundle_block_entry_create(block);
|
|
|
|
prev->next = entry;
|
|
|
|
uint8_t payload[12] = {
|
|
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
|
|
};
|
|
|
|
TEST_ASSERT_EQUAL(1, block->number);
|
|
block->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
block->length = sizeof(payload);
|
|
block->data = malloc(sizeof(payload));
|
|
TEST_ASSERT_NOT_NULL(block->data);
|
|
memcpy(block->data, payload, sizeof(payload));
|
|
bundle->payload_block = block;
|
|
|
|
return bundle;
|
|
}
|
|
|
|
|
|
TEST(bundle7Serializer, simple_bundle)
|
|
{
|
|
struct bundle *bundle = create_simple_bundle();
|
|
|
|
TEST_ASSERT_EQUAL(UD3TN_OK, bundle7_serialize(bundle, write, NULL));
|
|
TEST_ASSERT_EQUAL(len_simple_bundle, output_bytes);
|
|
|
|
bundle_free(bundle);
|
|
}
|
|
|
|
|
|
static enum ud3tn_result write_fail(void *cla_obj, const void *data,
|
|
const size_t len)
|
|
{
|
|
output_bytes++; // Here we just use it as a counter.
|
|
|
|
return UD3TN_FAIL;
|
|
}
|
|
|
|
|
|
TEST(bundle7Serializer, write_fail)
|
|
{
|
|
struct bundle *bundle = create_simple_bundle();
|
|
|
|
TEST_ASSERT_EQUAL(UD3TN_FAIL,
|
|
bundle7_serialize(bundle, write_fail, NULL));
|
|
// Assert write_fail was only called once.
|
|
TEST_ASSERT_EQUAL(1, output_bytes);
|
|
|
|
bundle_free(bundle);
|
|
}
|
|
|
|
|
|
// -----------------------
|
|
// CRC 16 AX.25 Generation
|
|
// -----------------------
|
|
//
|
|
extern uint8_t cbor_crc16_primary_block[];
|
|
extern uint8_t cbor_crc16_payload_block[];
|
|
extern size_t len_crc16_primary_block;
|
|
extern size_t len_crc16_payload_block;
|
|
|
|
static enum ud3tn_result write_crc16_primary_block(
|
|
void *cla_obj, const void *data,
|
|
const size_t len)
|
|
{
|
|
char buf[32];
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(
|
|
output_bytes + len <= len_crc16_primary_block,
|
|
"CBOR too long");
|
|
|
|
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
|
|
|
|
if (len)
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
|
|
cbor_crc16_primary_block + output_bytes,
|
|
data, len, buf);
|
|
|
|
output_bytes += len;
|
|
|
|
return UD3TN_OK;
|
|
}
|
|
|
|
static enum ud3tn_result write_crc16_payload_block(
|
|
void *cla_obj, const void *data,
|
|
const size_t len)
|
|
{
|
|
char buf[32];
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(
|
|
output_bytes + len <= len_crc16_payload_block,
|
|
"CBOR too long");
|
|
|
|
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
|
|
|
|
if (len)
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
|
|
cbor_crc16_payload_block + output_bytes,
|
|
data, len, buf);
|
|
|
|
output_bytes += len;
|
|
|
|
return UD3TN_OK;
|
|
}
|
|
|
|
TEST(bundle7Serializer, crc16_generation)
|
|
{
|
|
// --------------------
|
|
// CRC-16 primary block
|
|
// --------------------
|
|
|
|
struct bundle *bundle = bundle_init();
|
|
|
|
TEST_ASSERT_NOT_NULL(bundle);
|
|
|
|
bundle->protocol_version = 7;
|
|
bundle->proc_flags = BUNDLE_FLAG_NONE;
|
|
bundle->crc_type = BUNDLE_CRC_TYPE_16;
|
|
|
|
bundle->destination = strdup("dtn:GS2");
|
|
bundle->source = strdup("dtn:none");
|
|
bundle->report_to = strdup("dtn:none");
|
|
|
|
bundle->creation_timestamp_ms = 0;
|
|
bundle->sequence_number = 0;
|
|
bundle->lifetime_ms = 86400;
|
|
|
|
struct bundle_block *block;
|
|
|
|
// Empty Payload
|
|
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
|
|
bundle->blocks = bundle_block_entry_create(block);
|
|
|
|
block->number = 0;
|
|
block->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
block->length = 0;
|
|
block->data = NULL;
|
|
bundle->payload_block = block;
|
|
|
|
TEST_ASSERT_EQUAL(UD3TN_OK,
|
|
bundle7_serialize(bundle, write_crc16_primary_block, NULL));
|
|
TEST_ASSERT_EQUAL(len_crc16_primary_block, output_bytes);
|
|
|
|
// --------------------
|
|
// CRC-16 payload block
|
|
// --------------------
|
|
|
|
// Replace payload
|
|
free(block->data);
|
|
|
|
const uint8_t payload[] = {
|
|
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
|
|
};
|
|
|
|
block->crc_type = BUNDLE_CRC_TYPE_16;
|
|
block->length = sizeof(payload);
|
|
block->data = malloc(sizeof(payload));
|
|
TEST_ASSERT_NOT_NULL(block->data);
|
|
memcpy(block->data, payload, sizeof(payload));
|
|
|
|
// Disable CRC for primary block
|
|
bundle->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
|
|
// Reset output counter
|
|
output_bytes = 0;
|
|
|
|
TEST_ASSERT_EQUAL(UD3TN_OK,
|
|
bundle7_serialize(bundle, write_crc16_payload_block, NULL));
|
|
TEST_ASSERT_EQUAL(len_crc16_payload_block, output_bytes);
|
|
|
|
bundle_free(bundle);
|
|
}
|
|
|
|
// --------------------------
|
|
// CRC 32 Ethernet Generation
|
|
// --------------------------
|
|
//
|
|
extern uint8_t cbor_crc32_primary_block[];
|
|
extern uint8_t cbor_crc32_payload_block[];
|
|
extern size_t len_crc32_primary_block;
|
|
extern size_t len_crc32_payload_block;
|
|
|
|
static enum ud3tn_result write_crc32_primary_block(
|
|
void *cla_obj, const void *data,
|
|
const size_t len)
|
|
{
|
|
char buf[32];
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(
|
|
output_bytes + len <= len_crc32_primary_block,
|
|
"CBOR too long");
|
|
|
|
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
|
|
|
|
if (len)
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
|
|
cbor_crc32_primary_block + output_bytes,
|
|
data, len, buf);
|
|
|
|
output_bytes += len;
|
|
|
|
return UD3TN_OK;
|
|
}
|
|
|
|
static enum ud3tn_result write_crc32_payload_block(
|
|
void *cla_obj, const void *data,
|
|
const size_t len)
|
|
{
|
|
char buf[32];
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(
|
|
output_bytes + len <= len_crc32_payload_block,
|
|
"CBOR too long");
|
|
|
|
snprintf(buf, sizeof(buf), "Offset was: %zu", output_bytes);
|
|
|
|
if (len)
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(
|
|
cbor_crc32_payload_block + output_bytes,
|
|
data, len, buf);
|
|
|
|
output_bytes += len;
|
|
|
|
return UD3TN_OK;
|
|
}
|
|
|
|
TEST(bundle7Serializer, crc32_generation)
|
|
{
|
|
// --------------------
|
|
// CRC-32 primary block
|
|
// --------------------
|
|
|
|
struct bundle *bundle = bundle_init();
|
|
|
|
TEST_ASSERT_NOT_NULL(bundle);
|
|
|
|
bundle->protocol_version = 7;
|
|
bundle->proc_flags = BUNDLE_FLAG_NONE;
|
|
bundle->crc_type = BUNDLE_CRC_TYPE_32;
|
|
|
|
bundle->destination = strdup("dtn:GS2");
|
|
bundle->source = strdup("dtn:none");
|
|
bundle->report_to = strdup("dtn:none");
|
|
|
|
bundle->creation_timestamp_ms = 0;
|
|
bundle->sequence_number = 0;
|
|
bundle->lifetime_ms = 86400;
|
|
|
|
struct bundle_block *block;
|
|
|
|
// Empty Payload
|
|
block = bundle_block_create(BUNDLE_BLOCK_TYPE_PAYLOAD);
|
|
bundle->blocks = bundle_block_entry_create(block);
|
|
|
|
block->number = 0;
|
|
block->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
block->length = 0;
|
|
block->data = NULL;
|
|
bundle->payload_block = block;
|
|
|
|
TEST_ASSERT_EQUAL(UD3TN_OK,
|
|
bundle7_serialize(bundle, write_crc32_primary_block, NULL));
|
|
TEST_ASSERT_EQUAL(len_crc32_primary_block, output_bytes);
|
|
|
|
// --------------------
|
|
// CRC-32 payload block
|
|
// --------------------
|
|
|
|
// Replace payload
|
|
free(block->data);
|
|
|
|
const uint8_t payload[] = {
|
|
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
|
|
};
|
|
|
|
block->crc_type = BUNDLE_CRC_TYPE_32;
|
|
block->length = sizeof(payload);
|
|
block->data = malloc(sizeof(payload));
|
|
TEST_ASSERT_NOT_NULL(block->data);
|
|
memcpy(block->data, payload, sizeof(payload));
|
|
|
|
// Disable CRC for primary block
|
|
bundle->crc_type = BUNDLE_CRC_TYPE_NONE;
|
|
|
|
// Reset output counter
|
|
output_bytes = 0;
|
|
|
|
TEST_ASSERT_EQUAL(UD3TN_OK,
|
|
bundle7_serialize(bundle, write_crc32_payload_block, NULL));
|
|
TEST_ASSERT_EQUAL(len_crc32_payload_block, output_bytes);
|
|
|
|
bundle_free(bundle);
|
|
}
|
|
|
|
|
|
static uint8_t cbor_dtn_text[6] = { 0x82, 0x01, 0x63, 0x47, 0x53, 0x31 };
|
|
|
|
TEST(bundle7Serializer, dtn_text)
|
|
{
|
|
size_t length;
|
|
uint8_t *buffer;
|
|
|
|
buffer = bundle7_eid_serialize_alloc("dtn:GS1", &length);
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
TEST_ASSERT_EQUAL(sizeof(cbor_dtn_text), length);
|
|
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY(cbor_dtn_text, buffer,
|
|
sizeof(cbor_dtn_text));
|
|
}
|
|
|
|
|
|
static const uint8_t dtn_none[] = { 0x82, 0x01, 0x00 };
|
|
|
|
TEST(bundle7Serializer, dtn_none)
|
|
{
|
|
size_t length;
|
|
uint8_t *buffer;
|
|
|
|
buffer = bundle7_eid_serialize_alloc("dtn:none", &length);
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
TEST_ASSERT_EQUAL(sizeof(dtn_none), length);
|
|
|
|
buffer = bundle7_eid_serialize_alloc("", &length);
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
TEST_ASSERT_EQUAL(sizeof(dtn_none), length);
|
|
|
|
buffer = bundle7_eid_serialize_alloc(NULL, &length);
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
TEST_ASSERT_EQUAL(sizeof(dtn_none), length);
|
|
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY(dtn_none, buffer,
|
|
sizeof(dtn_none));
|
|
}
|
|
|
|
|
|
// ipn:12.123
|
|
static const uint8_t dtn_ipn[] = { 0x82, 0x02, 0x82, 0x0c, 0x18, 0x7b };
|
|
static const char *const dtn_ipn_eid = "ipn:12.123";
|
|
// max. value for ipn: EID
|
|
static const uint8_t dtn_ipn2[] = {
|
|
0x82, 0x02, 0x82,
|
|
0x1B, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0x1B, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
};
|
|
static const char *const dtn_ipn2_eid =
|
|
"ipn:18446744073709551615.18446744073709551615";
|
|
static const char *const dtn_ipn_overflow1_eid =
|
|
"ipn:18446744073709551616.18446744073709551615";
|
|
static const char *const dtn_ipn_overflow2_eid =
|
|
"ipn:18446744073709551615.18446744073709551616";
|
|
|
|
TEST(bundle7Serializer, dtn_ipn)
|
|
{
|
|
size_t length;
|
|
uint8_t *buffer;
|
|
|
|
buffer = bundle7_eid_serialize_alloc(dtn_ipn_eid, &length);
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
TEST_ASSERT_EQUAL(sizeof(dtn_ipn), length);
|
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(dtn_ipn, buffer,
|
|
sizeof(dtn_ipn));
|
|
TEST_ASSERT_EQUAL(length, bundle7_eid_sizeof(dtn_ipn_eid));
|
|
free(buffer);
|
|
|
|
buffer = bundle7_eid_serialize_alloc(
|
|
dtn_ipn2_eid,
|
|
&length
|
|
);
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
TEST_ASSERT_EQUAL(sizeof(dtn_ipn2), length);
|
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(dtn_ipn2, buffer,
|
|
sizeof(dtn_ipn2));
|
|
TEST_ASSERT_EQUAL(length, bundle7_eid_sizeof(dtn_ipn2_eid));
|
|
free(buffer);
|
|
|
|
buffer = bundle7_eid_serialize_alloc(
|
|
dtn_ipn_overflow1_eid,
|
|
&length
|
|
);
|
|
TEST_ASSERT_EQUAL(0, bundle7_eid_sizeof(dtn_ipn_overflow1_eid));
|
|
TEST_ASSERT_NULL(buffer);
|
|
|
|
buffer = bundle7_eid_serialize_alloc(
|
|
dtn_ipn_overflow2_eid,
|
|
&length
|
|
);
|
|
TEST_ASSERT_EQUAL(0, bundle7_eid_sizeof(dtn_ipn_overflow2_eid));
|
|
TEST_ASSERT_NULL(buffer);
|
|
}
|
|
|
|
|
|
// [40, 10]
|
|
static const uint8_t cbor_hop_count[] = { 0x82, 0x18, 0x28, 0x0a };
|
|
|
|
TEST(bundle7Serializer, hop_count)
|
|
{
|
|
struct bundle_hop_count hop_count = {
|
|
.limit = 40,
|
|
.count = 10
|
|
};
|
|
uint8_t *buffer = malloc(BUNDLE7_HOP_COUNT_MAX_ENCODED_SIZE);
|
|
|
|
TEST_ASSERT_NOT_NULL(buffer)
|
|
|
|
size_t written = bundle7_hop_count_serialize(
|
|
&hop_count, buffer, BUNDLE7_HOP_COUNT_MAX_ENCODED_SIZE);
|
|
|
|
TEST_ASSERT_EQUAL(sizeof(cbor_hop_count), written);
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY(cbor_hop_count, buffer,
|
|
sizeof(cbor_hop_count));
|
|
}
|
|
|
|
// 42000
|
|
static const uint8_t cbor_bundle_age[] = { 0x19, 0xa4, 0x10 };
|
|
|
|
TEST(bundle7Serializer, bundle_age)
|
|
{
|
|
uint64_t bundle_age = 42000;
|
|
uint8_t *buffer = malloc(BUNDLE_AGE_MAX_ENCODED_SIZE);
|
|
|
|
TEST_ASSERT_NOT_NULL(buffer);
|
|
size_t written = bundle_age_serialize(bundle_age, buffer,
|
|
BUNDLE_AGE_MAX_ENCODED_SIZE);
|
|
|
|
TEST_ASSERT_EQUAL(sizeof(cbor_bundle_age), written);
|
|
TEST_ASSERT_EQUAL_INT8_ARRAY(cbor_bundle_age, buffer,
|
|
sizeof(cbor_bundle_age));
|
|
}
|
|
|
|
|
|
TEST_GROUP_RUNNER(bundle7Serializer)
|
|
{
|
|
RUN_TEST_CASE(bundle7Serializer, dtn_text);
|
|
RUN_TEST_CASE(bundle7Serializer, dtn_none);
|
|
RUN_TEST_CASE(bundle7Serializer, dtn_ipn);
|
|
RUN_TEST_CASE(bundle7Serializer, hop_count);
|
|
RUN_TEST_CASE(bundle7Serializer, bundle_age);
|
|
RUN_TEST_CASE(bundle7Serializer, simple_bundle);
|
|
RUN_TEST_CASE(bundle7Serializer, write_fail);
|
|
RUN_TEST_CASE(bundle7Serializer, crc16_generation);
|
|
RUN_TEST_CASE(bundle7Serializer, crc32_generation);
|
|
}
|