UV srl_iterator_stack_info(pTHX_ srl_iterator_t *iter, UV *length_ptr) { UV type = 0; srl_stack_t *stack = iter->pstack; srl_iterator_stack_ptr stack_ptr = stack->ptr; SRL_ITER_ASSERT_STACK(iter); if (length_ptr) *length_ptr = stack_ptr->count; switch (stack_ptr->tag) { case SRL_ITER_STACK_ROOT_TAG: type = SRL_ITERATOR_OBJ_IS_ROOT; break; case SRL_HDR_HASH: CASE_SRL_HDR_HASHREF: type = SRL_ITERATOR_OBJ_IS_HASH; break; case SRL_HDR_ARRAY: CASE_SRL_HDR_ARRAYREF: type = SRL_ITERATOR_OBJ_IS_ARRAY; break; default: SRL_RDR_ERROR_UNEXPECTED(iter->pbuf, stack_ptr->tag, "ARRAY or HASH"); } return type; }
UV srl_iterator_object_info(pTHX_ srl_iterator_t *iter, UV *length_ptr) { U8 tag; UV offset, type = 0; srl_reader_char_ptr orig_pos = iter->buf.pos; DEBUG_ASSERT_RDR_SANE(iter->pbuf); if (length_ptr) *length_ptr = 0; read_again: SRL_ITER_ASSERT_EOF(iter, "serialized object"); tag = *iter->buf.pos & ~SRL_HDR_TRACK_FLAG; SRL_ITER_REPORT_TAG(iter, tag); iter->buf.pos++; switch (tag) { case SRL_HDR_PAD: case SRL_HDR_REFN: case SRL_HDR_WEAKEN: /* advanced pointer to the object */ goto read_again; case SRL_HDR_HASH: type = SRL_ITERATOR_OBJ_IS_HASH; if (length_ptr) *length_ptr = srl_read_varint_uv_count(aTHX_ iter->pbuf, " while reading HASH"); break; CASE_SRL_HDR_HASHREF: type = SRL_ITERATOR_OBJ_IS_HASH; if (length_ptr) *length_ptr = SRL_HDR_HASHREF_LEN_FROM_TAG(tag); break; case SRL_HDR_ARRAY: type = SRL_ITERATOR_OBJ_IS_ARRAY; if (length_ptr) *length_ptr = srl_read_varint_uv_count(aTHX_ iter->pbuf, " while reading ARRAY"); break; CASE_SRL_HDR_ARRAYREF: type = SRL_ITERATOR_OBJ_IS_ARRAY; if (length_ptr) *length_ptr = SRL_HDR_ARRAYREF_LEN_FROM_TAG(tag); break; CASE_SRL_HDR_POS: CASE_SRL_HDR_NEG: CASE_SRL_HDR_SHORT_BINARY: case SRL_HDR_BINARY: case SRL_HDR_STR_UTF8: case SRL_HDR_VARINT: case SRL_HDR_ZIGZAG: case SRL_HDR_FLOAT: case SRL_HDR_DOUBLE: case SRL_HDR_LONG_DOUBLE: case SRL_HDR_TRUE: case SRL_HDR_FALSE: case SRL_HDR_UNDEF: case SRL_HDR_CANONICAL_UNDEF: type = SRL_ITERATOR_OBJ_IS_SCALAR; break; case SRL_HDR_REFP: case SRL_HDR_COPY: offset = srl_read_varint_uv_offset(aTHX_ iter->pbuf, " while reading COPY tag"); iter->buf.pos = iter->buf.body_pos + offset; goto read_again; default: iter->buf.pos = orig_pos; SRL_RDR_ERROR_UNEXPECTED(iter->pbuf, tag, "ARRAY or HASH or SCALAR"); } iter->buf.pos = orig_pos; DEBUG_ASSERT_RDR_SANE(iter->pbuf); return type; }
IV srl_iterator_hash_exists(pTHX_ srl_iterator_t *iter, const char *name, STRLEN name_len) { U8 tag; UV length, offset; const char *key_ptr; IV stack_depth = iter->stack.depth; srl_iterator_stack_ptr stack_ptr = iter->stack.ptr; DEBUG_ASSERT_RDR_SANE(iter->pbuf); SRL_ITER_ASSERT_EOF(iter, "stringish"); SRL_ITER_ASSERT_STACK(iter); SRL_ITER_ASSERT_HASH_ON_STACK(iter); SRL_ITER_TRACE("name=%.*s", (int) name_len, name); SRL_ITER_REPORT_STACK_STATE(iter); while (stack_ptr->idx) { stack_ptr->idx--; // do not make it be part of while clause SRL_ITER_ASSERT_STACK(iter); assert(stack_ptr->idx % 2 == 1); assert(iter->stack.depth == stack_depth); DEBUG_ASSERT_RDR_SANE(iter->pbuf); tag = *iter->buf.pos & ~SRL_HDR_TRACK_FLAG; SRL_ITER_REPORT_TAG(iter, tag); iter->buf.pos++; switch (tag) { CASE_SRL_HDR_SHORT_BINARY: length = SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag); key_ptr = (const char *) iter->buf.pos; iter->buf.pos += length; break; case SRL_HDR_BINARY: length = srl_read_varint_uv_length(aTHX_ iter->pbuf, " while reading BINARY"); key_ptr = (const char *) iter->buf.pos; iter->buf.pos += length; break; case SRL_HDR_STR_UTF8: // TODO deal with UTF8 length = srl_read_varint_uv_length(aTHX_ iter->pbuf, " while reading STR_UTF8"); key_ptr = (const char *) iter->buf.pos; iter->buf.pos += length; break; case SRL_HDR_COPY: offset = srl_read_varint_uv_offset(aTHX_ iter->pbuf, " while reading COPY tag"); key_ptr = (const char *) iter->buf.body_pos + offset; tag = *key_ptr & ~SRL_HDR_TRACK_FLAG; key_ptr++; /* Note we do NOT validate these items, as we have already read them * and if they were a problem we would not be here to process them! */ switch (tag) { CASE_SRL_HDR_SHORT_BINARY: length = SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag); break; case SRL_HDR_BINARY: SET_UV_FROM_VARINT(iter->pbuf, length, key_ptr); break; case SRL_HDR_STR_UTF8: // TODO deal with UTF8 SET_UV_FROM_VARINT(iter->pbuf, length, key_ptr); break; default: SRL_RDR_ERROR_BAD_COPY(iter->pbuf, SRL_HDR_HASH); } break; default: SRL_RDR_ERROR_UNEXPECTED(iter->pbuf, tag, "stringish"); } if (expect_false((srl_reader_char_ptr) key_ptr >= iter->buf.end)) { SRL_RDR_ERROR_EOF(iter->pbuf, "string content"); } if ( length == name_len && memcmp(name, key_ptr, name_len) == 0) { SRL_ITER_TRACE("found key '%.*s' at offset %"UVuf, (int) name_len, name, SRL_RDR_BODY_POS_OFS(iter->pbuf)); return SRL_RDR_BODY_POS_OFS(iter->pbuf); } // srl_iterator_next garantee that we remans on current stack srl_iterator_next(aTHX_ iter, 1); stack_ptr = iter->stack.ptr; } SRL_ITER_TRACE("didn't found key '%.*s'", (int) name_len, name); return SRL_ITER_NOT_FOUND; }
const char * srl_iterator_hash_key(pTHX_ srl_iterator_t *iter, STRLEN *len_out) { U8 tag; UV length, offset; const char *result = NULL; srl_reader_char_ptr orig_pos = iter->buf.pos; *len_out = 0; DEBUG_ASSERT_RDR_SANE(iter->pbuf); SRL_ITER_ASSERT_EOF(iter, "stringish"); SRL_ITER_ASSERT_STACK(iter); SRL_ITER_ASSERT_HASH_ON_STACK(iter); tag = *iter->buf.pos & ~SRL_HDR_TRACK_FLAG; SRL_ITER_REPORT_TAG(iter, tag); iter->buf.pos++; switch (tag) { CASE_SRL_HDR_SHORT_BINARY: length = SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag); break; case SRL_HDR_BINARY: length = srl_read_varint_uv_length(aTHX_ iter->pbuf, " while reading BINARY"); break; case SRL_HDR_STR_UTF8: // TODO deal with UTF8 length = srl_read_varint_uv_length(aTHX_ iter->pbuf, " while reading STR_UTF8"); break; case SRL_HDR_COPY: offset = srl_read_varint_uv_offset(aTHX_ iter->pbuf, " while reading COPY tag"); iter->buf.pos = iter->buf.body_pos + offset; /* Note we do NOT validate these items, as we have already read them * and if they were a problem we would not be here to process them! */ tag = *iter->buf.pos & ~SRL_HDR_TRACK_FLAG; SRL_ITER_REPORT_TAG(iter, tag); iter->buf.pos++; switch (tag) { CASE_SRL_HDR_SHORT_BINARY: length = SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag); break; case SRL_HDR_BINARY: SET_UV_FROM_VARINT(iter->pbuf, length, iter->buf.pos); break; case SRL_HDR_STR_UTF8: // TODO deal with UTF8 SET_UV_FROM_VARINT(iter->pbuf, length, iter->buf.pos); break; default: SRL_RDR_ERROR_BAD_COPY(iter->pbuf, SRL_HDR_HASH); } break; default: SRL_RDR_ERROR_UNEXPECTED(iter->pbuf, tag, "stringish"); } if (expect_false(iter->buf.pos + length >= iter->buf.end)) { SRL_RDR_ERROR_EOF(iter->pbuf, "string content"); } *len_out = length; result = (const char *) iter->buf.pos; iter->buf.pos = orig_pos; // restore original position DEBUG_ASSERT_RDR_SANE(iter->pbuf); return result; }
SRL_STATIC_INLINE void srl_merge_single_value(pTHX_ srl_merger_t *mrg) { U8 tag; UV length, offset; ptable_entry_ptr ptable_entry; read_again: assert(mrg->recursion_depth >= 0); DEBUG_ASSERT_RDR_SANE(mrg->pibuf); DEBUG_ASSERT_BUF_SANE(&mrg->obuf); if (expect_false(++mrg->recursion_depth > mrg->max_recursion_depth)) SRL_RDR_ERRORf1(mrg->pibuf, "Reached recursion limit (%lu) during merging", mrg->max_recursion_depth); ptable_entry = NULL; if (expect_false(SRL_RDR_DONE(mrg->pibuf))) SRL_RDR_ERROR(mrg->pibuf, "Unexpected termination of input buffer"); tag = *mrg->ibuf.pos & ~SRL_HDR_TRACK_FLAG; SRL_REPORT_CURRENT_TAG(mrg, tag); if (mrg->tracked_offsets && !srl_stack_empty(mrg->tracked_offsets)) { UV itag_offset = SRL_RDR_BODY_POS_OFS(mrg->pibuf); if (expect_false(itag_offset == srl_stack_peek_nocheck(aTHX_ mrg->tracked_offsets))) { // trackme case srl_stack_pop_nocheck(mrg->tracked_offsets); ptable_entry = srl_store_tracked_offset(aTHX_ mrg, itag_offset, BODY_POS_OFS(&mrg->obuf)); } } if (tag <= SRL_HDR_NEG_HIGH) { srl_buf_cat_tag_nocheck(mrg, tag); } else if (tag >= SRL_HDR_ARRAYREF_LOW && tag <= SRL_HDR_ARRAYREF_HIGH) { srl_merge_array(aTHX_ mrg, tag, SRL_HDR_ARRAYREF_LEN_FROM_TAG(tag)); } else if (tag >= SRL_HDR_HASHREF_LOW && tag <= SRL_HDR_HASHREF_HIGH) { srl_merge_hash(aTHX_ mrg, tag, SRL_HDR_HASHREF_LEN_FROM_TAG(tag)); } else if (tag >= SRL_HDR_SHORT_BINARY_LOW) { srl_merge_short_binary(aTHX_ mrg, tag, ptable_entry); } else { switch (tag) { case SRL_HDR_VARINT: case SRL_HDR_ZIGZAG: srl_buf_cat_tag_nocheck(mrg, tag); srl_copy_varint(aTHX_ mrg); break; case SRL_HDR_FLOAT: srl_buf_copy_content_nocheck(aTHX_ mrg, 5); break; case SRL_HDR_DOUBLE: srl_buf_copy_content_nocheck(aTHX_ mrg, 9); break; case SRL_HDR_LONG_DOUBLE: srl_buf_copy_content_nocheck(aTHX_ mrg, 17); break; case SRL_HDR_TRUE: case SRL_HDR_FALSE: case SRL_HDR_UNDEF: case SRL_HDR_CANONICAL_UNDEF: srl_buf_cat_tag_nocheck(mrg, tag); break; case SRL_HDR_BINARY: case SRL_HDR_STR_UTF8: srl_merge_binary_utf8(aTHX_ mrg, ptable_entry); break; case SRL_HDR_HASH: mrg->ibuf.pos++; // skip tag in input buffer length = srl_read_varint_uv_count(aTHX_ mrg->pibuf, " while reading ARRAY or HASH"); srl_merge_hash(aTHX_ mrg, tag, length); break; case SRL_HDR_ARRAY: mrg->ibuf.pos++; // skip tag in input buffer length = srl_read_varint_uv_count(aTHX_ mrg->pibuf, " while reading ARRAY or HASH"); srl_merge_array(aTHX_ mrg, tag, length); break; default: switch (tag) { case SRL_HDR_COPY: case SRL_HDR_REFP: case SRL_HDR_ALIAS: mrg->ibuf.pos++; // skip tag in input buffer offset = srl_read_varint_uv_offset(aTHX_ mrg->pibuf, " while reading COPY/ALIAS/REFP"); offset = srl_lookup_tracked_offset(aTHX_ mrg, offset); // convert ibuf offset to obuf offset srl_buf_cat_varint(aTHX_ &mrg->obuf, tag, offset); if (tag == SRL_HDR_REFP || tag == SRL_HDR_ALIAS) { SRL_SET_TRACK_FLAG(*(mrg->obuf.body_pos + offset)); } break; case SRL_HDR_REFN: case SRL_HDR_WEAKEN: case SRL_HDR_EXTEND: srl_buf_cat_tag_nocheck(mrg, tag); goto read_again; case SRL_HDR_OBJECT: case SRL_HDR_OBJECT_FREEZE: srl_merge_object(aTHX_ mrg, tag); break; case SRL_HDR_REGEXP: srl_buf_cat_tag_nocheck(mrg, tag); srl_merge_stringish(aTHX_ mrg); tag = *mrg->ibuf.pos; if (expect_false(tag < SRL_HDR_SHORT_BINARY_LOW)) SRL_RDR_ERROR_UNEXPECTED(mrg->pibuf, tag, "SRL_HDR_SHORT_BINARY"); srl_buf_copy_content_nocheck(aTHX_ mrg, SRL_HDR_SHORT_BINARY_LEN_FROM_TAG(tag) + 1); break; case SRL_HDR_OBJECTV: case SRL_HDR_OBJECTV_FREEZE: mrg->ibuf.pos++; // skip tag in input buffer offset = srl_read_varint_uv_offset(aTHX_ mrg->pibuf, " while reading OBJECTV/OBJECTV_FREEZE"); offset = srl_lookup_tracked_offset(aTHX_ mrg, offset); // convert ibuf offset to obuf offset srl_buf_cat_varint(aTHX_ &mrg->obuf, tag, offset); goto read_again; case SRL_HDR_PAD: while (SRL_RDR_NOT_DONE(mrg->pibuf) && *mrg->ibuf.pos == SRL_HDR_PAD) { srl_buf_cat_tag_nocheck(mrg, SRL_HDR_PAD); } goto read_again; default: SRL_RDR_ERROR_UNIMPLEMENTED(mrg->pibuf, tag, ""); break; } } } --mrg->recursion_depth; DEBUG_ASSERT_RDR_SANE(mrg->pibuf); DEBUG_ASSERT_BUF_SANE(&mrg->obuf); }