This commit is contained in:
Basile Starynkevitch 2024-03-09 19:32:22 -07:00 committed by GitHub
commit afb357ca20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 217 additions and 6 deletions

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * Copyright (c) 2009-2021 Petri Lehtinen <petri@digip.org>
* and Basile Starynkevitch <basile@starynkevitch.net>
* *
* Jansson is free software; you can redistribute it and/or modify * Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details. * it under the terms of the MIT license. See LICENSE for details.
@ -35,6 +36,207 @@ struct buffer {
char *data; char *data;
}; };
struct attribute_flag_entry {
const char* attr_key;
size_t attr_flags;
};
struct attribute_flag_table_st {
unsigned atflag_size; /* allocated size of atflag_entries */
unsigned atflag_count; /* counting number of used entries */
struct attribute_flag_entry atflag_entries[]; /* flexible array member */
};
static struct attribute_flag_table_st* attribute_flag_hashtable;
static unsigned atflag_hash(const char*atkey)
{
/* NB: most of the decimal integer constants here are prime numbers. */
unsigned kl = (unsigned)strlen(atkey);
unsigned h1 = 17*kl+3;
unsigned h2 = 0;
unsigned h = 0;
for (unsigned i=0; i<kl; i++) {
if (i%2 == 0) {
unsigned nh1 = (h1*31 + i) ^ (atkey[i]*1471 + h2);
unsigned nh2 = h2*11 + (h1&0xfff) - atkey[i]*13;
h1 = nh1;
h2 = nh2;
}
else {
unsigned nh1 = (h1*53 - i) ^ (atkey[i]*1181 + 7*h2);
unsigned nh2 = h2*89 - (h1&0xffff) + atkey[i]*67;
h1 = nh1;
h2 = nh2;
}
};
h = h1 ^ h2;
if (h==0) {
h = h1?h1:11;
}
/* h is never 0 */
return h;
}
static struct attribute_flag_entry*
attr_flag_find(const char*atkey)
{
unsigned h=0, hsiz=0;
if (!atkey || !atkey[0])
return NULL;
if (!attribute_flag_hashtable)
return NULL;
h = atflag_hash(atkey);
hsiz = attribute_flag_hashtable->atflag_size;
for (unsigned ix = h % hsiz; ix < hsiz; ix++)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key)
return NULL;
if (!strcmp(curent->attr_key, atkey))
return curent;
};
for (int ix = (int)h % hsiz; ix >= 0; ix--)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key)
return NULL;
if (!strcmp(curent->attr_key, atkey))
return curent;
};
return NULL;
}
static struct attribute_flag_entry*
attr_flag_really_put(const char*atkey, size_t atflags)
{
unsigned h = 0, hsiz = 0;
if (!atkey || !atkey[0]) return NULL;
if (!attribute_flag_hashtable)
return NULL;
h = atflag_hash(atkey);
hsiz = attribute_flag_hashtable->atflag_size;
for (unsigned ix = h % hsiz; ix < hsiz; ix++)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
attribute_flag_hashtable->atflag_count++;
return curent;
}
if (!strcmp(curent->attr_key, atkey)) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
return curent;
}
};
for (int ix = (int)h % hsiz; ix >= 0; ix--)
{
struct attribute_flag_entry*curent
= attribute_flag_hashtable->atflag_entries + ix;
if (!curent->attr_key) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
attribute_flag_hashtable->atflag_count++;
return curent;
}
if (!strcmp(curent->attr_key, atkey)) {
curent->attr_key = atkey;
curent->attr_flags = atflags;
return curent;
}
};
return NULL;
}
// an array of primes, gotten with something similar to
// /usr/games/primes 3 | awk '($1>p+p/9){print $1, ","; p=$1}'
static const unsigned primes_array[] = {
29, 37, 43, 53, 59, 67, 79, 89, 101, 113,
127, 149, 167, 191, 223, 251, 281, 313, 349, 389, 433, 487, 547, 613,
683, 761, 853, 953, 1061, 1181, 1319, 1471, 1637, 1823, 2027, 2267,
2521, 2803, 3119, 3467, 3853, 4283, 4759, 5297, 5897, 6553, 7283, 8093,
8999, 10007, 11119, 12373, 13751, 15287, 16987, 18899, 21001, 23339,
25933, 28817, 32027, 35591, 39551, 43951, 48847, 54277, 60317, 67021,
74471, 82757, 91957, 102181, 113537, 126173, 140197, 155777, 173087,
192319, 213713, 237467, 263863, 293201, 325781, 361979, 402221, 446921,
496579, 551767, 613097, 681221, 756919, 841063, 934517, 1038383, 1153759,
1281961, 1424407, 1582697, 1758553, 1953949, 2171077, 2412323, 2680367,
2978189, 3309107, 3676789, 4085339, 4539277, 5043653, 5604073, 6226757,
6918619, 7687387, 8541551, 9490631, 10545167, 11716879, 13018757,
14465291, 16072547, 17858389, 19842659, 22047401, 24497113, 27219019,
30243359, 33603743, 37337497, 41486111, 46095719, 51217477, 56908337,
63231499, 70257241, 78063641, 86737379, 96374881, 107083213, 118981367,
132201521, 146890631, 163211821, 181346479, 201496157, 223884629,
248760703, 276400823, 307112027, 341235667, 379150777, 421278643,
468087391, 520097111, 577885681, 642095213, 713439127, 792710159,
880789067, 978654533, 1087393949, 1208215531, 1342461719, 1491624137,
1657360153, 1841511311, 2046123679, 2273470799, 2526078691, 2806754123,
0
};
/* feature request #595 : https://github.com/akheron/jansson/issues/595 */
void
json_register_dump_attribute_flag(const char*attrname, size_t attrflags)
{
unsigned ix;
if (!attrname || !attrname[0])
return;
if (!attribute_flag_hashtable) {
unsigned initsiz = 29;
size_t bytsiz = sizeof(struct attribute_flag_table_st) + initsiz * sizeof(struct attribute_flag_entry);
void *ptr = jsonp_malloc(bytsiz);
if (!ptr)
return;
memset (ptr, 0, bytsiz);
attribute_flag_hashtable = ptr;
attribute_flag_hashtable->atflag_size = initsiz;
}
else if (attribute_flag_hashtable->atflag_size * 4 < attribute_flag_hashtable->atflag_count * 3) {
struct attribute_flag_table_st*oldtable = attribute_flag_hashtable;
unsigned newsiz = 4 * attribute_flag_hashtable->atflag_count / 3 + 17;
unsigned lowix = 0;
unsigned highix = sizeof(primes_array)/sizeof(primes_array[0]) - 1;
size_t bytsiz=0;
unsigned oldsiz=0;
void*ptr = NULL;
while (lowix + 4 < highix) {
unsigned midix = (lowix+highix)/2;
if (primes_array[midix] < lowix)
lowix = midix;
else highix = midix;
};
for (ix = lowix; ix<highix; ix++)
if (primes_array[ix] >= newsiz) {
newsiz = primes_array[ix];
break;
};
ptr = jsonp_malloc(bytsiz);
if (!ptr)
return;
memset (ptr, 0, bytsiz);
attribute_flag_hashtable = ptr;
attribute_flag_hashtable->atflag_size = newsiz;
oldsiz = oldtable->atflag_size;
for (unsigned oldix = 0; oldix < oldsiz; oldix++) {
struct attribute_flag_entry*oldent
= oldtable->atflag_entries + oldix;
if (oldent->attr_key)
attr_flag_really_put(oldent->attr_key, oldent->attr_flags);
};
jsonp_free(oldtable);
};
attr_flag_really_put(attrname, attrflags);
}
static int dump_to_strbuffer(const char *buffer, size_t size, void *data) { static int dump_to_strbuffer(const char *buffer, size_t size, void *data) {
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
} }
@ -359,12 +561,15 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
const struct key_len *key; const struct key_len *key;
json_t *value; json_t *value;
struct attribute_flag_entry*atent=NULL;
key = &keys[i]; key = &keys[i];
value = json_object_getn(json, key->key, key->len); value = json_object_getn(json, key->key, key->len);
assert(value); assert(value);
assert(key->key[key->len]==(char)0);
atent= attr_flag_find(key->key);
dump_string(key->key, key->len, dump, data, flags); dump_string(key->key, key->len, dump, data, flags);
if (atent)
flags |= atent->attr_flags;
if (dump(separator, separator_length, data) || if (dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, parents, dump, data)) { do_dump(value, flags, depth + 1, parents, dump, data)) {
jsonp_free(keys); jsonp_free(keys);
@ -393,8 +598,10 @@ static int do_dump(const json_t *json, size_t flags, int depth, hashtable_t *par
void *next = json_object_iter_next((json_t *)json, iter); void *next = json_object_iter_next((json_t *)json, iter);
const char *key = json_object_iter_key(iter); const char *key = json_object_iter_key(iter);
const size_t key_len = json_object_iter_key_len(iter); const size_t key_len = json_object_iter_key_len(iter);
struct attribute_flag_entry*atent= attr_flag_find(key);
dump_string(key, key_len, dump, data, flags); dump_string(key, key_len, dump, data, flags);
if (atent)
flags |= atent->attr_flags;
if (dump(separator, separator_length, data) || if (dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1, parents, do_dump(json_object_iter_value(iter), flags, depth + 1, parents,
dump, data)) dump, data))

View File

@ -21,11 +21,11 @@ extern "C" {
/* version */ /* version */
#define JANSSON_MAJOR_VERSION 2 #define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 14 #define JANSSON_MINOR_VERSION 15
#define JANSSON_MICRO_VERSION 0 #define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */ /* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.14" #define JANSSON_VERSION "2.15"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@ -407,6 +407,10 @@ typedef void (*json_free_t)(void *);
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn); void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn);
/* feature request #595 : https://github.com/akheron/jansson/issues/595 */
void json_register_dump_attribute_flag(const char*attrname, size_t attrflags);
/* runtime version checking */ /* runtime version checking */
const char *jansson_version_str(void); const char *jansson_version_str(void);