| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /*
- * lws-api-test-lws_struct-json
- *
- * Written in 2010-2020 by Andy Green <[email protected]>
- *
- * This file is made available under the Creative Commons CC0 1.0
- * Universal Public Domain Dedication.
- *
- * lws_struct apis are used to serialize and deserialize your C structs and
- * linked-lists in a standardized way that's very modest on memory but
- * convenient and easy to maintain.
- *
- * This second test file shows a worked example for how to express a schema
- * and both consume JSON -> struct and struct -> JSON for it.
- */
- #include <libwebsockets.h>
- static const char * const test2_json =
- "{"
- "\"config\":["
- "{"
- "\"id1\":" "null,"
- "\"creds\":{"
- "\"key1\":" "\"\\\"xxxxxxxxx\\\"\","
- "\"key2\":" "null"
- "},"
- "\"frequency\":" "0,"
- "\"arg1\":" "\"val1\","
- "\"arg2\":" "0,"
- "\"priority\":" "1,"
- "\"ssid\":" "\"\\\"nw2\\\"\""
- "}, {"
- "\"id2\":" "null,"
- "\"creds\": {"
- "\"key1\":" "\"\\\"xxxxxxxxxxxxx\\\"\","
- "\"key2\":" "null"
- "},"
- "\"frequency\":" "11,"
- "\"arg1\":" "\"val2\","
- "\"arg2\":" "1420887242594,"
- "\"priority\":" "3,"
- "\"ssid\":" "\"\\\"nw1\\\"\""
- "}"
- "]"
- "}";
- static const char * const test2_json_expected =
- "{\"config\":[{\"creds\":{\"key1\":\"\\u0022xxxxxxxxx\\u0022\"},"
- "\"arg1\":\"val1\",\"ssid\":\"\\u0022nw2\\u0022\","
- "\"frequency\":0,\"arg2\":0,\"priority\":1},"
- "{\"creds\":{\"key1\":\"\\u0022xxxxxxxxxxxxx\\u0022\"},"
- "\"arg1\":\"val2\",\"ssid\":\"\\u0022nw1\\u0022\","
- "\"frequency\":11,\"arg2\":1420887242594,\"priority\":3}]}"
- ;
- /*
- * level 3: Credentials object
- */
- typedef struct t2_cred {
- const char *key1;
- const char *key2;
- } t2_cred_t;
- static const lws_struct_map_t lsm_t2_cred[] = {
- LSM_STRING_PTR (t2_cred_t, key1, "key1"),
- LSM_STRING_PTR (t2_cred_t, key2, "key2"),
- };
- /*
- * level 2: Configuration object, containing a child credentials object
- */
- typedef struct t2_config {
- lws_dll2_t list;
- t2_cred_t *creds;
- const char *id1;
- const char *arg1;
- const char *ssid;
- unsigned int frequency;
- unsigned long arg2;
- unsigned int priority;
- } t2_config_t;
- static const lws_struct_map_t lsm_t2_config[] = {
- LSM_CHILD_PTR (t2_config_t,
- creds, /* the child pointer member */
- t2_cred_t, /* the child type */
- NULL, lsm_t2_cred, /* map object for item type */
- "creds"), /* outer json object name */
- LSM_STRING_PTR (t2_config_t, id1, "id1"),
- LSM_STRING_PTR (t2_config_t, arg1, "arg1"),
- LSM_STRING_PTR (t2_config_t, ssid, "ssid"),
- LSM_UNSIGNED (t2_config_t, frequency, "frequency"),
- LSM_UNSIGNED (t2_config_t, arg2, "arg2"),
- LSM_UNSIGNED (t2_config_t, priority, "priority"),
- };
- /*
- * level 1: list-of-configurations object
- */
- typedef struct t2_configs {
- lws_dll2_owner_t configs;
- } t2_configs_t;
- static const lws_struct_map_t lsm_t2_configs[] = {
- LSM_LIST (t2_configs_t, configs, /* the list owner type/member */
- t2_config_t, list, /* the list item type/member */
- NULL, lsm_t2_config, /* map object for item type */
- "config"), /* outer json object name */
- };
- /*
- * For parsing, this lists the kind of object we expect to parse so the struct
- * can be allocated polymorphically.
- *
- * Lws uses an explicit "schema" member so the type is known unambiguously. If
- * in the incoming JSON the first member is not "schema", it will scan the
- * maps listed here and instantiate the first object that has a member of that
- * name.
- */
- static const lws_struct_map_t lsm_schema[] = {
- LSM_SCHEMA (t2_configs_t, NULL, lsm_t2_configs, "t2"),
- /* other schemata that might need parsing... */
- };
- static int
- t2_config_dump(struct lws_dll2 *d, void *user)
- {
- t2_config_t *c = lws_container_of(d, t2_config_t, list);
- lwsl_notice("%s: id1 '%s'\n", __func__, c->id1);
- lwsl_notice("%s: arg1 '%s'\n", __func__, c->arg1);
- lwsl_notice("%s: ssid '%s'\n", __func__, c->ssid);
- lwsl_notice("%s: freq %d\n", __func__, c->frequency);
- lwsl_notice("%s: arg2 %lu\n", __func__, c->arg2);
- lwsl_notice("%s: priority %d\n", __func__, c->priority);
- lwsl_notice("%s: key1: %s, key2: %s\n", __func__,
- c->creds->key1, c->creds->key2);
- return 0;
- }
- static int
- t2_configs_dump(t2_configs_t *t2cs)
- {
- lwsl_notice("%s: number of configs: %d\n", __func__,
- t2cs->configs.count);
- lws_dll2_foreach_safe(&t2cs->configs, NULL, t2_config_dump);
- return 0;
- }
- int
- test2(void)
- {
- lws_struct_serialize_t *ser;
- struct lejp_ctx ctx;
- lws_struct_args_t a;
- t2_configs_t *top;
- uint8_t buf[4096];
- size_t written;
- int n, bad = 1;
- lwsl_notice("%s: start \n", __func__);
- memset(&a, 0, sizeof(a));
- a.map_st[0] = lsm_schema;
- a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema);
- a.ac_block_size = 512;
- lws_struct_json_init_parse(&ctx, NULL, &a);
- n = lejp_parse(&ctx, (uint8_t *)test2_json, (int)strlen(test2_json));
- lwsl_notice("%s: lejp_parse %d\n", __func__, n);
- if (n < 0) {
- lwsl_err("%s: test2 JSON decode failed '%s'\n",
- __func__, lejp_error_to_string(n));
- goto bail;
- }
- lwsac_info(a.ac);
- top = (t2_configs_t *)a.dest; /* the top level object */
- if (!top) {
- lwsl_err("%s: no top level object\n", __func__);
- goto bail;
- }
- t2_configs_dump(top);
- /* 2. Let's reserialize the top level object and see what comes out */
- ser = lws_struct_json_serialize_create(&lsm_schema[0], 1,
- LSSERJ_FLAG_OMIT_SCHEMA, top);
- if (!ser) {
- lwsl_err("%s: unable to init serialization\n", __func__);
- goto bail;
- }
- do {
- n = lws_struct_json_serialize(ser, buf, sizeof(buf), &written);
- switch (n) {
- case LSJS_RESULT_FINISH:
- puts((const char *)buf);
- break;
- case LSJS_RESULT_CONTINUE:
- case LSJS_RESULT_ERROR:
- goto bail;
- }
- } while (n == LSJS_RESULT_CONTINUE);
- if (strcmp(test2_json_expected, (char *)buf)) {
- lwsl_err("%s: expected %s\n", __func__, test2_json_expected);
- goto bail;
- }
- lws_struct_json_serialize_destroy(&ser);
- bad = 0;
- bail:
- lwsac_free(&a.ac);
- return bad;
- }
|