aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/decode.c
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-06-25 15:33:47 +0200
committerbfredl <bjorn.linse@gmail.com>2024-06-27 11:04:04 +0200
commitbda63d5b97dfb333de6f4bd757dbb978906062a2 (patch)
tree65b2460064f42b39e33bf7bc7507f973b907dd37 /src/nvim/eval/decode.c
parent9e436251de0329b1479365ff162d87ef18d6d14c (diff)
downloadrneovim-bda63d5b97dfb333de6f4bd757dbb978906062a2.tar.gz
rneovim-bda63d5b97dfb333de6f4bd757dbb978906062a2.tar.bz2
rneovim-bda63d5b97dfb333de6f4bd757dbb978906062a2.zip
refactor(typval)!: remove distinction of binary and nonbinary strings
This is a breaking change which will make refactor of typval and shada code a lot easier. In particular, code that would use or check for v:msgpack_types.binary in the wild would be broken. This appears to be rarely used in existing plugins. Also some cases where v:msgpack_type.string would be used to represent a binary string of "string" type, we use a BLOB instead, which is vimscripts native type for binary blobs, and already was used for BIN formats when necessary. msgpackdump(msgpackparse(data)) no longer preserves the distinction of BIN and STR strings. This is very common behavior for language-specific msgpack bindings. Nvim uses msgpack as a tool to serialize its data. Nvim is not a tool to bit-perfectly manipulate arbitrary msgpack data out in the wild. The changed tests should indicate how behavior changes in various edge cases.
Diffstat (limited to 'src/nvim/eval/decode.c')
-rw-r--r--src/nvim/eval/decode.c64
1 files changed, 16 insertions, 48 deletions
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index d7df7bb150..13cd3274dd 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -247,45 +247,29 @@ list_T *decode_create_map_special_dict(typval_T *const ret_tv, const ptrdiff_t l
///
/// @param[in] s String to decode.
/// @param[in] len String length.
-/// @param[in] hasnul Whether string has NUL byte, not or it was not yet
-/// determined.
-/// @param[in] binary Determines decode type if string has NUL bytes.
-/// If true convert string to VAR_BLOB, otherwise to the
-/// kMPString special type.
+/// @param[in] force_blob whether string always should be decoded as a blob,
+/// or only when embedded NUL bytes were present
/// @param[in] s_allocated If true, then `s` was allocated and can be saved in
/// a returned structure. If it is not saved there, it
/// will be freed.
///
/// @return Decoded string.
-typval_T decode_string(const char *const s, const size_t len, const TriState hasnul,
- const bool binary, const bool s_allocated)
+typval_T decode_string(const char *const s, const size_t len, bool force_blob,
+ const bool s_allocated)
FUNC_ATTR_WARN_UNUSED_RESULT
{
assert(s != NULL || len == 0);
- const bool really_hasnul = (hasnul == kNone
- ? ((s != NULL) && (memchr(s, NUL, len) != NULL))
- : (bool)hasnul);
- if (really_hasnul) {
+ const bool use_blob = force_blob || ((s != NULL) && (memchr(s, NUL, len) != NULL));
+ if (use_blob) {
typval_T tv;
tv.v_lock = VAR_UNLOCKED;
- if (binary) {
- tv_blob_alloc_ret(&tv);
- ga_concat_len(&tv.vval.v_blob->bv_ga, s, len);
+ blob_T *b = tv_blob_alloc_ret(&tv);
+ if (s_allocated) {
+ b->bv_ga.ga_data = (void *)s;
+ b->bv_ga.ga_len = (int)len;
+ b->bv_ga.ga_maxlen = (int)len;
} else {
- list_T *const list = tv_list_alloc(kListLenMayKnow);
- tv_list_ref(list);
- create_special_dict(&tv, kMPString,
- (typval_T){ .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list } });
- const int elw_ret = encode_list_write((void *)list, s, len);
- if (s_allocated) {
- xfree((void *)s);
- }
- if (elw_ret == -1) {
- tv_clear(&tv);
- return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
- }
+ ga_concat_len(&b->bv_ga, s, len);
}
return tv;
}
@@ -405,7 +389,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
char *str = xmalloc(len + 1);
int fst_in_pair = 0;
char *str_end = str;
- bool hasnul = false;
#define PUT_FST_IN_PAIR(fst_in_pair, str_end) \
do { \
if ((fst_in_pair) != 0) { \
@@ -426,9 +409,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
uvarnumber_T ch;
vim_str2nr(ubuf, NULL, NULL,
STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4, true, NULL);
- if (ch == 0) {
- hasnul = true;
- }
if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) {
PUT_FST_IN_PAIR(fst_in_pair, str_end);
fst_in_pair = (int)ch;
@@ -476,10 +456,7 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len,
PUT_FST_IN_PAIR(fst_in_pair, str_end);
#undef PUT_FST_IN_PAIR
*str_end = NUL;
- typval_T obj = decode_string(str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
- if (obj.v_type == VAR_UNKNOWN) {
- goto parse_json_string_fail;
- }
+ typval_T obj = decode_string(str, (size_t)(str_end - str), false, true);
POP(obj, obj.v_type != VAR_STRING);
goto parse_json_string_ret;
parse_json_string_fail:
@@ -982,18 +959,8 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
};
break;
case MSGPACK_OBJECT_STR:
- *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false,
- false);
- if (rettv->v_type == VAR_UNKNOWN) {
- return FAIL;
- }
- break;
case MSGPACK_OBJECT_BIN:
- *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true,
- false);
- if (rettv->v_type == VAR_UNKNOWN) {
- return FAIL;
- }
+ *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, false, false);
break;
case MSGPACK_OBJECT_ARRAY: {
list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
@@ -1016,7 +983,8 @@ int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
}
case MSGPACK_OBJECT_MAP: {
for (size_t i = 0; i < mobj.via.map.size; i++) {
- if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
+ if ((mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
+ && mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_BIN)
|| mobj.via.map.ptr[i].key.via.str.size == 0
|| memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
mobj.via.map.ptr[i].key.via.str.size) != NULL) {