SRL_STATIC_INLINE void srl_fill_header(pTHX_ srl_merger_t *mrg, const char *user_header, STRLEN user_header_len) { /* 4 byte magic string + proto version * + potentially uncompressed size varint * + 1 byte varint that indicates zero-length header */ GROW_BUF(&mrg->obuf, 128); if (expect_true(mrg->protocol_version > 2)) { srl_buf_cat_str_s_nocheck(&mrg->obuf, SRL_MAGIC_STRING_HIGHBIT); } else { srl_buf_cat_str_s_nocheck(&mrg->obuf, SRL_MAGIC_STRING); } srl_buf_cat_char_nocheck(&mrg->obuf, (U8) mrg->protocol_version); if (user_header == NULL) { srl_buf_cat_char_nocheck(&mrg->obuf, '\0'); } else { if (expect_false(mrg->protocol_version < 2)) croak("Cannot serialize user header data in Sereal protocol V1 mode!"); // TODO srl_buf_cat_varint_nocheck(aTHX_ &mrg->obuf, 0, (UV) (user_header_len + 1)); /* Encode header length, +1 for bit field */ srl_buf_cat_char_nocheck(&mrg->obuf, '\1'); /* Encode bitfield */ Copy(user_header, mrg->obuf.pos, user_header_len, char); /* Copy user header data */ mrg->obuf.pos += user_header_len; } SRL_UPDATE_BODY_POS(&mrg->obuf, mrg->protocol_version); }
void srl_write_header(pTHX_ srl_encoder_t *enc) { /* 4th to 8th bit are flags. Using 4th for snappy flag. FIXME needs to go in spec. */ const U8 version_and_flags = SRL_PROTOCOL_VERSION | ( SRL_ENC_HAVE_OPTION(enc, SRL_F_COMPRESS_SNAPPY) ? SRL_PROTOCOL_ENCODING_SNAPPY : SRL_PROTOCOL_ENCODING_RAW ); /* 4 byte magic string + proto version * + potentially uncompressed size varint * + 1 byte varint that indicates zero-length header */ BUF_SIZE_ASSERT(enc, sizeof(SRL_MAGIC_STRING) + 1 + 1); srl_buf_cat_str_s_nocheck(enc, SRL_MAGIC_STRING); srl_buf_cat_char_nocheck(enc, version_and_flags); srl_buf_cat_char_nocheck(enc, '\0'); /* variable header length (0 right now) */ }
/* Code for serializing floats */ static SRL_INLINE void srl_dump_nv(pTHX_ srl_encoder_t *enc, SV *src) { NV nv= SvNV(src); float f= nv; double d= nv; if ( f == nv || nv != nv ) { BUF_SIZE_ASSERT(enc, 1 + sizeof(f)); /* heuristic: header + string + simple value */ srl_buf_cat_char_nocheck(enc,SRL_HDR_FLOAT); Copy((char *)&f, enc->pos, sizeof(f), char); enc->pos += sizeof(f); } else if (d == nv) {
/* Code for serializing floats */ SRL_STATIC_INLINE void srl_dump_nv(pTHX_ srl_encoder_t *enc, SV *src) { NV nv= SvNV(src); MS_VC6_WORKAROUND_VOLATILE float f= (float)nv; MS_VC6_WORKAROUND_VOLATILE double d= (double)nv; /* TODO: this logic could be reworked to not duplicate so much code, which will help on win32 */ if ( f == nv || nv != nv ) { BUF_SIZE_ASSERT(enc, 1 + sizeof(f)); /* heuristic: header + string + simple value */ srl_buf_cat_char_nocheck(enc,SRL_HDR_FLOAT); Copy((char *)&f, enc->pos, sizeof(f), char); enc->pos += sizeof(f); } else if (d == nv) {
srl_merger_t * srl_build_merger_struct(pTHX_ HV *opt) { srl_merger_t *mrg; SV **svp; int i; mrg = srl_empty_merger_struct(aTHX); /* load options */ if (opt != NULL) { /* Needs to be before the snappy options */ /* mrg->protocol_version defaults to SRL_PROTOCOL_VERSION. */ svp = hv_fetchs(opt, "protocol_version", 0); if (svp && SvOK(*svp)) { mrg->protocol_version = SvUV(*svp); if (mrg->protocol_version < 1 || mrg->protocol_version > SRL_PROTOCOL_VERSION) { croak("Specified Sereal protocol version ('%lu') is invalid", (unsigned long) mrg->protocol_version); } } svp = hv_fetchs(opt, "top_level_element", 0); if (svp && SvOK(*svp)) { switch (SvUV(*svp)) { case 0: /* SCALAR */ SRL_MRG_SET_OPTION(mrg, SRL_F_TOPLEVEL_KEY_SCALAR); break; case 1: /* ARRAYREF */ SRL_MRG_SET_OPTION(mrg, SRL_F_TOPLEVEL_KEY_ARRAY); break; case 2: /* HASHREF */ SRL_MRG_SET_OPTION(mrg, SRL_F_TOPLEVEL_KEY_HASH); break; default: croak("Invalid Sereal::Merger top level element"); } } svp = hv_fetchs(opt, "dedupe_strings", 0); if (svp && SvTRUE(*svp)) SRL_MRG_SET_OPTION(mrg, SRL_F_DEDUPE_STRINGS); svp = hv_fetchs(opt, "compress", 0); if (svp && SvOK(*svp)) { switch (SvIV(*svp)) { case 0: /* uncompressed */ break; case 1: /* snappy incremental */ SRL_MRG_SET_OPTION(mrg, SRL_F_COMPRESS_SNAPPY_INCREMENTAL); break; default: croak("Invalid Sereal compression format"); } } svp = hv_fetchs(opt, "max_recursion_depth", 0); if (svp && SvOK(*svp)) mrg->max_recursion_depth = SvUV(*svp); } if (mrg->protocol_version == 1) { srl_fill_header(aTHX_ mrg, NULL, 0); } else { /* Preallocate memory for buffer. * SRL_PREALLOCATE_FOR_USER_HEADER for potential user header + 100 bytes for body */ GROW_BUF(&mrg->obuf, SRL_PREALLOCATE_FOR_USER_HEADER + 100); mrg->obuf.pos = mrg->obuf.start + SRL_PREALLOCATE_FOR_USER_HEADER; SRL_UPDATE_BODY_POS(&mrg->obuf, mrg->protocol_version); } if (!SRL_MRG_HAVE_OPTION(mrg, SRL_F_TOPLEVEL_KEY_SCALAR)) { srl_buf_cat_char_nocheck(&mrg->obuf, SRL_HDR_REFN); srl_buf_cat_char_nocheck(&mrg->obuf, SRL_MRG_HAVE_OPTION(mrg, SRL_F_TOPLEVEL_KEY_HASH) ? SRL_HDR_HASH : SRL_HDR_ARRAY); mrg->obuf_padding_bytes_offset = BUF_POS_OFS(&mrg->obuf); for (i = 0; i < SRL_MAX_VARINT_LENGTH_U32; ++i) { srl_buf_cat_char_nocheck(&mrg->obuf, SRL_HDR_PAD); } } return mrg; }