diff --git a/pdf.c b/pdf.c index 93741d6854105c297403722cfc7f6021ac7684f2..363c08b75f1f3fa5e23659e17059f1d18a234461 100644 --- a/pdf.c +++ b/pdf.c @@ -2,7 +2,7 @@ * pesco 2019 */ -#include <string.h> /* strncmp(), memset() */ +#include <string.h> /* strncmp(), memset(), memcpy() */ #include <hammer/hammer.h> #include <hammer/glue.h> @@ -393,7 +393,45 @@ act_a85partialgroup(const HParseResult *p, void *u) return H_MAKE_BYTES(bytes, bytes_used); } -// TODO: flatten sequence in a85string semantic action +HParsedToken * +act_a85string(const HParseResult *p, void *u) +{ + uint8_t *result_bytes; + size_t chunk_number; + size_t required_bytes; + size_t out_pos = 0; + HCountedArray *seq = H_CAST_SEQ(p->ast); + HParsedToken *res; + + /* Number of 4-byte chunks, minus the potential last partial group and EOD */ + chunk_number = seq->used - 2; + + /* Special-case: last chunk before EOD may be 4, 3, 2 or 1 bytes + * The latter two happening if the group was parsed from a partial + * group consisting less than 5 chars */ + HBytes *last_chunk = seq->elements[seq->used-1]; + required_bytes = chunk_number * 4 + last_chunk->len; + + result_bytes = h_arena_malloc(p->arena, required_bytes); + + /* Memcpy all but the group's bytes into a single array */ + for (size_t i = 0; i < seq->used-1; ++i) + { + HBytes *chunk = H_CAST_BYTES(seq->elements[i]); + assert(out_pos < required_bytes); + memcpy(&(result_bytes[out_pos]), chunk->token, 4); + out_pos += 4; + assert(out_pos < required_bytes); + } + + memcpy(&(result_bytes[out_pos]), last_chunk->token, last_chunk->len); + out_pos += last_chunk->len; + /* We should have filled the array exactly by this point */ + assert(out_pos == required_bytes-1); + + res = H_MAKE_BYTES(result_bytes, required_bytes); + return res; +} HParsedToken * act_nat(const HParseResult *p, void *u) @@ -870,7 +908,7 @@ init_parser(struct Env *aux) H_VARULE(a85partial4group, h_repeat_n(MANY_LWS(a85digit), 4)); H_ARULE(a85partialgroup, CHX(a85partial4group, a85partial3group, a85partial2group)); - H_RULE(a85string, SEQ(h_many(a85group), OPT(a85partialgroup), IGN(a85eod))); + H_ARULE(a85string, SEQ(h_many(a85group), OPT(a85partialgroup), IGN(a85eod))); /* AsciiHexDecode parser */ H_RULE(ahexeod, h_ch('>'));