mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
lws_struct
lws_struct JSON + sqlite3 serializer and deserializer See READMEs/README.lws_struct.md
This commit is contained in:
parent
0850231a09
commit
38fb0e31da
22 changed files with 2659 additions and 532 deletions
|
@ -101,6 +101,8 @@ option(LWS_WITHOUT_DAEMONIZE "Don't build the daemonization api" ON)
|
|||
option(LWS_SSL_SERVER_WITH_ECDH_CERT "Include SSL server use ECDH certificate" OFF)
|
||||
option(LWS_WITH_LEJP "With the Lightweight JSON Parser" ON)
|
||||
option(LWS_WITH_SQLITE3 "Require SQLITE3 support" OFF)
|
||||
option(LWS_WITH_STRUCT_JSON "Generic struct serialization to and from JSON" ON)
|
||||
option(LWS_WITH_STRUCT_SQLITE3 "Generic struct serialization to and from SQLITE3" OFF)
|
||||
option(LWS_WITH_SMTP "Provide SMTP support" OFF)
|
||||
if (WIN32 OR LWS_WITH_ESP32)
|
||||
option(LWS_WITH_DIR "Directory scanning api support" OFF)
|
||||
|
@ -189,6 +191,10 @@ if (NOT LWS_WITH_NETWORK)
|
|||
set(LWS_WITH_POLL 0)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_STRUCT_SQLITE3)
|
||||
set(LWS_WITH_SQLITE3 1)
|
||||
endif()
|
||||
|
||||
# do you care about this? Then send me a patch where it disables it on travis
|
||||
# but allows it on APPLE
|
||||
if (APPLE)
|
||||
|
@ -898,7 +904,10 @@ set(HDR_PUBLIC
|
|||
|
||||
set(SOURCES
|
||||
lib/core/alloc.c
|
||||
lib/core/buflist.c
|
||||
lib/core/context.c
|
||||
lib/core/lws_dll.c
|
||||
lib/core/lws_dll2.c
|
||||
lib/core/libwebsockets.c
|
||||
lib/core/logs.c
|
||||
lib/misc/base64-decode.c
|
||||
|
@ -1020,6 +1029,16 @@ if (LWS_WITH_DISKCACHE)
|
|||
lib/misc/diskcache.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_STRUCT_JSON)
|
||||
list(APPEND SOURCES
|
||||
lib/misc/lws-struct-lejp.c)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_STRUCT_SQLITE3)
|
||||
list(APPEND SOURCES
|
||||
lib/misc/lws-struct-sqlite.c)
|
||||
endif()
|
||||
|
||||
if (NOT LWS_WITHOUT_CLIENT)
|
||||
list(APPEND SOURCES
|
||||
lib/core-net/connect.c
|
||||
|
|
38
READMEs/README.lws_struct.md
Normal file
38
READMEs/README.lws_struct.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# lws_struct
|
||||
|
||||
## Overview
|
||||
|
||||
lws_struct provides a lightweight method for serializing and deserializing C
|
||||
structs to and from JSON, and to and from sqlite3.
|
||||
|
||||

|
||||
|
||||
- you provide a metadata array describing struct members one-time, then call
|
||||
generic apis to serialize and deserialize
|
||||
|
||||
- supports flat structs, single child struct pointers, and unbounded arrays /
|
||||
linked-lists of child objects automatically using [lws_dll2 linked-lists](./README.lws_dll.md)
|
||||
|
||||
- supports boolean and C types char, int, long, long long in explicitly signed
|
||||
and unsigned forms
|
||||
|
||||
- supports both char * type string members where the unbounded content is
|
||||
separate and pointed to, and fixed length char array[] type members where
|
||||
the content is part of the struct
|
||||
|
||||
- huge linear strings are supported by storing to a temp lwsac of chained chunks,
|
||||
which is written into a single linear chunk in the main lwsac once the
|
||||
total string length is known
|
||||
|
||||
- deserialization allocates into an [lwsac](../lib/misc/lwsac/README.md), so everything is inside as few
|
||||
heap allocations as possible while still able to expand to handle arbitrary
|
||||
array or strins sizes
|
||||
|
||||
- when deserialized structs are finished with, a single call to free the
|
||||
lwsac frees the whole thing without having to walk it
|
||||
|
||||
- stateful serializaton and deserialization allows as-you-get packets incremental
|
||||
parsing and production of chunks of as-you-can-send incremental serialization
|
||||
output cleanly
|
||||
|
||||
## Examples
|
|
@ -116,6 +116,8 @@
|
|||
#cmakedefine LWS_WITH_SOCKS5
|
||||
#cmakedefine LWS_WITH_STATEFUL_URLDECODE
|
||||
#cmakedefine LWS_WITH_STATS
|
||||
#cmakedefine LWS_WITH_STRUCT_SQLITE3
|
||||
#cmakedefine LWS_WITH_SQLITE3
|
||||
#cmakedefine LWS_WITH_THREADPOOL
|
||||
#cmakedefine LWS_WITH_TLS
|
||||
#cmakedefine LWS_WITH_UNIX_SOCK
|
||||
|
|
62
doc-assets/lws_struct-overview.svg
Normal file
62
doc-assets/lws_struct-overview.svg
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="258.28mm" height="107.81mm" version="1.1" viewBox="0 0 258.28 107.81" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<marker id="a" overflow="visible" orient="auto">
|
||||
<path transform="matrix(.2 0 0 .2 1.2 0)" d="m0 0 5-5-17.5 5 17.5 5z" fill-rule="evenodd" stroke="#000" stroke-width="1pt"/>
|
||||
</marker>
|
||||
<marker id="e" overflow="visible" orient="auto">
|
||||
<path transform="matrix(-.3 0 0 -.3 .69 0)" d="m8.7186 4.0337-10.926-4.0177 10.926-4.0177c-1.7455 2.3721-1.7354 5.6175-6e-7 8.0354z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="b" overflow="visible" orient="auto">
|
||||
<path transform="matrix(.2 0 0 .2 1.2 0)" d="m0 0 5-5-17.5 5 17.5 5z" fill-rule="evenodd" stroke="#000" stroke-width="1pt"/>
|
||||
</marker>
|
||||
<marker id="f" overflow="visible" orient="auto">
|
||||
<path transform="matrix(-.3 0 0 -.3 .69 0)" d="m8.7186 4.0337-10.926-4.0177 10.926-4.0177c-1.7455 2.3721-1.7354 5.6175-6e-7 8.0354z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="c" overflow="visible" orient="auto">
|
||||
<path transform="matrix(.2 0 0 .2 1.2 0)" d="m0 0 5-5-17.5 5 17.5 5z" fill-rule="evenodd" stroke="#000" stroke-width="1pt"/>
|
||||
</marker>
|
||||
<marker id="g" overflow="visible" orient="auto">
|
||||
<path transform="matrix(-.3 0 0 -.3 .69 0)" d="m8.7186 4.0337-10.926-4.0177 10.926-4.0177c-1.7455 2.3721-1.7354 5.6175-6e-7 8.0354z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<filter id="d" x="-.03148" y="-.082687" width="1.063" height="1.1654" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="1.2468962"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g transform="translate(751.29 58.975)">
|
||||
<g>
|
||||
<rect transform="matrix(2.5561 0 0 2.5561 1169.1 91.771)" x="-748.3" y="-55.983" width="95.061" height="36.191" filter="url(#d)"/>
|
||||
<rect x="-744.61" y="-52.171" width="242.99" height="92.508" fill="#fff"/>
|
||||
<circle cx="-715.52" cy="-2.6399" r="13.375" fill="#d4aa00"/>
|
||||
<text x="-715.49457" y="-0.013140791" dominant-baseline="auto" fill="#000000" font-family="'Open Sans Condensed'" font-size="9.0174px" letter-spacing="0px" stroke-width=".6763" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-715.49457" y="-0.013140791" stroke-width=".6763">sqlite</tspan></text>
|
||||
<circle cx="-671.6" cy="-2.9116" r="13.375" fill="#b3b3b3"/>
|
||||
<text x="-671.56494" y="-0.28489438" dominant-baseline="auto" fill="#000000" font-family="'Open Sans Condensed'" font-size="9.0174px" letter-spacing="0px" stroke-width=".6763" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-671.56494" y="-0.28489438" stroke-width=".6763">C structs</tspan></text>
|
||||
<circle cx="-627.82" cy="-2.67" r="13.375" fill="#aad400"/>
|
||||
</g>
|
||||
<g fill="#000000" font-family="'Open Sans Condensed'" font-size="9.0174px" letter-spacing="0px" stroke-width=".6763" text-anchor="middle" word-spacing="0px">
|
||||
<text x="-627.78656" y="-0.043329135" dominant-baseline="auto" text-align="center" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-627.78656" y="-0.043329135" stroke-width=".6763">JSON</tspan></text>
|
||||
<text x="-627.64801" y="21.166273" dominant-baseline="auto" text-align="center" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-627.64801" y="21.166273" stroke-width=".6763">transit</tspan></text>
|
||||
<text x="-716.26086" y="21.211004" dominant-baseline="auto" text-align="center" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-716.26086" y="21.211004" stroke-width=".6763">storage</tspan></text>
|
||||
<text x="-672.80682" y="20.817616" dominant-baseline="auto" text-align="center" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-672.80682" y="20.817616" stroke-width=".6763">processing</tspan></text>
|
||||
</g>
|
||||
<g fill="none" stroke="#000" stroke-width="1.7147">
|
||||
<path d="m-699.88-2.5175 13.015-0.1388" marker-end="url(#g)" marker-start="url(#c)" stroke-dasharray="3.42934834, 1.71467418"/>
|
||||
<path d="m-655.78-2.6715 13.015-0.1388" marker-end="url(#f)" marker-start="url(#b)"/>
|
||||
<path d="m-611.7-3.5168 13.015-0.1388" marker-end="url(#e)" marker-start="url(#a)"/>
|
||||
</g>
|
||||
<g transform="matrix(.98084 0 0 .98084 -621.3 237.27)" fill="#000080" opacity=".244">
|
||||
<path d="m41.881-252.66c-0.74224 2.5432-0.89347 6.2107 2.3684 9.2701"/>
|
||||
<path d="m53.529-227.18c6.6092-4.0094 3.4326-11.99-0.99884-13.439-1.8556-0.60663-5.8343 0.0294-7.9178 3.1773-0.58269 0.88034-2.1307 3.9439-0.48031 5.5996 2.9809 2.6693 5.6161 0.56537 5.3608-1.4101-0.21066-1.6304-2.5195-2.2246-3.5161-0.16091-0.25975-2.8413 3.6465-3.1988 4.5934-2.4826 3.041 2.3001 1.5823 6.4615 1.0276 7.1414-0.73173 0.89688-3.6971 3.6214-8.2393 0.56437-6.8298-5.655-0.13193-11.313 3.866-12.476 6.1028-2.0341 9.0102 1.5223 10.671 3.6144 3.6868 4.6452 1.9809 8.9627 5.3505 13.525 1.9595 3.128 7.9821 3.7261 11.158 0.60173 5.5288-6.1445 3.3332-13.229-1.2516-13.479-0.22801-0.0125-2.9101-0.63086-4.4241 2.3627-1.0649 2.794 4e-3 3.8072 0.81726 4.1078 2.9088 0.79976 4.5016-5.174 0.82228-3.1128 4.8236-4.2183 5.2182 0.96693 5.0018 2.2308-0.80165 5.564-9.3442 7.4818-10.819 2.8668-0.35205-0.62503-1.4338-5.0762 3.9067-8.1954 5.5765-3.6326 13.211 5.2134 17.982 5.8918 10.106 1.6835 14.307-6.6479 10.856-12.582-1.2554-1.7669-2.8684-3.5441-5.7068-3.7758-6.1109-0.17391-9.2141 3.4739-7.9593 8.2436 1.3959 2.9346 4.6564 2.9335 5.6551 2.6689 10.271-4.9733-4.2693-8.9086-0.87901-1.2245-4.8802-3.8972 0.63964-7.5993 4.4048-6.1991 0.96063 0.35724 5.1803 5.0648-0.05897 9.3556-1.1663 0.95517-4.5269 2.2051-8.0004 0.28109-3.3694-1.8664-3.5338-5.8701-2.477-9.261 1.0569-3.3909 5.3014-5.0232 8.3812-4.6644 6.7277 0.78392 8.7315 5.091 9.5955 7.5454 2.4366 6.9213-4.6408 13.804-8.902 13.4-4.2109 0.0282-8.4677 0.21333-12.52-6.2854 2.1202 3.9189 2.0498 12.14-3.7631 14.191-4.5313 1.8257-11.466 2.5989-16.992-3.7837-8.6613 4.8198-20.705 1.566-24.156-7.0006-0.92495-2.578-0.47339-6.8624 0.24474-9.4071-7.6693 1.5897-10.613-4.3062-9.6483-8.4011 0.91606-4.9175 6.1951-6.9841 9.8568-7.0428 1.5425-0.0247 4.6646-0.23374 6.5237 1.4445 0.91307 0.82426 0.56096-3.1566 4.8371-7.1831 1.0571-1.2067 4.9098-4.4309 6.8716-4.0876 2.9444 0.51523 6.0699-5.719 15.148-4.942 3.6186 0.30968 11.982 4.7173 15.123 5.2824 6.4081 1.1531 11.088-2.2 14.812 1.3207 2.1216 2.0055 4.2287 8.5906 1.9089 12.056-3.3431 5.2297 0.78824 7.9425 0.71094 11.137-0.41729 1.0853-2.8169-2.0166-3.8145-6.0592-0.12602-0.51067-1.1007-2.262-2.1876-2.0061 5.211-1.0111 1.7392-4.8923 3.8526-5.3799-1.3772 2.9802-4.6943 6.3834-11.832 6.001 2.3202-2.0058 7.0672-2.1803 9.3859-7.409 1.4893-3.3583-1.1162-6.6918-1.6409-7.4946-1.7761-2.7172-9.3712-0.53945-10.376 0.18939-1.5682 1.1375-2.5616 5.9494-0.43858 6.8512 0.54995 0.23361 1.794 0.56034 3.5295 0.0399 0.50862-0.15251 2.2807-1.4805 1.5209-3.1415-0.75989-1.661-4.1817-1.9196-3.2935 2.0787-2.4306-2.4398 0.42917-5.7946 3.2902-5.3916 0.79279 0.11167 2.0901 0.64339 2.7036 1.9892 0.7832 1.7182 0.04247 9.0743-6.3208 9.7095-2.5704-0.23817-4.933-1.0036-6.0081-4.2173-1.0894-3.2565-0.34649-6.6133 3.6075-8.8417-10.088-5.6172-13.564-5.3423-14.931-5.3234-3.5985 0.0499-11.415 2.2097-12.233 6.9656-2.0539 9.4145 6.0196 15.718 11.313 13.869 2.0435-0.71404 5.3178-3.0132 6.2069-5.7695 1.1253-2.7161 0.52067-9.2257-3.7502-9.8187-7.5674-1.0507-7.4178 5.1207-7.3467 5.7392 0.43169 3.7568 3.3857 3.0344 3.6417 2.0547 0.95883-3.6692-2.0573-0.28653-1.6915-1.0436 0.46602-0.96437 3.7458-4.2325 5.2541-0.60127 1.7856 4.2987-2.9558 7.0032-5.6537 6.3922-4.4526-1.0083-5.5626-5.3976-4.766-8.0601 2.1592-7.2172 11.062-5.6806 12.605-5.1024 5.4016 2.0239 6.2208 7.6173 5.5996 10.861-0.49155 2.5665-2.0196 9.0474-10.012 9.7885-4.1054 0.38065-9.5771-2.4666-11.216-5.3882-2.0253-3.6104-3.5546-6.4056-1.5183-12.344 0.49778-1.4517-0.80522-2.6114-2.1376-2.7358-1.8908-0.17651-7.8322 5.0017-8.3951 12.347-0.0049 0.0687 0.16434 3.8731 1.508 5.7369 1.0084 1.3987 1.5571 1.0966 3.0688 0.64569-0.50956 1.6452-2.9656 3.1932-5.2687 0.96907-1.1202-1.0819-1.4076-4.8291-2.1762-7.3776-0.52918-1.7545-1.3818-2.0825-1.8102-2.3238-10.206-1.1153-13.561 6.2269-9.7615 11.16 1.0884 1.2644 4.3886 2.667 7.0879-0.23624 0.9211-1.4945 1.569-5.634-2.188-6.2928-2.8126-0.35877-4.3231 2.5961-2.3307 4.1754 0.37764 0.29935 2.4183 0.24252 2.3959-1.3755 2.2889 2.8495-1.3845 4.3098-3.6108 2.018-1.7839-2.9588 1.0791-5.2149 3.1674-5.1311-0.18791-0.022 5.895-0.84785 4.9726 6.1419-4.9602 11.939 4.7226 21.559 15.224 15.13z"/>
|
||||
<path d="m49.624-251.08c4.0745-1.5884-4.5287-6.9179-2.0933 1.9722 3.3605 7.6759 16.386 13.929 25.972 10.856 6.2802-2.3279 6.422-8.3769 11.798-9.3185-1.4058 0.498-3.0762-0.99605-8.0373 3.492 2.7673-2.8522 0.46911-8.4801 0.5153-10.38 0.81305 6.522-3.3474 14.573-10.648 15.099-9.1475-0.20557-17.567-6.4219-18.317-10.157-1.3969-3.3934 1.9255-4.3416 0.80968-1.5631z"/>
|
||||
<path d="m65.991-266.93c-3.2975 0.0765-7.0461 1.7511-9.1722 4.3069-1.4452 1.8513-1.5312 4.3552-1.5178 6.6306 0.40978 2.9471 0.52755-2.4046 1.0549-3.2704 0.79541-3.0328-0.05729 1.3697 0.19279 2.5077-3e-3 1.4284 0.62634 4.1837 0.98556 4.6393-0.36808-2.9118-0.83127-5.9611-0.0089-8.831 1.1023-1.717-1.0043 5.3378-0.05502 2.4936 0.4507-2.5768 3.4798-4.9071 5.958-5.5887 1.9113-0.44792 3.8363 0.0423 5.7521 0.13584-1.5893-1.1774-4.5231-0.98014-5.3358-0.94935 1.9261-0.94969 4.1318-0.0705 6.1133 0.25724 0.92665 0.28009 6.1313 2.5542 3.7244 1.4918-2.7444-2.1779-4.7658-2.532-8.0506-2.962 2.403-0.17544 4.792 0.0365 7.8314 1.5548 1.0265 0.36413 3.0918 2.8212 3.2862 2.578-1.2943-1.7886-1.656-2.829-5.0375-4.2074-2.3484-0.68646-3.2712-0.65201-5.7213-0.78692z"/>
|
||||
<path d="m58.364-238.03c0.82342 0.96459 1.6468 1.9292 2.4703 2.8938 0.7972 4.0979 0.99109 8.6917 3.935 11.943 1.529 1.3148 3.8631 1.8335 5.5898 0.94221-1.6708 0.0763-3.301-0.33307-4.7173-1.19-1.0351-0.45373-2.6418-3.7051-0.93718-1.5735 1.7152 1.2122 3.8589 2.519 6.0318 1.776 1.6617-0.48301 3.0361-1.5936 3.9635-3.0436 0.658-0.86497-1.5494 1.0574-2.0538 1.3326-1.8192 1.5865-4.345 0.99565-6.3502 0.16388-1.5572-1.0506-3.0636-2.5037-3.4345-4.4401-0.53767-2.1605 0.98445-4.2317 2.4081-5.6982 1.6672-1.9048-2.3171 0.34388-2.1141 1.6664-1.0943 2.7953-0.80067-1.9094 0.29333-2.6286 1.0637-1.4519-1.4052-0.44253-1.242 0.76276-0.18207 0.78531-0.7779 2.569-0.75391 0.63336 0.26016-2.0878-1.6642-2.6196-3.0889-3.5399z"/>
|
||||
<path d="m28.156-247.06c0.92848-3.4966 5.0287-4.4196 8.1746-4.5432 2.7482-0.098 3.9609 2.5301 3.7359 4.9102 1.2078 1.8932 1.8939 5.2494 4.7221 5.2123 1.2565-0.038 4.8122-0.79982 1.7535 0.0858-1.4333 0.12222-3.256 0.27432-3.2963 0.71318-2.8124-0.78131-1.9305 3.4262-3.2886 4.988-0.84011 2.5666 0.06825 5.4727 1.5198 7.6219-2.1035-1.442-2.5373-4.3132-2.6564-6.6511-1.0429 0.61507 0.02588 3.9157-0.70499 1.3105-0.96281-3.0077 0.12061-6.1571 1.2057-8.9638-0.28831 1.356-1.0953 5.2215-0.54995 4.9051 0.17316-2.8227 2.8539-6.6846 0.33375-8.8214-0.47624-1.622-3.5311-2.5422-3.7271-2.9056 1.0824-0.19259 4.4689 1.1444 2.3851-0.89256-1.7961-1.5634-4.5102-0.71819-6.2136 0.55886-0.92245 1.0856-0.90091 1.8597-1.0907 0.0721-0.8937 0.11462-1.6812 1.692-2.3029 2.3998z"/>
|
||||
<path d="m45.236-235.2c1.4188-1.2781 3.3971-2.7545 5.3421-1.602 2.2217 0.66519 3.4478 3.1534 2.884 5.3536-0.35111 2.2009-1.6599 4.5037-3.921 5.1553 2.5987-0.48934 4.4214-2.8736 4.7078-5.4242 0.1482-0.77718 0.32924-3.0423 0.40115-1.0554 0.12287 1.4282 0.10405 3.0167-0.82412 4.1993 1.4662-1.0739 2.0707-2.9731 1.5762-4.6908-0.45478-0.93908-0.35002-2.0493 0.21589-0.60058 0.29431 0.77353 0.85771 2.5136 0.68046 0.59142 0.10183-2.1526-1.1589-3.992-2.5783-5.468-1.6545-1.5072-4.1397-1.0272-6.0679-0.40689-0.86995 0.3702-2.6266 1.5015-2.405 2.1681 1.5976-1.3604 3.7768-2.0397 5.8513-2.0223 1.1343 0.0526 1.9047 0.93003 0.30213 0.39937-1.4706-0.39468-4.1193 0.64258-4.5509 1.1895 1.2514-0.73692 2.9324-1.0773 4.2523-0.52456-2.0155 0.32148-4.9769-2e-3 -5.7173 2.462z"/>
|
||||
<path d="m86.737-261.88c2.7563-0.85852 6.3293-0.86997 7.8693 2.0772 2.368 3.7758-0.10823 8.4824-3.8369 10.086-1.0758 0.54064-4.9583 2.5338-2.4181 1.0435 1.7273-0.88976 5.7959-3.6731 5.9537-6.6596-1.5209 2.8566-5.3829 6.2444-5.4944 5.5818 2.2515-1.9622 5.7254-6.7355 4.4017-8.798-0.18086 2.3574-0.74912 3.2298-1.9174 4.6555 1.3091-2.3149 1.4959-5.674-1.6939-7.182-1.3411-0.35708-2.2776-0.17587-3.6745-0.07 3.191-1.0558 7.3728 0.49056 7.9763 1.8864-0.45062-2.8257-4.689-2.7438-7.1658-2.621z"/>
|
||||
<path d="m75.47-237.09c2.803 1.1663 5.3876 2.75 7.7894 4.5827 1.9392 1.5512 4.4316 2.1984 6.8793 1.8021 2.3819-0.15037 4.6177-1.2797 6.0384-3.2205 1.9103-1.8401 1.691-4.7936 1.1326-7.1714-0.72217-1.5912-1.5238-3.4197-3.1792-4.1842-2.4435-1.655-5.9834-0.92278-8.0631 1.0117-1.5923 0.92202-2.2122 4.5642-1.4908 5.0768-0.0885-1.1957 0.49061-4.0393 1.2515-3.838-0.37329 1.783-0.92585 4.5926 0.50945 5.5734-0.8281-2.4749-0.42119-5.6188 1.6709-7.3533 1.916-0.69165 1.3727 0.0971 0.05383 0.82066-1.0229 0.84309-0.97413 1.8974 0.2291 0.57914 1.6494-1.1529 5.0885-1.3778 6.0631 0.19933-0.90007-0.28761-2.911-1.116-1.022-0.0561 1.9922 0.71869 2.4199 2.8623 2.6766 4.5463 1.1651-3.0198-1.5306-6.5592-4.7208-6.464 2.0653-0.70343 4.5676 1.3093 5.1924 3.4456 0.99083 2.0816 0.44235 4.4699-0.78661 6.3162-0.28779 1.164-3.2359 3.5234-0.83706 1.7868 1.0288-0.62561 1.9327-3.8066 2.276-3.4672-0.62049 2.3505-2.1836 4.9718-4.8418 5.2318-1.685-1.3884-3.9146 1.1436-5.6327 0.0106 1.0791 1.0606 3.711-0.21206 4.0259 0.49175-2.1714 0.97677-4.6633 0.0758-6.5161-1.1913-2.1407-0.61396-3.3669-2.5051-3.7891-4.5991-0.80372-1.169 0.05018-4.2871 0.01116-4.1904-1.3934 1.8704-0.77804 4.5464 0.15394 6.3709-1.4526-1.2408-3.2863-1.6076-5.0744-2.1103z"/>
|
||||
<path d="m50.816-260.85c-4.7428 2.3195-7.1531 8.0201-6.1682 13.101 0.39021 3.199 4.0638 3.4365 5.7719 5.5891 1.5389 0.65182 2.9375 0.63553 0.71682-0.17495-1.5715-1.7161-4.12-3.0931-5.145-4.8013 1.783-0.2772 4.1569 3.8232 4.4273 3.0339-1.8386-2.4567-5.1454-4.5752-4.3129-8.1415-0.08179-1.1106 1.0497 5.0564 0.75955 1.2857-1.2383-2.9507 0.76703-6.6915 3.6364-3.2944 2.2856 2.3184-1.7431 5.7349 1.4032 7.6768 2.9709 2.6687 6.3811 5.045 10.377 5.8104-2.8244-1.2674-8.8144-4.4477-8.8341-5.6956 3.7202 2.8569 8.0143 5.1295 12.555 6.2946 1.903 0.41675 5.1739-0.28816 5.8167-1.6201-1.0633 0.93888-7.2765 1.5085-3.2054 0.5499 2.3524 0.0776 6.2515-3.239 5.786-3.926-3.7911 3.7293-9.9662 4.6807-14.649 2.0879-2.5619-1.4337-5.342-2.8518-7.136-5.2375-1.3113-2.369 3.214 2.47 0.93224-0.61762-1.1318-2.9407-2.6594-5.4934-4.4296-8.0667 0.12899-2.4985 1.7215-1.6882 1.3476 0.44799 1.3267 0.61265 1.9866 5.1062 2.2629 4.4024 3e-3 -2.2907-2.4535-5.7724-1.0966-7.2729 0.70538 5.5047 2.2634-4.336-0.81591-1.4309z"/>
|
||||
<path d="m64.434-258.85c0.50641-2.0361 2.6105-3.0205 4.9975-2.1045 2.2245 1.1612 3.1451 4.1428 2.485 6.4831-0.36288 1.6369-0.91876 2.8077-1.8397 4.0217 0.91276-2.6109 2.182-5.7102 0.3283-7.932 0.69965 1.4755 0.09798 4.4636-0.42959 6.0267-0.42961 1.2118-1.9816 2.8979-2.5725 3.3358 1.3169-1.5756 2.7659-3.31 2.7069-5.3954 0.55889-1.9106-0.70491-5.1142-3.0272-4.5658-1.0129 0.0956-3.4269 2.0908-3.4554 1.7915 1.0397-1.6217 3.2371-2.8233 5.0618-2.6442-0.69423-1.545-3.1889-0.0781-4.0742 0.84006z"/>
|
||||
</g>
|
||||
<text x="-696.14355" y="-27.217051" dominant-baseline="auto" fill="#000000" font-family="'Open Sans Condensed'" font-size="20.244px" letter-spacing="0px" stroke-width="1.5183" text-align="center" text-anchor="middle" word-spacing="0px" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;line-height:1.25;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal" xml:space="preserve"><tspan x="-696.14355" y="-27.217051" stroke-width="1.5183">lws_struct</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 18 KiB |
|
@ -522,6 +522,7 @@ struct lws;
|
|||
#include <libwebsockets/lws-vfs.h>
|
||||
#include <libwebsockets/lws-lejp.h>
|
||||
#include <libwebsockets/lws-stats.h>
|
||||
#include <libwebsockets/lws-struct.h>
|
||||
#include <libwebsockets/lws-threadpool.h>
|
||||
#include <libwebsockets/lws-tokenize.h>
|
||||
#include <libwebsockets/lws-lwsac.h>
|
||||
|
|
|
@ -173,6 +173,9 @@ LWS_EXTERN signed char _lejp_callback(struct lejp_ctx *ctx, char reason);
|
|||
|
||||
typedef signed char (*lejp_callback)(struct lejp_ctx *ctx, char reason);
|
||||
|
||||
#ifndef LEJP_MAX_PARSING_STACK_DEPTH
|
||||
#define LEJP_MAX_PARSING_STACK_DEPTH 5
|
||||
#endif
|
||||
#ifndef LEJP_MAX_DEPTH
|
||||
#define LEJP_MAX_DEPTH 12
|
||||
#endif
|
||||
|
@ -201,25 +204,36 @@ struct _lejp_stack {
|
|||
char b; /* user bitfield */
|
||||
};
|
||||
|
||||
struct _lejp_parsing_stack {
|
||||
void *user; /* private to the stack level */
|
||||
signed char (*callback)(struct lejp_ctx *ctx, char reason);
|
||||
const char * const *paths;
|
||||
uint8_t count_paths;
|
||||
uint8_t ppos;
|
||||
uint8_t path_match;
|
||||
};
|
||||
|
||||
struct lejp_ctx {
|
||||
|
||||
/* sorted by type for most compact alignment
|
||||
*
|
||||
* pointers
|
||||
*/
|
||||
|
||||
signed char (*callback)(struct lejp_ctx *ctx, char reason);
|
||||
void *user;
|
||||
const char * const *paths;
|
||||
|
||||
/* arrays */
|
||||
|
||||
struct _lejp_parsing_stack pst[LEJP_MAX_PARSING_STACK_DEPTH];
|
||||
struct _lejp_stack st[LEJP_MAX_DEPTH];
|
||||
uint16_t i[LEJP_MAX_INDEX_DEPTH]; /* index array */
|
||||
uint16_t wild[LEJP_MAX_INDEX_DEPTH]; /* index array */
|
||||
char path[LEJP_MAX_PATH];
|
||||
char buf[LEJP_STRING_CHUNK + 1];
|
||||
|
||||
/* size_t */
|
||||
|
||||
size_t path_stride; /* 0 means default ptr size, else stride */
|
||||
|
||||
/* int */
|
||||
|
||||
uint32_t line;
|
||||
|
@ -235,11 +249,11 @@ struct lejp_ctx {
|
|||
uint8_t f;
|
||||
uint8_t sp; /* stack head */
|
||||
uint8_t ipos; /* index stack depth */
|
||||
uint8_t ppos;
|
||||
uint8_t count_paths;
|
||||
uint8_t path_match;
|
||||
uint8_t path_match_len;
|
||||
uint8_t wildcount;
|
||||
uint8_t pst_sp; /* parsing stack head */
|
||||
};
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
|
@ -257,6 +271,21 @@ LWS_VISIBLE LWS_EXTERN void
|
|||
lejp_change_callback(struct lejp_ctx *ctx,
|
||||
signed char (*callback)(struct lejp_ctx *ctx, char reason));
|
||||
|
||||
/*
|
||||
* push the current paths / paths_count and lejp_cb to a stack in the ctx, and
|
||||
* start using the new ones
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lejp_parser_push(struct lejp_ctx *ctx, void *user, const char * const *paths,
|
||||
unsigned char paths_count, lejp_callback lejp_cb);
|
||||
|
||||
/*
|
||||
* pop the previously used paths / paths_count and lejp_cb, and continue
|
||||
* parsing using those as before
|
||||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lejp_parser_pop(struct lejp_ctx *ctx);
|
||||
|
||||
/* exported for use when reevaluating a path for use with a subcontext */
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lejp_check_path_match(struct lejp_ctx *ctx);
|
||||
|
|
|
@ -241,18 +241,19 @@ lws_dll_foreach_safe(struct lws_dll *phead, void *user,
|
|||
struct lws_dll2;
|
||||
struct lws_dll2_owner;
|
||||
|
||||
struct lws_dll2 {
|
||||
typedef struct lws_dll2 {
|
||||
struct lws_dll2 *prev;
|
||||
struct lws_dll2 *next;
|
||||
struct lws_dll2_owner *owner;
|
||||
};
|
||||
} lws_dll2_t;
|
||||
|
||||
struct lws_dll2_owner {
|
||||
typedef struct lws_dll2_owner {
|
||||
struct lws_dll2 *tail;
|
||||
struct lws_dll2 *head;
|
||||
|
||||
uint32_t count;
|
||||
};
|
||||
} lws_dll2_owner_t;
|
||||
|
||||
static LWS_INLINE int
|
||||
lws_dll2_is_detached(const struct lws_dll2 *d) { return !d->owner; }
|
||||
|
||||
|
@ -278,6 +279,12 @@ LWS_VISIBLE LWS_EXTERN int
|
|||
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
|
||||
int (*cb)(struct lws_dll2 *d, void *user));
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_clear(struct lws_dll2 *d);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_dll2_owner_clear(struct lws_dll2_owner *d);
|
||||
|
||||
/*
|
||||
* these are safe against the current container object getting deleted,
|
||||
* since the hold his next in a temp and go to that next. ___tmp is
|
||||
|
@ -332,6 +339,7 @@ lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf,
|
|||
*/
|
||||
LWS_VISIBLE LWS_EXTERN size_t
|
||||
lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf);
|
||||
|
||||
/**
|
||||
* lws_buflist_use_segment(): remove len bytes from the current segment
|
||||
*
|
||||
|
@ -349,6 +357,7 @@ lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf);
|
|||
*/
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_buflist_use_segment(struct lws_buflist **head, size_t len);
|
||||
|
||||
/**
|
||||
* lws_buflist_destroy_all_segments(): free all segments on the list
|
||||
*
|
||||
|
|
258
include/libwebsockets/lws-struct.h
Normal file
258
include/libwebsockets/lws-struct.h
Normal file
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
* included from libwebsockets.h
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_STRUCT_SQLITE3)
|
||||
#include <sqlite3.h>
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
LSMT_SIGNED,
|
||||
LSMT_UNSIGNED,
|
||||
LSMT_BOOLEAN,
|
||||
LSMT_STRING_CHAR_ARRAY,
|
||||
LSMT_STRING_PTR,
|
||||
LSMT_LIST,
|
||||
LSMT_CHILD_PTR,
|
||||
LSMT_SCHEMA,
|
||||
|
||||
} lws_struct_map_type_eum;
|
||||
|
||||
typedef struct lejp_collation {
|
||||
struct lws_dll2 chunks;
|
||||
int len;
|
||||
char buf[LEJP_STRING_CHUNK + 1];
|
||||
} lejp_collation_t;
|
||||
|
||||
typedef struct lws_struct_map {
|
||||
const char *colname;
|
||||
const struct lws_struct_map *child_map;
|
||||
lejp_callback lejp_cb;
|
||||
size_t ofs; /* child dll2; points to dll2_owner */
|
||||
size_t aux;
|
||||
size_t ofs_clist;
|
||||
size_t child_map_size;
|
||||
lws_struct_map_type_eum type;
|
||||
} lws_struct_map_t;
|
||||
|
||||
typedef int (*lws_struct_args_cb)(void *obj, void *cb_arg);
|
||||
|
||||
typedef struct lws_struct_args {
|
||||
const lws_struct_map_t *map_st[LEJP_MAX_PARSING_STACK_DEPTH];
|
||||
lws_struct_args_cb cb;
|
||||
struct lwsac *ac;
|
||||
void *cb_arg;
|
||||
void *dest;
|
||||
|
||||
size_t dest_len;
|
||||
size_t toplevel_dll2_ofs;
|
||||
size_t map_entries_st[LEJP_MAX_PARSING_STACK_DEPTH];
|
||||
size_t ac_block_size;
|
||||
int subtype;
|
||||
|
||||
/*
|
||||
* temp ac used to collate unknown possibly huge strings before final
|
||||
* allocation and copy
|
||||
*/
|
||||
struct lwsac *ac_chunks;
|
||||
struct lws_dll2_owner chunks_owner;
|
||||
size_t chunks_length;
|
||||
} lws_struct_args_t;
|
||||
|
||||
#define LSM_SIGNED(type, name, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
offsetof(type, name), \
|
||||
sizeof ((type *)0)->name, \
|
||||
0, \
|
||||
0, \
|
||||
LSMT_SIGNED \
|
||||
}
|
||||
|
||||
#define LSM_UNSIGNED(type, name, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
offsetof(type, name), \
|
||||
sizeof ((type *)0)->name, \
|
||||
0, \
|
||||
0, \
|
||||
LSMT_UNSIGNED \
|
||||
}
|
||||
|
||||
#define LSM_BOOLEAN(type, name, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
offsetof(type, name), \
|
||||
sizeof ((type *)0)->name, \
|
||||
0, \
|
||||
0, \
|
||||
LSMT_BOOLEAN \
|
||||
}
|
||||
|
||||
#define LSM_CARRAY(type, name, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
offsetof(type, name), \
|
||||
sizeof (((type *)0)->name), \
|
||||
0, \
|
||||
0, \
|
||||
LSMT_STRING_CHAR_ARRAY \
|
||||
}
|
||||
|
||||
#define LSM_STRING_PTR(type, name, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
offsetof(type, name), \
|
||||
sizeof (((type *)0)->name), \
|
||||
0, \
|
||||
0, \
|
||||
LSMT_STRING_PTR \
|
||||
}
|
||||
|
||||
#define LSM_LIST(ptype, pname, ctype, cname, lejp_cb, cmap, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
cmap, \
|
||||
lejp_cb, \
|
||||
offsetof(ptype, pname), \
|
||||
sizeof (ctype), \
|
||||
offsetof(ctype, cname), \
|
||||
LWS_ARRAY_SIZE(cmap), \
|
||||
LSMT_LIST \
|
||||
}
|
||||
|
||||
#define LSM_CHILD_PTR(ptype, pname, ctype, lejp_cb, cmap, qname) \
|
||||
{ \
|
||||
qname, \
|
||||
cmap, \
|
||||
lejp_cb, \
|
||||
offsetof(ptype, pname), \
|
||||
sizeof (ctype), \
|
||||
0, \
|
||||
LWS_ARRAY_SIZE(cmap), \
|
||||
LSMT_CHILD_PTR \
|
||||
}
|
||||
|
||||
#define LSM_SCHEMA(ctype, lejp_cb, map, schema_name) \
|
||||
{ \
|
||||
schema_name, \
|
||||
map, \
|
||||
lejp_cb, \
|
||||
0, \
|
||||
sizeof (ctype), \
|
||||
0, \
|
||||
LWS_ARRAY_SIZE(map), \
|
||||
LSMT_SCHEMA \
|
||||
}
|
||||
|
||||
#define LSM_SCHEMA_DLL2(ctype, cdll2mem, lejp_cb, map, schema_name) \
|
||||
{ \
|
||||
schema_name, \
|
||||
map, \
|
||||
lejp_cb, \
|
||||
offsetof(ctype, cdll2mem), \
|
||||
sizeof (ctype), \
|
||||
0, \
|
||||
LWS_ARRAY_SIZE(map), \
|
||||
LSMT_SCHEMA \
|
||||
}
|
||||
|
||||
typedef struct lws_struct_serialize_st {
|
||||
const struct lws_dll2 *dllpos;
|
||||
const lws_struct_map_t *map;
|
||||
const char *obj;
|
||||
size_t map_entries;
|
||||
size_t map_entry;
|
||||
size_t size;
|
||||
char subsequent;
|
||||
char idt;
|
||||
} lws_struct_serialize_st_t;
|
||||
|
||||
enum {
|
||||
LSSERJ_FLAG_PRETTY = 1
|
||||
};
|
||||
|
||||
typedef struct lws_struct_serialize {
|
||||
lws_struct_serialize_st_t st[LEJP_MAX_PARSING_STACK_DEPTH];
|
||||
|
||||
size_t offset;
|
||||
size_t remaining;
|
||||
|
||||
int sp;
|
||||
int flags;
|
||||
} lws_struct_serialize_t;
|
||||
|
||||
typedef enum {
|
||||
LSJS_RESULT_CONTINUE,
|
||||
LSJS_RESULT_FINISH,
|
||||
LSJS_RESULT_ERROR
|
||||
} lws_struct_json_serialize_result_t;
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb,
|
||||
void *user);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN signed char
|
||||
lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN signed char
|
||||
lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN lws_struct_serialize_t *
|
||||
lws_struct_json_serialize_create(const lws_struct_map_t *map,
|
||||
size_t map_entries, int flags, void *ptoplevel);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN void
|
||||
lws_struct_json_serialize_destroy(lws_struct_serialize_t **pjs);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN lws_struct_json_serialize_result_t
|
||||
lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
|
||||
size_t len, size_t *written);
|
||||
|
||||
#if defined(LWS_WITH_STRUCT_SQLITE3)
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_struct_sq3_deserialize(sqlite3 *pdb, const lws_struct_map_t *schema,
|
||||
lws_dll2_owner_t *o, struct lwsac **ac,
|
||||
uint64_t start, int limit);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
|
||||
sqlite3 **pdb);
|
||||
|
||||
LWS_VISIBLE LWS_EXTERN int
|
||||
lws_struct_sq3_close(sqlite3 **pdb);
|
||||
|
||||
#endif
|
170
lib/core/buflist.c
Normal file
170
lib/core/buflist.c
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
|
||||
#ifdef LWS_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
/* lws_buflist */
|
||||
|
||||
int
|
||||
lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct lws_buflist *nbuf;
|
||||
int first = !*head;
|
||||
void *p = *head;
|
||||
int sanity = 1024;
|
||||
|
||||
assert(buf);
|
||||
assert(len);
|
||||
|
||||
/* append at the tail */
|
||||
while (*head) {
|
||||
if (!--sanity) {
|
||||
lwsl_err("%s: buflist reached sanity limit\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (*head == (*head)->next) {
|
||||
lwsl_err("%s: corrupt list points to self\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
head = &((*head)->next);
|
||||
}
|
||||
|
||||
lwsl_info("%s: len %u first %d %p\n", __func__, (uint32_t)len, first, p);
|
||||
|
||||
nbuf = (struct lws_buflist *)lws_malloc(sizeof(**head) + len, __func__);
|
||||
if (!nbuf) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nbuf->len = len;
|
||||
nbuf->pos = 0;
|
||||
nbuf->next = NULL;
|
||||
|
||||
p = (void *)nbuf->buf;
|
||||
memcpy(p, buf, len);
|
||||
|
||||
*head = nbuf;
|
||||
|
||||
return first; /* returns 1 if first segment just created */
|
||||
}
|
||||
|
||||
static int
|
||||
lws_buflist_destroy_segment(struct lws_buflist **head)
|
||||
{
|
||||
struct lws_buflist *old = *head;
|
||||
|
||||
assert(*head);
|
||||
*head = old->next;
|
||||
old->next = NULL;
|
||||
lws_free(old);
|
||||
|
||||
return !*head; /* returns 1 if last segment just destroyed */
|
||||
}
|
||||
|
||||
void
|
||||
lws_buflist_destroy_all_segments(struct lws_buflist **head)
|
||||
{
|
||||
struct lws_buflist *p = *head, *p1;
|
||||
|
||||
while (p) {
|
||||
p1 = p->next;
|
||||
p->next = NULL;
|
||||
lws_free(p);
|
||||
p = p1;
|
||||
}
|
||||
|
||||
*head = NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf)
|
||||
{
|
||||
if (!*head) {
|
||||
if (buf)
|
||||
*buf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(*head)->len && (*head)->next)
|
||||
lws_buflist_destroy_segment(head);
|
||||
|
||||
if (!*head) {
|
||||
if (buf)
|
||||
*buf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert((*head)->pos < (*head)->len);
|
||||
|
||||
if (buf)
|
||||
*buf = (*head)->buf + (*head)->pos;
|
||||
|
||||
return (*head)->len - (*head)->pos;
|
||||
}
|
||||
|
||||
int
|
||||
lws_buflist_use_segment(struct lws_buflist **head, size_t len)
|
||||
{
|
||||
assert(*head);
|
||||
assert(len);
|
||||
assert((*head)->pos + len <= (*head)->len);
|
||||
|
||||
(*head)->pos += len;
|
||||
if ((*head)->pos == (*head)->len)
|
||||
lws_buflist_destroy_segment(head);
|
||||
|
||||
if (!*head)
|
||||
return 0;
|
||||
|
||||
return (int)((*head)->len - (*head)->pos);
|
||||
}
|
||||
|
||||
void
|
||||
lws_buflist_describe(struct lws_buflist **head, void *id)
|
||||
{
|
||||
struct lws_buflist *old;
|
||||
int n = 0;
|
||||
|
||||
if (*head == NULL)
|
||||
lwsl_notice("%p: buflist empty\n", id);
|
||||
|
||||
while (*head) {
|
||||
lwsl_notice("%p: %d: %llu / %llu (%llu left)\n", id, n,
|
||||
(unsigned long long)(*head)->pos,
|
||||
(unsigned long long)(*head)->len,
|
||||
(unsigned long long)(*head)->len - (*head)->pos);
|
||||
old = *head;
|
||||
head = &((*head)->next);
|
||||
if (*head == old) {
|
||||
lwsl_err("%s: next points to self\n", __func__);
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
|
@ -94,321 +94,6 @@ int lws_open(const char *__file, int __oflag, ...)
|
|||
#endif
|
||||
|
||||
|
||||
void
|
||||
lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead)
|
||||
{
|
||||
if (!lws_dll_is_detached(d, phead)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our next guy is current first guy, if any */
|
||||
if (phead->next != d)
|
||||
d->next = phead->next;
|
||||
|
||||
/* if there is a next guy, set his prev ptr to our next ptr */
|
||||
if (d->next)
|
||||
d->next->prev = d;
|
||||
/* there is nobody previous to us, we are the head */
|
||||
d->prev = NULL;
|
||||
|
||||
/* set the first guy to be us */
|
||||
phead->next = d;
|
||||
|
||||
/* if there was nothing on the list before, we are also now the tail */
|
||||
if (!phead->prev)
|
||||
phead->prev = d;
|
||||
|
||||
assert(d->prev != d);
|
||||
assert(d->next != d);
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead)
|
||||
{
|
||||
if (!lws_dll_is_detached(d, phead)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our previous guy is current last guy */
|
||||
d->prev = phead->prev;
|
||||
/* if there is a prev guy, set his next ptr to our prev ptr */
|
||||
if (d->prev)
|
||||
d->prev->next = d;
|
||||
/* our next ptr is NULL */
|
||||
d->next = NULL;
|
||||
/* set the last guy to be us */
|
||||
phead->prev = d;
|
||||
|
||||
/* list head is also us if we're the first */
|
||||
if (!phead->next)
|
||||
phead->next = d;
|
||||
|
||||
assert(d->prev != d);
|
||||
assert(d->next != d);
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll_insert(struct lws_dll *n, struct lws_dll *target,
|
||||
struct lws_dll *phead, int before)
|
||||
{
|
||||
if (!lws_dll_is_detached(n, phead)) {
|
||||
assert(0); /* only wholly detached things can be inserted */
|
||||
return;
|
||||
}
|
||||
if (!target) {
|
||||
/*
|
||||
* the case where there's no target identified degenerates to
|
||||
* a simple add at head or tail
|
||||
*/
|
||||
if (before) {
|
||||
lws_dll_add_head(n, phead);
|
||||
return;
|
||||
}
|
||||
lws_dll_add_tail(n, phead);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* in the case there's a target "cursor", we have to do the work to
|
||||
* stitch the new guy in appropriately
|
||||
*/
|
||||
|
||||
if (before) {
|
||||
/*
|
||||
* we go before dd
|
||||
* DDp <-> DD <-> DDn --> DDp <-> us <-> DD <-> DDn
|
||||
*/
|
||||
/* we point forward to dd */
|
||||
n->next = target;
|
||||
/* we point back to what dd used to point back to */
|
||||
n->prev = target->prev;
|
||||
/* DDp points forward to us now */
|
||||
if (target->prev)
|
||||
target->prev->next = n;
|
||||
/* DD points back to us now */
|
||||
target->prev = n;
|
||||
|
||||
/* if target was the head, we are now the head */
|
||||
if (phead->next == target)
|
||||
phead->next = n;
|
||||
|
||||
/* since we are before another guy, we cannot become the tail */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* we go after dd
|
||||
* DDp <-> DD <-> DDn --> DDp <-> DD <-> us <-> DDn
|
||||
*/
|
||||
/* we point forward to what dd used to point forward to */
|
||||
n->next = target->next;
|
||||
/* we point back to dd */
|
||||
n->prev = target;
|
||||
/* DDn points back to us */
|
||||
if (target->next)
|
||||
target->next->prev = n;
|
||||
/* DD points forward to us */
|
||||
target->next = n;
|
||||
|
||||
/* if target was the tail, we are now the tail */
|
||||
if (phead->prev == target)
|
||||
phead->prev = n;
|
||||
|
||||
/* since we go after another guy, we cannot become the head */
|
||||
}
|
||||
}
|
||||
|
||||
/* situation is:
|
||||
*
|
||||
* HEAD: struct lws_dll * = &entry1
|
||||
*
|
||||
* Entry 1: struct lws_dll .pprev = &HEAD , .next = Entry 2
|
||||
* Entry 2: struct lws_dll .pprev = &entry1 , .next = &entry2
|
||||
* Entry 3: struct lws_dll .pprev = &entry2 , .next = NULL
|
||||
*
|
||||
* Delete Entry1:
|
||||
*
|
||||
* - HEAD = &entry2
|
||||
* - Entry2: .pprev = &HEAD, .next = &entry3
|
||||
* - Entry3: .pprev = &entry2, .next = NULL
|
||||
*
|
||||
* Delete Entry2:
|
||||
*
|
||||
* - HEAD = &entry1
|
||||
* - Entry1: .pprev = &HEAD, .next = &entry3
|
||||
* - Entry3: .pprev = &entry1, .next = NULL
|
||||
*
|
||||
* Delete Entry3:
|
||||
*
|
||||
* - HEAD = &entry1
|
||||
* - Entry1: .pprev = &HEAD, .next = &entry2
|
||||
* - Entry2: .pprev = &entry1, .next = NULL
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
lws_dll_remove(struct lws_dll *d)
|
||||
{
|
||||
if (!d->prev && !d->next)
|
||||
return;
|
||||
|
||||
/*
|
||||
* remove us
|
||||
*
|
||||
* USp <-> us <-> USn --> USp <-> USn
|
||||
*/
|
||||
|
||||
/* if we have a next guy, set his prev to our prev */
|
||||
if (d->next)
|
||||
d->next->prev = d->prev;
|
||||
|
||||
/* set our prev guy to our next guy instead of us */
|
||||
if (d->prev)
|
||||
d->prev->next = d->next;
|
||||
|
||||
/* we're out of the list, we should not point anywhere any more */
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead)
|
||||
{
|
||||
if (lws_dll_is_detached(d, phead)) {
|
||||
assert(phead->prev != d);
|
||||
assert(phead->next != d);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we have a next guy, set his prev to our prev */
|
||||
if (d->next)
|
||||
d->next->prev = d->prev;
|
||||
|
||||
/* if we have a previous guy, set his next to our next */
|
||||
if (d->prev)
|
||||
d->prev->next = d->next;
|
||||
|
||||
if (phead->prev == d)
|
||||
phead->prev = d->prev;
|
||||
|
||||
if (phead->next == d)
|
||||
phead->next = d->next;
|
||||
|
||||
/* we're out of the list, we should not point anywhere any more */
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_dll_foreach_safe(struct lws_dll *phead, void *user,
|
||||
int (*cb)(struct lws_dll *d, void *user))
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll *, p, tp, phead->next) {
|
||||
if (cb(p, user))
|
||||
return 1;
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
|
||||
int (*cb)(struct lws_dll2 *d, void *user))
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp, owner->head) {
|
||||
if (cb(p, user))
|
||||
return 1;
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner)
|
||||
{
|
||||
if (!lws_dll2_is_detached(d)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our next guy is current first guy, if any */
|
||||
if (owner->head != d)
|
||||
d->next = owner->head;
|
||||
|
||||
/* if there is a next guy, set his prev ptr to our next ptr */
|
||||
if (d->next)
|
||||
d->next->prev = d;
|
||||
/* there is nobody previous to us, we are the head */
|
||||
d->prev = NULL;
|
||||
|
||||
/* set the first guy to be us */
|
||||
owner->head = d;
|
||||
|
||||
if (!owner->tail)
|
||||
owner->tail = d;
|
||||
|
||||
d->owner = owner;
|
||||
owner->count++;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner)
|
||||
{
|
||||
if (!lws_dll2_is_detached(d)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our previous guy is current last guy */
|
||||
d->prev = owner->tail;
|
||||
/* if there is a prev guy, set his next ptr to our prev ptr */
|
||||
if (d->prev)
|
||||
d->prev->next = d;
|
||||
/* our next ptr is NULL */
|
||||
d->next = NULL;
|
||||
/* set the last guy to be us */
|
||||
owner->tail = d;
|
||||
|
||||
/* list head is also us if we're the first */
|
||||
if (!owner->head)
|
||||
owner->head = d;
|
||||
|
||||
d->owner = owner;
|
||||
owner->count++;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_remove(struct lws_dll2 *d)
|
||||
{
|
||||
if (lws_dll2_is_detached(d))
|
||||
return;
|
||||
|
||||
/* if we have a next guy, set his prev to our prev */
|
||||
if (d->next)
|
||||
d->next->prev = d->prev;
|
||||
|
||||
/* if we have a previous guy, set his next to our next */
|
||||
if (d->prev)
|
||||
d->prev->next = d->next;
|
||||
|
||||
/* if we have phead, track the tail and head if it points to us... */
|
||||
|
||||
if (d->owner->tail == d)
|
||||
d->owner->tail = d->prev;
|
||||
|
||||
if (d->owner->head == d)
|
||||
d->owner->head = d->next;
|
||||
|
||||
d->owner->count--;
|
||||
|
||||
/* we're out of the list, we should not point anywhere any more */
|
||||
d->owner = NULL;
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
#if !(defined(LWS_PLAT_OPTEE) && !defined(LWS_WITH_NETWORK))
|
||||
|
||||
LWS_VISIBLE lws_usec_t
|
||||
|
@ -441,151 +126,6 @@ lws_pthread_self_to_tsi(struct lws_context *context)
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* lws_buflist */
|
||||
|
||||
int
|
||||
lws_buflist_append_segment(struct lws_buflist **head, const uint8_t *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct lws_buflist *nbuf;
|
||||
int first = !*head;
|
||||
void *p = *head;
|
||||
int sanity = 1024;
|
||||
|
||||
assert(buf);
|
||||
assert(len);
|
||||
|
||||
/* append at the tail */
|
||||
while (*head) {
|
||||
if (!--sanity) {
|
||||
lwsl_err("%s: buflist reached sanity limit\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (*head == (*head)->next) {
|
||||
lwsl_err("%s: corrupt list points to self\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
head = &((*head)->next);
|
||||
}
|
||||
|
||||
lwsl_info("%s: len %u first %d %p\n", __func__, (uint32_t)len, first, p);
|
||||
|
||||
nbuf = (struct lws_buflist *)lws_malloc(sizeof(**head) + len, __func__);
|
||||
if (!nbuf) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nbuf->len = len;
|
||||
nbuf->pos = 0;
|
||||
nbuf->next = NULL;
|
||||
|
||||
p = (void *)nbuf->buf;
|
||||
memcpy(p, buf, len);
|
||||
|
||||
*head = nbuf;
|
||||
|
||||
return first; /* returns 1 if first segment just created */
|
||||
}
|
||||
|
||||
static int
|
||||
lws_buflist_destroy_segment(struct lws_buflist **head)
|
||||
{
|
||||
struct lws_buflist *old = *head;
|
||||
|
||||
assert(*head);
|
||||
*head = old->next;
|
||||
old->next = NULL;
|
||||
lws_free(old);
|
||||
|
||||
return !*head; /* returns 1 if last segment just destroyed */
|
||||
}
|
||||
|
||||
void
|
||||
lws_buflist_destroy_all_segments(struct lws_buflist **head)
|
||||
{
|
||||
struct lws_buflist *p = *head, *p1;
|
||||
|
||||
while (p) {
|
||||
p1 = p->next;
|
||||
p->next = NULL;
|
||||
lws_free(p);
|
||||
p = p1;
|
||||
}
|
||||
|
||||
*head = NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
lws_buflist_next_segment_len(struct lws_buflist **head, uint8_t **buf)
|
||||
{
|
||||
if (!*head) {
|
||||
if (buf)
|
||||
*buf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(*head)->len && (*head)->next)
|
||||
lws_buflist_destroy_segment(head);
|
||||
|
||||
if (!*head) {
|
||||
if (buf)
|
||||
*buf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert((*head)->pos < (*head)->len);
|
||||
|
||||
if (buf)
|
||||
*buf = (*head)->buf + (*head)->pos;
|
||||
|
||||
return (*head)->len - (*head)->pos;
|
||||
}
|
||||
|
||||
int
|
||||
lws_buflist_use_segment(struct lws_buflist **head, size_t len)
|
||||
{
|
||||
assert(*head);
|
||||
assert(len);
|
||||
assert((*head)->pos + len <= (*head)->len);
|
||||
|
||||
(*head)->pos += len;
|
||||
if ((*head)->pos == (*head)->len)
|
||||
lws_buflist_destroy_segment(head);
|
||||
|
||||
if (!*head)
|
||||
return 0;
|
||||
|
||||
return (int)((*head)->len - (*head)->pos);
|
||||
}
|
||||
|
||||
void
|
||||
lws_buflist_describe(struct lws_buflist **head, void *id)
|
||||
{
|
||||
struct lws_buflist *old;
|
||||
int n = 0;
|
||||
|
||||
if (*head == NULL)
|
||||
lwsl_notice("%p: buflist empty\n", id);
|
||||
|
||||
while (*head) {
|
||||
lwsl_notice("%p: %d: %llu / %llu (%llu left)\n", id, n,
|
||||
(unsigned long long)(*head)->pos,
|
||||
(unsigned long long)(*head)->len,
|
||||
(unsigned long long)(*head)->len - (*head)->pos);
|
||||
old = *head;
|
||||
head = &((*head)->next);
|
||||
if (*head == old) {
|
||||
lwsl_err("%s: next points to self\n", __func__);
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
LWS_EXTERN void *
|
||||
lws_context_user(struct lws_context *context)
|
||||
{
|
||||
|
|
246
lib/core/lws_dll.c
Normal file
246
lib/core/lws_dll.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
|
||||
#ifdef LWS_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
lws_dll_add_head(struct lws_dll *d, struct lws_dll *phead)
|
||||
{
|
||||
if (!lws_dll_is_detached(d, phead)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our next guy is current first guy, if any */
|
||||
if (phead->next != d)
|
||||
d->next = phead->next;
|
||||
|
||||
/* if there is a next guy, set his prev ptr to our next ptr */
|
||||
if (d->next)
|
||||
d->next->prev = d;
|
||||
/* there is nobody previous to us, we are the head */
|
||||
d->prev = NULL;
|
||||
|
||||
/* set the first guy to be us */
|
||||
phead->next = d;
|
||||
|
||||
/* if there was nothing on the list before, we are also now the tail */
|
||||
if (!phead->prev)
|
||||
phead->prev = d;
|
||||
|
||||
assert(d->prev != d);
|
||||
assert(d->next != d);
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll_add_tail(struct lws_dll *d, struct lws_dll *phead)
|
||||
{
|
||||
if (!lws_dll_is_detached(d, phead)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our previous guy is current last guy */
|
||||
d->prev = phead->prev;
|
||||
/* if there is a prev guy, set his next ptr to our prev ptr */
|
||||
if (d->prev)
|
||||
d->prev->next = d;
|
||||
/* our next ptr is NULL */
|
||||
d->next = NULL;
|
||||
/* set the last guy to be us */
|
||||
phead->prev = d;
|
||||
|
||||
/* list head is also us if we're the first */
|
||||
if (!phead->next)
|
||||
phead->next = d;
|
||||
|
||||
assert(d->prev != d);
|
||||
assert(d->next != d);
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll_insert(struct lws_dll *n, struct lws_dll *target,
|
||||
struct lws_dll *phead, int before)
|
||||
{
|
||||
if (!lws_dll_is_detached(n, phead)) {
|
||||
assert(0); /* only wholly detached things can be inserted */
|
||||
return;
|
||||
}
|
||||
if (!target) {
|
||||
/*
|
||||
* the case where there's no target identified degenerates to
|
||||
* a simple add at head or tail
|
||||
*/
|
||||
if (before) {
|
||||
lws_dll_add_head(n, phead);
|
||||
return;
|
||||
}
|
||||
lws_dll_add_tail(n, phead);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* in the case there's a target "cursor", we have to do the work to
|
||||
* stitch the new guy in appropriately
|
||||
*/
|
||||
|
||||
if (before) {
|
||||
/*
|
||||
* we go before dd
|
||||
* DDp <-> DD <-> DDn --> DDp <-> us <-> DD <-> DDn
|
||||
*/
|
||||
/* we point forward to dd */
|
||||
n->next = target;
|
||||
/* we point back to what dd used to point back to */
|
||||
n->prev = target->prev;
|
||||
/* DDp points forward to us now */
|
||||
if (target->prev)
|
||||
target->prev->next = n;
|
||||
/* DD points back to us now */
|
||||
target->prev = n;
|
||||
|
||||
/* if target was the head, we are now the head */
|
||||
if (phead->next == target)
|
||||
phead->next = n;
|
||||
|
||||
/* since we are before another guy, we cannot become the tail */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* we go after dd
|
||||
* DDp <-> DD <-> DDn --> DDp <-> DD <-> us <-> DDn
|
||||
*/
|
||||
/* we point forward to what dd used to point forward to */
|
||||
n->next = target->next;
|
||||
/* we point back to dd */
|
||||
n->prev = target;
|
||||
/* DDn points back to us */
|
||||
if (target->next)
|
||||
target->next->prev = n;
|
||||
/* DD points forward to us */
|
||||
target->next = n;
|
||||
|
||||
/* if target was the tail, we are now the tail */
|
||||
if (phead->prev == target)
|
||||
phead->prev = n;
|
||||
|
||||
/* since we go after another guy, we cannot become the head */
|
||||
}
|
||||
}
|
||||
|
||||
/* situation is:
|
||||
*
|
||||
* HEAD: struct lws_dll * = &entry1
|
||||
*
|
||||
* Entry 1: struct lws_dll .pprev = &HEAD , .next = Entry 2
|
||||
* Entry 2: struct lws_dll .pprev = &entry1 , .next = &entry2
|
||||
* Entry 3: struct lws_dll .pprev = &entry2 , .next = NULL
|
||||
*
|
||||
* Delete Entry1:
|
||||
*
|
||||
* - HEAD = &entry2
|
||||
* - Entry2: .pprev = &HEAD, .next = &entry3
|
||||
* - Entry3: .pprev = &entry2, .next = NULL
|
||||
*
|
||||
* Delete Entry2:
|
||||
*
|
||||
* - HEAD = &entry1
|
||||
* - Entry1: .pprev = &HEAD, .next = &entry3
|
||||
* - Entry3: .pprev = &entry1, .next = NULL
|
||||
*
|
||||
* Delete Entry3:
|
||||
*
|
||||
* - HEAD = &entry1
|
||||
* - Entry1: .pprev = &HEAD, .next = &entry2
|
||||
* - Entry2: .pprev = &entry1, .next = NULL
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
lws_dll_remove(struct lws_dll *d)
|
||||
{
|
||||
if (!d->prev && !d->next)
|
||||
return;
|
||||
|
||||
/*
|
||||
* remove us
|
||||
*
|
||||
* USp <-> us <-> USn --> USp <-> USn
|
||||
*/
|
||||
|
||||
/* if we have a next guy, set his prev to our prev */
|
||||
if (d->next)
|
||||
d->next->prev = d->prev;
|
||||
|
||||
/* set our prev guy to our next guy instead of us */
|
||||
if (d->prev)
|
||||
d->prev->next = d->next;
|
||||
|
||||
/* we're out of the list, we should not point anywhere any more */
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll_remove_track_tail(struct lws_dll *d, struct lws_dll *phead)
|
||||
{
|
||||
if (lws_dll_is_detached(d, phead)) {
|
||||
assert(phead->prev != d);
|
||||
assert(phead->next != d);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we have a next guy, set his prev to our prev */
|
||||
if (d->next)
|
||||
d->next->prev = d->prev;
|
||||
|
||||
/* if we have a previous guy, set his next to our next */
|
||||
if (d->prev)
|
||||
d->prev->next = d->next;
|
||||
|
||||
if (phead->prev == d)
|
||||
phead->prev = d->prev;
|
||||
|
||||
if (phead->next == d)
|
||||
phead->next = d->next;
|
||||
|
||||
/* we're out of the list, we should not point anywhere any more */
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
lws_dll_foreach_safe(struct lws_dll *phead, void *user,
|
||||
int (*cb)(struct lws_dll *d, void *user))
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll *, p, tp, phead->next) {
|
||||
if (cb(p, user))
|
||||
return 1;
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
return 0;
|
||||
}
|
138
lib/core/lws_dll2.c
Normal file
138
lib/core/lws_dll2.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010-2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "core/private.h"
|
||||
|
||||
#ifdef LWS_HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
lws_dll2_foreach_safe(struct lws_dll2_owner *owner, void *user,
|
||||
int (*cb)(struct lws_dll2 *d, void *user))
|
||||
{
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp, owner->head) {
|
||||
if (cb(p, user))
|
||||
return 1;
|
||||
} lws_end_foreach_dll_safe(p, tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_add_head(struct lws_dll2 *d, struct lws_dll2_owner *owner)
|
||||
{
|
||||
if (!lws_dll2_is_detached(d)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our next guy is current first guy, if any */
|
||||
if (owner->head != d)
|
||||
d->next = owner->head;
|
||||
|
||||
/* if there is a next guy, set his prev ptr to our next ptr */
|
||||
if (d->next)
|
||||
d->next->prev = d;
|
||||
/* there is nobody previous to us, we are the head */
|
||||
d->prev = NULL;
|
||||
|
||||
/* set the first guy to be us */
|
||||
owner->head = d;
|
||||
|
||||
if (!owner->tail)
|
||||
owner->tail = d;
|
||||
|
||||
d->owner = owner;
|
||||
owner->count++;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_add_tail(struct lws_dll2 *d, struct lws_dll2_owner *owner)
|
||||
{
|
||||
if (!lws_dll2_is_detached(d)) {
|
||||
assert(0); /* only wholly detached things can be added */
|
||||
return;
|
||||
}
|
||||
|
||||
/* our previous guy is current last guy */
|
||||
d->prev = owner->tail;
|
||||
/* if there is a prev guy, set his next ptr to our prev ptr */
|
||||
if (d->prev)
|
||||
d->prev->next = d;
|
||||
/* our next ptr is NULL */
|
||||
d->next = NULL;
|
||||
/* set the last guy to be us */
|
||||
owner->tail = d;
|
||||
|
||||
/* list head is also us if we're the first */
|
||||
if (!owner->head)
|
||||
owner->head = d;
|
||||
|
||||
d->owner = owner;
|
||||
owner->count++;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_remove(struct lws_dll2 *d)
|
||||
{
|
||||
if (lws_dll2_is_detached(d))
|
||||
return;
|
||||
|
||||
/* if we have a next guy, set his prev to our prev */
|
||||
if (d->next)
|
||||
d->next->prev = d->prev;
|
||||
|
||||
/* if we have a previous guy, set his next to our next */
|
||||
if (d->prev)
|
||||
d->prev->next = d->next;
|
||||
|
||||
/* if we have phead, track the tail and head if it points to us... */
|
||||
|
||||
if (d->owner->tail == d)
|
||||
d->owner->tail = d->prev;
|
||||
|
||||
if (d->owner->head == d)
|
||||
d->owner->head = d->next;
|
||||
|
||||
d->owner->count--;
|
||||
|
||||
/* we're out of the list, we should not point anywhere any more */
|
||||
d->owner = NULL;
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_clear(struct lws_dll2 *d)
|
||||
{
|
||||
d->owner = NULL;
|
||||
d->prev = NULL;
|
||||
d->next = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dll2_owner_clear(struct lws_dll2_owner *d)
|
||||
{
|
||||
d->head = NULL;
|
||||
d->tail = NULL;
|
||||
d->count = 0;
|
||||
}
|
|
@ -176,7 +176,8 @@ lws_jws_jose_cb(struct lejp_ctx *ctx, char reason)
|
|||
lejp_check_path_match(&args->jwk_jctx);
|
||||
|
||||
if (args->jwk_jctx.path_match)
|
||||
args->jwk_jctx.callback(&args->jwk_jctx, reason);
|
||||
args->jwk_jctx.pst[args->jwk_jctx.pst_sp].
|
||||
callback(&args->jwk_jctx, reason);
|
||||
}
|
||||
|
||||
// lwsl_notice("%s: %s %d (%d)\n", __func__, ctx->path, reason, ctx->sp);
|
||||
|
|
176
lib/misc/lejp.c
176
lib/misc/lejp.c
|
@ -74,15 +74,20 @@ lejp_construct(struct lejp_ctx *ctx,
|
|||
ctx->st[0].b = 0;
|
||||
ctx->sp = 0;
|
||||
ctx->ipos = 0;
|
||||
ctx->ppos = 0;
|
||||
ctx->path_match = 0;
|
||||
ctx->path_stride = 0;
|
||||
ctx->path[0] = '\0';
|
||||
ctx->callback = callback;
|
||||
ctx->user = user;
|
||||
ctx->paths = paths;
|
||||
ctx->count_paths = count_paths;
|
||||
ctx->line = 1;
|
||||
ctx->callback(ctx, LEJPCB_CONSTRUCTED);
|
||||
|
||||
ctx->pst_sp = 0;
|
||||
ctx->pst[0].callback = callback;
|
||||
ctx->pst[0].paths = paths;
|
||||
ctx->pst[0].count_paths = count_paths;
|
||||
ctx->pst[0].user = NULL;
|
||||
ctx->pst[0].ppos = 0;
|
||||
|
||||
ctx->pst[0].callback(ctx, LEJPCB_CONSTRUCTED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,7 +104,7 @@ void
|
|||
lejp_destruct(struct lejp_ctx *ctx)
|
||||
{
|
||||
/* no allocations... just let callback know what it happening */
|
||||
ctx->callback(ctx, LEJPCB_DESTRUCTED);
|
||||
ctx->pst[0].callback(ctx, LEJPCB_DESTRUCTED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,23 +133,29 @@ void
|
|||
lejp_change_callback(struct lejp_ctx *ctx,
|
||||
signed char (*callback)(struct lejp_ctx *ctx, char reason))
|
||||
{
|
||||
ctx->callback(ctx, LEJPCB_DESTRUCTED);
|
||||
ctx->callback = callback;
|
||||
ctx->callback(ctx, LEJPCB_CONSTRUCTED);
|
||||
ctx->callback(ctx, LEJPCB_START);
|
||||
ctx->pst[0].callback(ctx, LEJPCB_DESTRUCTED);
|
||||
ctx->pst[0].callback = callback;
|
||||
ctx->pst[0].callback(ctx, LEJPCB_CONSTRUCTED);
|
||||
ctx->pst[0].callback(ctx, LEJPCB_START);
|
||||
}
|
||||
|
||||
void
|
||||
lejp_check_path_match(struct lejp_ctx *ctx)
|
||||
{
|
||||
const char *p, *q;
|
||||
int n;
|
||||
int n, s = sizeof(char *);
|
||||
|
||||
if (ctx->path_stride)
|
||||
s = ctx->path_stride;
|
||||
|
||||
/* we only need to check if a match is not active */
|
||||
for (n = 0; !ctx->path_match && n < ctx->count_paths; n++) {
|
||||
for (n = 0; !ctx->path_match &&
|
||||
n < ctx->pst[ctx->pst_sp].count_paths; n++) {
|
||||
ctx->wildcount = 0;
|
||||
p = ctx->path;
|
||||
q = ctx->paths[n];
|
||||
|
||||
q = *((char **)(((char *)ctx->pst[ctx->pst_sp].paths) + (n * s)));
|
||||
|
||||
while (*p && *q) {
|
||||
if (*q != '*') {
|
||||
if (*p != *q)
|
||||
|
@ -170,7 +181,7 @@ lejp_check_path_match(struct lejp_ctx *ctx)
|
|||
continue;
|
||||
|
||||
ctx->path_match = n + 1;
|
||||
ctx->path_match_len = ctx->ppos;
|
||||
ctx->path_match_len = ctx->pst[ctx->pst_sp].ppos;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -188,7 +199,7 @@ lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
|
|||
|
||||
n = ctx->wild[wildcard];
|
||||
|
||||
while (--len && n < ctx->ppos &&
|
||||
while (--len && n < ctx->pst[ctx->pst_sp].ppos &&
|
||||
(n == ctx->wild[wildcard] || ctx->path[n] != '.'))
|
||||
*dest++ = ctx->path[n++];
|
||||
|
||||
|
@ -222,8 +233,8 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
static const char esc_tran[] = "\"\\/\b\f\n\r\t";
|
||||
static const char tokens[] = "rue alse ull ";
|
||||
|
||||
if (!ctx->sp && !ctx->ppos)
|
||||
ctx->callback(ctx, LEJPCB_START);
|
||||
if (!ctx->sp && !ctx->pst[ctx->pst_sp].ppos)
|
||||
ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_START);
|
||||
|
||||
while (len--) {
|
||||
c = *json++;
|
||||
|
@ -252,7 +263,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
ret = LEJP_REJECT_IDLE_NO_BRACE;
|
||||
goto reject;
|
||||
}
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -284,7 +295,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
}
|
||||
if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
|
||||
ctx->buf[ctx->npos] = '\0';
|
||||
if (ctx->callback(ctx,
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx,
|
||||
LEJPCB_VAL_STR_END) < 0) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
|
@ -391,10 +402,10 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
goto reject;
|
||||
}
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE;
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_PAIR_NAME)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_PAIR_NAME)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -415,7 +426,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
c = LEJP_MP_STRING;
|
||||
ctx->npos = 0;
|
||||
ctx->buf[0] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_STR_START)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_STR_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -426,7 +437,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
c = LEJP_MEMBERS;
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -437,10 +448,10 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
/* push */
|
||||
ctx->st[ctx->sp].s = LEJP_MP_ARRAY_END;
|
||||
c = LEJP_MP_VALUE;
|
||||
ctx->path[ctx->ppos++] = '[';
|
||||
ctx->path[ctx->ppos++] = ']';
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_ARRAY_START)) {
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '[';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos++] = ']';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_START)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -464,12 +475,12 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
}
|
||||
/* drop the path [n] bit */
|
||||
if (ctx->sp) {
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->ipos = ctx->st[ctx->sp - 1].i;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
|
@ -544,12 +555,12 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
|
||||
ctx->buf[ctx->npos] = '\0';
|
||||
if (ctx->f & LEJP_SEEN_POINT) {
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
} else {
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_NUM_INT)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_NUM_INT)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -580,7 +591,7 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
case 3:
|
||||
ctx->buf[0] = '1';
|
||||
ctx->buf[1] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_TRUE)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_TRUE)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -588,14 +599,14 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
case 8:
|
||||
ctx->buf[0] = '0';
|
||||
ctx->buf[1] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_FALSE)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_FALSE)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
ctx->buf[0] = '\0';
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_NULL)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_NULL)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -605,12 +616,12 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
break;
|
||||
|
||||
case LEJP_MP_COMMA_OR_END:
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (c == ',') {
|
||||
/* increment this stack level's index */
|
||||
ctx->st[ctx->sp].s = LEJP_M_P;
|
||||
if (!ctx->sp) {
|
||||
ctx->ppos = 0;
|
||||
ctx->pst[ctx->pst_sp].ppos = 0;
|
||||
/*
|
||||
* since we came back to root level,
|
||||
* no path can still match
|
||||
|
@ -618,10 +629,10 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
ctx->path_match = 0;
|
||||
break;
|
||||
}
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
|
@ -649,12 +660,12 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
}
|
||||
/* drop the path [n] bit */
|
||||
if (ctx->sp) {
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->ipos = ctx->st[ctx->sp - 1].i;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
|
@ -667,11 +678,11 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
if (c == '}') {
|
||||
if (!ctx->sp) {
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_END)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
if (ctx->callback(ctx, LEJPCB_COMPLETE))
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_COMPLETE))
|
||||
goto reject;
|
||||
else
|
||||
/* done, return unused amount */
|
||||
|
@ -680,19 +691,19 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
/* pop */
|
||||
ctx->sp--;
|
||||
if (ctx->sp) {
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->ipos = ctx->st[ctx->sp - 1].i;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (ctx->path_match &&
|
||||
ctx->ppos <= ctx->path_match_len)
|
||||
ctx->pst[ctx->pst_sp].ppos <= ctx->path_match_len)
|
||||
/*
|
||||
* we shrank the path to be
|
||||
* smaller than the matching point
|
||||
*/
|
||||
ctx->path_match = 0;
|
||||
lejp_check_path_match(ctx);
|
||||
if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_OBJECT_END)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -704,15 +715,15 @@ lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
|
|||
|
||||
case LEJP_MP_ARRAY_END:
|
||||
array_end:
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
if (c == ',') {
|
||||
/* increment this stack level's index */
|
||||
if (ctx->ipos)
|
||||
ctx->i[ctx->ipos - 1]++;
|
||||
ctx->st[ctx->sp].s = LEJP_MP_VALUE;
|
||||
if (ctx->sp)
|
||||
ctx->ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->pst[ctx->pst_sp].ppos = ctx->st[ctx->sp - 1].p;
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
break;
|
||||
}
|
||||
if (c != ']') {
|
||||
|
@ -721,7 +732,7 @@ array_end:
|
|||
}
|
||||
|
||||
ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
|
||||
ctx->callback(ctx, LEJPCB_ARRAY_END);
|
||||
ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_ARRAY_END);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -732,7 +743,7 @@ emit_string_char:
|
|||
/* assemble the string value into chunks */
|
||||
ctx->buf[ctx->npos++] = c;
|
||||
if (ctx->npos == sizeof(ctx->buf) - 1) {
|
||||
if (ctx->callback(ctx, LEJPCB_VAL_STR_CHUNK)) {
|
||||
if (ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_VAL_STR_CHUNK)) {
|
||||
ret = LEJP_REJECT_CALLBACK;
|
||||
goto reject;
|
||||
}
|
||||
|
@ -741,22 +752,22 @@ emit_string_char:
|
|||
continue;
|
||||
}
|
||||
/* name part of name:value pair */
|
||||
ctx->path[ctx->ppos++] = c;
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos++] = c;
|
||||
continue;
|
||||
|
||||
add_stack_level:
|
||||
/* push on to the object stack */
|
||||
if (ctx->ppos && ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END &&
|
||||
if (ctx->pst[ctx->pst_sp].ppos && ctx->st[ctx->sp].s != LEJP_MP_COMMA_OR_END &&
|
||||
ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
|
||||
ctx->path[ctx->ppos++] = '.';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos++] = '.';
|
||||
|
||||
ctx->st[ctx->sp].p = ctx->ppos;
|
||||
ctx->st[ctx->sp].p = ctx->pst[ctx->pst_sp].ppos;
|
||||
ctx->st[ctx->sp].i = ctx->ipos;
|
||||
if (++ctx->sp == LWS_ARRAY_SIZE(ctx->st)) {
|
||||
ret = LEJP_REJECT_STACK_OVERFLOW;
|
||||
goto reject;
|
||||
}
|
||||
ctx->path[ctx->ppos] = '\0';
|
||||
ctx->path[ctx->pst[ctx->pst_sp].ppos] = '\0';
|
||||
ctx->st[ctx->sp].s = c;
|
||||
ctx->st[ctx->sp].b = 0;
|
||||
continue;
|
||||
|
@ -777,10 +788,55 @@ redo_character:
|
|||
return LEJP_CONTINUE;
|
||||
|
||||
reject:
|
||||
ctx->callback(ctx, LEJPCB_FAILED);
|
||||
ctx->pst[ctx->pst_sp].callback(ctx, LEJPCB_FAILED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
lejp_parser_push(struct lejp_ctx *ctx, void *user, const char * const *paths,
|
||||
unsigned char paths_count, lejp_callback lejp_cb)
|
||||
{
|
||||
struct _lejp_parsing_stack *p;
|
||||
|
||||
if (ctx->pst_sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
|
||||
return -1;
|
||||
|
||||
lejp_check_path_match(ctx);
|
||||
|
||||
ctx->pst[ctx->pst_sp].path_match = ctx->path_match;
|
||||
ctx->pst_sp++;
|
||||
|
||||
p = &ctx->pst[ctx->pst_sp];
|
||||
p->user = user;
|
||||
p->callback = lejp_cb;
|
||||
p->paths = paths;
|
||||
p->count_paths = paths_count;
|
||||
p->ppos = 0;
|
||||
|
||||
ctx->path_match = 0;
|
||||
lejp_check_path_match(ctx);
|
||||
|
||||
lwsl_debug("%s: pushed parser stack to %d (path %s)\n", __func__,
|
||||
ctx->pst_sp, ctx->path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lejp_parser_pop(struct lejp_ctx *ctx)
|
||||
{
|
||||
if (!ctx->pst_sp)
|
||||
return -1;
|
||||
|
||||
ctx->pst_sp--;
|
||||
lwsl_debug("%s: popped parser stack to %d\n", __func__, ctx->pst_sp);
|
||||
|
||||
ctx->path_match = 0; /* force it to check */
|
||||
lejp_check_path_match(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
lejp_error_to_string(int e)
|
||||
{
|
||||
|
|
762
lib/misc/lws-struct-lejp.c
Normal file
762
lib/misc/lws-struct-lejp.c
Normal file
|
@ -0,0 +1,762 @@
|
|||
/*
|
||||
* libwebsockets - lws_struct JSON serialization helpers
|
||||
*
|
||||
* Copyright (C) 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <core/private.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
signed char
|
||||
lws_struct_schema_only_lejp_cb(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
lws_struct_args_t *a = (lws_struct_args_t *)ctx->user;
|
||||
const lws_struct_map_t *map = a->map_st[ctx->pst_sp];
|
||||
int n = a->map_entries_st[ctx->pst_sp];
|
||||
lejp_callback cb = map->lejp_cb;
|
||||
|
||||
if (reason != LEJPCB_VAL_STR_END || ctx->path_match != 1)
|
||||
return 0;
|
||||
|
||||
while (n--) {
|
||||
if (strcmp(ctx->buf, map->colname)) {
|
||||
map++;
|
||||
continue;
|
||||
}
|
||||
|
||||
a->dest = lwsac_use_zero(&a->ac, map->aux, a->ac_block_size);
|
||||
if (!a->dest) {
|
||||
lwsl_err("%s: OOT\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
a->dest_len = map->aux;
|
||||
|
||||
if (!cb)
|
||||
cb = lws_struct_default_lejp_cb;
|
||||
|
||||
lejp_parser_push(ctx, a->dest, &map->child_map[0].colname,
|
||||
(uint8_t)map->child_map_size, cb);
|
||||
a->map_st[ctx->pst_sp] = map->child_map;
|
||||
a->map_entries_st[ctx->pst_sp] = map->child_map_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lwsl_notice("%s: unknown schema %s\n", __func__, ctx->buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_struct_lejp_push(struct lejp_ctx *ctx, lws_struct_args_t *args,
|
||||
const lws_struct_map_t *map, uint8_t *ch)
|
||||
{
|
||||
lejp_callback cb = map->lejp_cb;
|
||||
|
||||
if (!cb)
|
||||
cb = lws_struct_default_lejp_cb;
|
||||
|
||||
lejp_parser_push(ctx, ch, (const char * const*)map->child_map,
|
||||
(uint8_t)map->child_map_size, cb);
|
||||
|
||||
args->map_st[ctx->pst_sp] = map->child_map;
|
||||
args->map_entries_st[ctx->pst_sp] = map->child_map_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
signed char
|
||||
lws_struct_default_lejp_cb(struct lejp_ctx *ctx, char reason)
|
||||
{
|
||||
lws_struct_args_t *args = (lws_struct_args_t *)ctx->user;
|
||||
const lws_struct_map_t *map, *pmap = NULL;
|
||||
uint8_t *ch;
|
||||
char *u;
|
||||
int n;
|
||||
|
||||
if (reason == LEJPCB_ARRAY_END) {
|
||||
lejp_parser_pop(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_ARRAY_START) {
|
||||
map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
|
||||
n = args->map_entries_st[ctx->pst_sp];
|
||||
|
||||
if (map->type == LSMT_LIST)
|
||||
lws_struct_lejp_push(ctx, args, map, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->pst_sp)
|
||||
pmap = &args->map_st[ctx->pst_sp - 1]
|
||||
[ctx->pst[ctx->pst_sp - 1].path_match - 1];
|
||||
map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
|
||||
n = args->map_entries_st[ctx->pst_sp];
|
||||
|
||||
if (reason == LEJPCB_OBJECT_START) {
|
||||
|
||||
if (map->type != LSMT_CHILD_PTR) {
|
||||
ctx->pst[ctx->pst_sp].user = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
pmap = map;
|
||||
|
||||
lws_struct_lejp_push(ctx, args, map, NULL);
|
||||
map = &args->map_st[ctx->pst_sp][ctx->path_match - 1];
|
||||
n = args->map_entries_st[ctx->pst_sp];
|
||||
}
|
||||
|
||||
if (reason == LEJPCB_OBJECT_END && pmap && pmap->type == LSMT_CHILD_PTR)
|
||||
lejp_parser_pop(ctx);
|
||||
|
||||
if (map->type == LSMT_SCHEMA) {
|
||||
|
||||
while (n--) {
|
||||
if (strcmp(map->colname, ctx->buf)) {
|
||||
map++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* instantiate the correct toplevel object */
|
||||
|
||||
ch = lwsac_use_zero(&args->ac, map->aux,
|
||||
args->ac_block_size);
|
||||
if (!ch) {
|
||||
lwsl_err("OOM\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_struct_lejp_push(ctx, args, map, ch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
lwsl_notice("%s: unknown schema\n", __func__);
|
||||
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!ctx->pst[ctx->pst_sp].user) {
|
||||
struct lws_dll2_owner *owner;
|
||||
struct lws_dll2 *list;
|
||||
|
||||
/* create list item object if none already */
|
||||
|
||||
if (!ctx->path_match || !pmap)
|
||||
return 0;
|
||||
|
||||
map = &args->map_st[ctx->pst_sp - 1][ctx->path_match - 1];
|
||||
n = args->map_entries_st[ctx->pst_sp - 1];
|
||||
|
||||
if (pmap->type != LSMT_LIST && pmap->type != LSMT_CHILD_PTR)
|
||||
return 1;
|
||||
|
||||
/* we need to create a child or array item object */
|
||||
|
||||
owner = (struct lws_dll2_owner *)
|
||||
(((char *)ctx->pst[ctx->pst_sp - 1].user) + pmap->ofs);
|
||||
|
||||
assert(pmap->aux);
|
||||
|
||||
/* instantiate one of the child objects */
|
||||
|
||||
ctx->pst[ctx->pst_sp].user = lwsac_use_zero(&args->ac,
|
||||
pmap->aux, args->ac_block_size);
|
||||
if (!ctx->pst[ctx->pst_sp].user) {
|
||||
lwsl_err("OOM\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
lwsl_notice("%s: created child object size %d\n", __func__,
|
||||
(int)pmap->aux);
|
||||
|
||||
if (pmap->type == LSMT_LIST) {
|
||||
list = (struct lws_dll2 *)((char *)ctx->pst[ctx->pst_sp].user +
|
||||
map->ofs_clist);
|
||||
|
||||
lws_dll2_add_tail(list, owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ctx->path_match)
|
||||
return 0;
|
||||
|
||||
if (reason == LEJPCB_VAL_STR_CHUNK) {
|
||||
lejp_collation_t *coll;
|
||||
|
||||
/* don't cache stuff we are going to ignore */
|
||||
|
||||
if (map->type == LSMT_STRING_CHAR_ARRAY &&
|
||||
args->chunks_length >= map->aux)
|
||||
return 0;
|
||||
|
||||
coll = lwsac_use_zero(&args->ac_chunks, sizeof(*coll),
|
||||
sizeof(*coll));
|
||||
if (!coll) {
|
||||
lwsl_err("%s: OOT\n", __func__);
|
||||
|
||||
return 1;
|
||||
}
|
||||
coll->chunks.prev = NULL;
|
||||
coll->chunks.next = NULL;
|
||||
coll->chunks.owner = NULL;
|
||||
|
||||
coll->len = ctx->npos;
|
||||
lws_dll2_add_tail(&coll->chunks, &args->chunks_owner);
|
||||
|
||||
memcpy(coll->buf, ctx->buf, ctx->npos);
|
||||
|
||||
args->chunks_length += ctx->npos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (reason != LEJPCB_VAL_STR_END && reason != LEJPCB_VAL_NUM_INT &&
|
||||
reason != LEJPCB_VAL_TRUE && reason != LEJPCB_VAL_FALSE)
|
||||
return 0;
|
||||
|
||||
/* this is the end of the string */
|
||||
|
||||
if (ctx->pst[ctx->pst_sp].user && pmap && pmap->type == LSMT_CHILD_PTR) {
|
||||
void **pp = (void **)
|
||||
(((char *)ctx->pst[ctx->pst_sp - 1].user) + pmap->ofs);
|
||||
|
||||
*pp = ctx->pst[ctx->pst_sp].user;
|
||||
}
|
||||
|
||||
u = (char *)ctx->pst[ctx->pst_sp].user;
|
||||
if (!u)
|
||||
u = (char *)ctx->pst[ctx->pst_sp - 1].user;
|
||||
|
||||
{
|
||||
char **pp, *s;
|
||||
size_t lim, b;
|
||||
long long li;
|
||||
|
||||
switch (map->type) {
|
||||
case LSMT_SIGNED:
|
||||
if (map->aux == sizeof(signed char)) {
|
||||
signed char *pc;
|
||||
pc = (signed char *)(u + map->ofs);
|
||||
*pc = atoi(ctx->buf);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(int)) {
|
||||
int *pi;
|
||||
pi = (int *)(u + map->ofs);
|
||||
*pi = atoi(ctx->buf);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(long)) {
|
||||
long *pl;
|
||||
pl = (long *)(u + map->ofs);
|
||||
*pl = atol(ctx->buf);
|
||||
} else {
|
||||
long long *pll;
|
||||
pll = (long long *)(u + map->ofs);
|
||||
*pll = atoll(ctx->buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_UNSIGNED:
|
||||
if (map->aux == sizeof(unsigned char)) {
|
||||
unsigned char *pc;
|
||||
pc = (unsigned char *)(u + map->ofs);
|
||||
*pc = atoi(ctx->buf);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(unsigned int)) {
|
||||
unsigned int *pi;
|
||||
pi = (unsigned int *)(u + map->ofs);
|
||||
*pi = atoi(ctx->buf);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(unsigned long)) {
|
||||
unsigned long *pl;
|
||||
pl = (unsigned long *)(u + map->ofs);
|
||||
*pl = atol(ctx->buf);
|
||||
} else {
|
||||
unsigned long long *pll;
|
||||
pll = (unsigned long long *)(u + map->ofs);
|
||||
*pll = atoll(ctx->buf);
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_BOOLEAN:
|
||||
li = reason == LEJPCB_VAL_TRUE;
|
||||
if (map->aux == sizeof(char)) {
|
||||
char *pc;
|
||||
pc = (char *)(u + map->ofs);
|
||||
*pc = (char)li;
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(int)) {
|
||||
int *pi;
|
||||
pi = (int *)(u + map->ofs);
|
||||
*pi = (int)li;
|
||||
} else {
|
||||
uint64_t *p64;
|
||||
p64 = (uint64_t *)(u + map->ofs);
|
||||
*p64 = li;
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_STRING_CHAR_ARRAY:
|
||||
s = (char *)(u + map->ofs);
|
||||
lim = map->aux - 1;
|
||||
goto chunk_copy;
|
||||
|
||||
case LSMT_STRING_PTR:
|
||||
pp = (char **)(u + map->ofs);
|
||||
lim = args->chunks_length + ctx->npos;
|
||||
s = lwsac_use(&args->ac, lim + 1, args->ac_block_size);
|
||||
if (!s)
|
||||
goto cleanup;
|
||||
*pp = s;
|
||||
|
||||
chunk_copy:
|
||||
s[lim] = '\0';
|
||||
/* copy up to lim from the string chunk ac first */
|
||||
lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1,
|
||||
args->chunks_owner.head) {
|
||||
lejp_collation_t *coll = (lejp_collation_t *)p;
|
||||
|
||||
if (lim) {
|
||||
b = coll->len;
|
||||
if (b > lim)
|
||||
b = lim;
|
||||
memcpy(s, coll->buf, b);
|
||||
s += b;
|
||||
lim -= b;
|
||||
}
|
||||
} lws_end_foreach_dll_safe(p, p1);
|
||||
|
||||
lwsac_free(&args->ac_chunks);
|
||||
args->chunks_owner.count = 0;
|
||||
args->chunks_owner.head = NULL;
|
||||
args->chunks_owner.tail = NULL;
|
||||
|
||||
if (lim) {
|
||||
b = ctx->npos;
|
||||
if (b > lim)
|
||||
b = lim;
|
||||
memcpy(s, ctx->buf, b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (args->cb)
|
||||
args->cb(args->dest, args->cb_arg);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
lwsl_notice("%s: cleanup\n", __func__);
|
||||
lwsac_free(&args->ac_chunks);
|
||||
args->chunks_owner.count = 0;
|
||||
args->chunks_owner.head = NULL;
|
||||
args->chunks_owner.tail = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char * schema[] = { "schema" };
|
||||
|
||||
int
|
||||
lws_struct_json_init_parse(struct lejp_ctx *ctx, lejp_callback cb, void *user)
|
||||
{
|
||||
if (!cb)
|
||||
cb = lws_struct_schema_only_lejp_cb;
|
||||
lejp_construct(ctx, cb, user, schema, 1);
|
||||
|
||||
ctx->path_stride = sizeof(lws_struct_map_t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_struct_serialize_t *
|
||||
lws_struct_json_serialize_create(const lws_struct_map_t *map,
|
||||
size_t map_entries, int flags,
|
||||
void *ptoplevel)
|
||||
{
|
||||
lws_struct_serialize_t *js = lws_zalloc(sizeof(*js), __func__);
|
||||
lws_struct_serialize_st_t *j;
|
||||
|
||||
if (!js)
|
||||
return NULL;
|
||||
|
||||
js->flags = flags;
|
||||
|
||||
j = &js->st[0];
|
||||
j->map = map;
|
||||
j->map_entries = map_entries;
|
||||
j->obj = ptoplevel;
|
||||
j->idt = 0;
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
void
|
||||
lws_struct_json_serialize_destroy(lws_struct_serialize_t **pjs)
|
||||
{
|
||||
if (!*pjs)
|
||||
return;
|
||||
|
||||
lws_free(*pjs);
|
||||
|
||||
*pjs = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_struct_pretty(lws_struct_serialize_t *js, uint8_t **pbuf, size_t *plen)
|
||||
{
|
||||
if (js->flags & LSSERJ_FLAG_PRETTY) {
|
||||
int n;
|
||||
|
||||
*(*pbuf)++ = '\n';
|
||||
(*plen)--;
|
||||
for (n = 0; n < js->st[js->sp].idt; n++) {
|
||||
*(*pbuf)++ = ' ';
|
||||
(*plen)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lws_struct_json_serialize_result_t
|
||||
lws_struct_json_serialize(lws_struct_serialize_t *js, uint8_t *buf,
|
||||
size_t len, size_t *written)
|
||||
{
|
||||
lws_struct_serialize_st_t *j;
|
||||
const lws_struct_map_t *map;
|
||||
size_t budget = 0, olen = len;
|
||||
struct lws_dll2_owner *o;
|
||||
unsigned long long uli;
|
||||
const char *q;
|
||||
const void *p;
|
||||
char dbuf[72];
|
||||
long long li;
|
||||
int n;
|
||||
|
||||
*written = 0;
|
||||
*buf = '\0';
|
||||
|
||||
while (len > sizeof(dbuf) + 20) {
|
||||
j = &js->st[js->sp];
|
||||
map = &j->map[j->map_entry];
|
||||
q = j->obj + map->ofs;
|
||||
|
||||
/* early check if the entry should be elided */
|
||||
|
||||
switch (map->type) {
|
||||
case LSMT_STRING_PTR:
|
||||
case LSMT_CHILD_PTR:
|
||||
q = (char *)*(char **)q;
|
||||
if (!q)
|
||||
goto up;
|
||||
break;
|
||||
|
||||
case LSMT_LIST:
|
||||
o = (struct lws_dll2_owner *)q;
|
||||
p = j->dllpos = lws_dll2_get_head(o);
|
||||
if (!p)
|
||||
goto up;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (j->subsequent) {
|
||||
*buf++ = ',';
|
||||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
}
|
||||
j->subsequent = 1;
|
||||
|
||||
if (map->type != LSMT_SCHEMA && !js->offset) {
|
||||
n = lws_snprintf((char *)buf, len, "\"%s\":",
|
||||
map->colname);
|
||||
buf += n;
|
||||
len -= n;
|
||||
if (js->flags & LSSERJ_FLAG_PRETTY) {
|
||||
*buf++ = ' ';
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
switch (map->type) {
|
||||
case LSMT_BOOLEAN:
|
||||
case LSMT_UNSIGNED:
|
||||
if (map->aux == sizeof(char)) {
|
||||
uli = *(unsigned char *)q;
|
||||
} else {
|
||||
if (map->aux == sizeof(int)) {
|
||||
uli = *(unsigned int *)q;
|
||||
} else {
|
||||
if (map->aux == sizeof(long))
|
||||
uli = *(unsigned long *)q;
|
||||
else
|
||||
uli = *(unsigned long long *)q;
|
||||
}
|
||||
}
|
||||
q = dbuf;
|
||||
|
||||
if (map->type == LSMT_BOOLEAN) {
|
||||
budget = lws_snprintf(dbuf, sizeof(dbuf),
|
||||
"%s", uli ? "true" : "false");
|
||||
} else
|
||||
budget = lws_snprintf(dbuf, sizeof(dbuf),
|
||||
"%llu", uli);
|
||||
break;
|
||||
|
||||
case LSMT_SIGNED:
|
||||
if (map->aux == sizeof(signed char)) {
|
||||
li = (long long)*(signed char *)q;
|
||||
} else {
|
||||
if (map->aux == sizeof(int)) {
|
||||
li = (long long)*(int *)q;
|
||||
} else {
|
||||
if (map->aux == sizeof(long))
|
||||
li = (long long)*(long *)q;
|
||||
else
|
||||
li = *(long long *)q;
|
||||
}
|
||||
}
|
||||
q = dbuf;
|
||||
budget = lws_snprintf(dbuf, sizeof(dbuf), "%lld", li);
|
||||
break;
|
||||
|
||||
case LSMT_STRING_CHAR_ARRAY:
|
||||
budget = strlen(q);
|
||||
if (!js->offset) {
|
||||
*buf++ = '\"';
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_STRING_PTR:
|
||||
budget = strlen(q);
|
||||
if (!js->offset) {
|
||||
*buf++ = '\"';
|
||||
len--;
|
||||
}
|
||||
break;
|
||||
case LSMT_LIST:
|
||||
*buf++ = '[';
|
||||
len--;
|
||||
if (js->sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
|
||||
return LSJS_RESULT_ERROR;
|
||||
|
||||
/* add a stack level to handle parsing array members */
|
||||
|
||||
o = (struct lws_dll2_owner *)q;
|
||||
p = j->dllpos = lws_dll2_get_head(o);
|
||||
|
||||
if (!j->dllpos) {
|
||||
*buf++ = ']';
|
||||
len--;
|
||||
goto up;
|
||||
}
|
||||
|
||||
n = j->idt;
|
||||
j = &js->st[++js->sp];
|
||||
j->idt = n + 2;
|
||||
j->map = map->child_map;
|
||||
j->map_entries = map->child_map_size;
|
||||
j->size = map->aux;
|
||||
j->subsequent = 0;
|
||||
j->map_entry = 0;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
*buf++ = '{';
|
||||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
if (p)
|
||||
j->obj = ((char *)p) - j->map->ofs_clist;
|
||||
else
|
||||
j->obj = NULL;
|
||||
continue;
|
||||
|
||||
case LSMT_CHILD_PTR:
|
||||
|
||||
if (js->sp + 1 == LEJP_MAX_PARSING_STACK_DEPTH)
|
||||
return LSJS_RESULT_ERROR;
|
||||
|
||||
/* add a stack level tto handle parsing child members */
|
||||
|
||||
n = j->idt;
|
||||
j = &js->st[++js->sp];
|
||||
j->idt = n + 2;
|
||||
j->map = map->child_map;
|
||||
j->map_entries = map->child_map_size;
|
||||
j->size = map->aux;
|
||||
j->subsequent = 0;
|
||||
j->map_entry = 0;
|
||||
*buf++ = '{';
|
||||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
j->obj = q;
|
||||
continue;
|
||||
|
||||
case LSMT_SCHEMA:
|
||||
q = dbuf;
|
||||
*buf++ = '{';
|
||||
len--;
|
||||
j = &js->st[++js->sp];
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
budget = lws_snprintf(dbuf, 15, "\"schema\":");
|
||||
if (js->flags & LSSERJ_FLAG_PRETTY)
|
||||
dbuf[budget++] = ' ';
|
||||
|
||||
budget += lws_snprintf(dbuf + budget,
|
||||
sizeof(dbuf) - budget,
|
||||
"\"%s\"", map->colname);
|
||||
|
||||
|
||||
if (js->sp != 1)
|
||||
return LSJS_RESULT_ERROR;
|
||||
j->map = map->child_map;
|
||||
j->map_entries = map->child_map_size;
|
||||
j->size = map->aux;
|
||||
j->subsequent = 0;
|
||||
j->map_entry = 0;
|
||||
j->obj = js->st[js->sp - 1].obj;
|
||||
j->dllpos = NULL;
|
||||
/* we're actually at the same level */
|
||||
j->subsequent = 1;
|
||||
j->idt = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
q += js->offset;
|
||||
budget -= js->remaining;
|
||||
|
||||
if (budget > len) {
|
||||
js->remaining = budget - len;
|
||||
js->offset = len;
|
||||
budget = len;
|
||||
} else {
|
||||
js->remaining = 0;
|
||||
js->offset = 0;
|
||||
}
|
||||
|
||||
memcpy(buf, q, budget);
|
||||
buf += budget;
|
||||
*buf = '\0';
|
||||
len -= budget;
|
||||
|
||||
switch (map->type) {
|
||||
case LSMT_STRING_CHAR_ARRAY:
|
||||
case LSMT_STRING_PTR:
|
||||
*buf++ = '\"';
|
||||
len--;
|
||||
break;
|
||||
case LSMT_SCHEMA:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (js->remaining)
|
||||
continue;
|
||||
up:
|
||||
if (++j->map_entry < j->map_entries)
|
||||
continue;
|
||||
|
||||
if (!js->sp)
|
||||
continue;
|
||||
js->sp--;
|
||||
if (!js->sp) {
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
*buf++ = '}';
|
||||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
break;
|
||||
}
|
||||
js->offset = 0;
|
||||
j = &js->st[js->sp];
|
||||
map = &j->map[j->map_entry];
|
||||
|
||||
if (map->type == LSMT_CHILD_PTR) {
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
*buf++ = '}';
|
||||
len--;
|
||||
|
||||
/* we have done the singular child pointer */
|
||||
|
||||
js->offset = 0;
|
||||
goto up;
|
||||
}
|
||||
|
||||
if (map->type != LSMT_LIST)
|
||||
continue;
|
||||
/*
|
||||
* we are coming back up to an array map, it means we should
|
||||
* advance to the next array member if there is one
|
||||
*/
|
||||
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
*buf++ = '}';
|
||||
len--;
|
||||
|
||||
p = j->dllpos = j->dllpos->next;
|
||||
if (j->dllpos) {
|
||||
/*
|
||||
* there was another item in the array to do... let's
|
||||
* move on to that nd do it
|
||||
*/
|
||||
*buf++ = ',';
|
||||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
js->offset = 0;
|
||||
j = &js->st[++js->sp];
|
||||
j->map_entry = 0;
|
||||
map = &j->map[j->map_entry];
|
||||
|
||||
*buf++ = '{';
|
||||
len--;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
|
||||
j->subsequent = 0;
|
||||
j->obj = ((char *)p) - j->map->ofs_clist;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* there are no further items in the array */
|
||||
|
||||
js->offset = 0;
|
||||
lws_struct_pretty(js, &buf, &len);
|
||||
*buf++ = ']';
|
||||
len--;
|
||||
goto up;
|
||||
}
|
||||
|
||||
*written = olen - len;
|
||||
*buf = '\0'; /* convenience, a NUL after the official end */
|
||||
|
||||
return LSJS_RESULT_FINISH;
|
||||
}
|
275
lib/misc/lws-struct-sqlite.c
Normal file
275
lib/misc/lws-struct-sqlite.c
Normal file
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* libwebsockets - lws_struct JSON serialization helpers
|
||||
*
|
||||
* Copyright (C) 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation:
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <core/private.h>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
/*
|
||||
* we get one of these per matching result from the query
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_struct_sq3_deser_cb(void *priv, int cols, char **cv, char **cn)
|
||||
{
|
||||
lws_struct_args_t *a = (lws_struct_args_t *)priv;
|
||||
const lws_struct_map_t *map = a->map_st[0];
|
||||
int n, mems = a->map_entries_st[0];
|
||||
lws_dll2_owner_t *o = (lws_dll2_owner_t *)a->cb_arg;
|
||||
char *u = lwsac_use_zero(&a->ac, a->dest_len, a->ac_block_size);
|
||||
long long li;
|
||||
size_t lim;
|
||||
char **pp;
|
||||
char *s;
|
||||
|
||||
if (!u) {
|
||||
lwsl_err("OOM\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_dll2_add_tail((lws_dll2_t *)((char *)u + a->toplevel_dll2_ofs), o);
|
||||
|
||||
while (mems--) {
|
||||
for (n = 0; n < cols; n++) {
|
||||
if (!cv[n] || strcmp(cn[n], map->colname))
|
||||
continue;
|
||||
|
||||
switch (map->type) {
|
||||
case LSMT_SIGNED:
|
||||
if (map->aux == sizeof(signed char)) {
|
||||
signed char *pc;
|
||||
pc = (signed char *)(u + map->ofs);
|
||||
*pc = atoi(cv[n]);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(int)) {
|
||||
int *pi;
|
||||
pi = (int *)(u + map->ofs);
|
||||
*pi = atoi(cv[n]);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(long)) {
|
||||
long *pl;
|
||||
pl = (long *)(u + map->ofs);
|
||||
*pl = atol(cv[n]);
|
||||
break;
|
||||
}
|
||||
{
|
||||
long long *pll;
|
||||
pll = (long long *)(u + map->ofs);
|
||||
*pll = atoll(cv[n]);
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_UNSIGNED:
|
||||
if (map->aux == sizeof(unsigned char)) {
|
||||
unsigned char *pc;
|
||||
pc = (unsigned char *)(u + map->ofs);
|
||||
*pc = atoi(cv[n]);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(unsigned int)) {
|
||||
unsigned int *pi;
|
||||
pi = (unsigned int *)(u + map->ofs);
|
||||
*pi = atoi(cv[n]);
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(unsigned long)) {
|
||||
unsigned long *pl;
|
||||
pl = (unsigned long *)(u + map->ofs);
|
||||
*pl = atol(cv[n]);
|
||||
break;
|
||||
}
|
||||
{
|
||||
unsigned long long *pll;
|
||||
pll = (unsigned long long *)(u + map->ofs);
|
||||
*pll = atoll(cv[n]);
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_BOOLEAN:
|
||||
li = 0;
|
||||
if (!strcmp(cv[n], "true") ||
|
||||
!strcmp(cv[n], "TRUE") || cv[n][0] == '1')
|
||||
li = 1;
|
||||
if (map->aux == sizeof(char)) {
|
||||
char *pc;
|
||||
pc = (char *)(u + map->ofs);
|
||||
*pc = (char)li;
|
||||
break;
|
||||
}
|
||||
if (map->aux == sizeof(int)) {
|
||||
int *pi;
|
||||
pi = (int *)(u + map->ofs);
|
||||
*pi = (int)li;
|
||||
} else {
|
||||
uint64_t *p64;
|
||||
p64 = (uint64_t *)(u + map->ofs);
|
||||
*p64 = li;
|
||||
}
|
||||
break;
|
||||
|
||||
case LSMT_STRING_CHAR_ARRAY:
|
||||
s = (char *)(u + map->ofs);
|
||||
lim = map->aux - 1;
|
||||
lws_strncpy(s, cv[n], lim);
|
||||
break;
|
||||
|
||||
case LSMT_STRING_PTR:
|
||||
pp = (char **)(u + map->ofs);
|
||||
lim = strlen(cv[n]);
|
||||
s = lwsac_use(&a->ac, lim + 1, a->ac_block_size);
|
||||
if (!s)
|
||||
return 1;
|
||||
*pp = s;
|
||||
memcpy(s, cv[n], lim);
|
||||
s[lim] = '\0';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
map++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this with an LSM_SCHEMA map, its colname is the table name and its
|
||||
* type information describes the toplevel type. Schema is dereferenced and
|
||||
* put in args before the actual sq3 query, which is given the child map.
|
||||
*/
|
||||
|
||||
int
|
||||
lws_struct_sq3_deserialize(sqlite3 *pdb, const lws_struct_map_t *schema,
|
||||
lws_dll2_owner_t *o, struct lwsac **ac,
|
||||
uint64_t start, int limit)
|
||||
{
|
||||
char s[150], where[32];
|
||||
lws_struct_args_t a;
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
a.cb_arg = o; /* lws_dll2_owner tracking query result objects */
|
||||
a.map_st[0] = schema->child_map;
|
||||
a.map_entries_st[0] = schema->child_map_size;
|
||||
a.dest_len = schema->aux; /* size of toplevel object to allocate */
|
||||
a.toplevel_dll2_ofs = schema->ofs;
|
||||
|
||||
lws_dll2_owner_clear(o);
|
||||
|
||||
where[0] = '\0';
|
||||
if (start)
|
||||
lws_snprintf(where, sizeof(where), " where when < %llu ",
|
||||
(unsigned long long)start);
|
||||
|
||||
lws_snprintf(s, sizeof(s) - 1, "select * "
|
||||
"from %s %s order by created desc limit %d;",
|
||||
schema->colname, where, limit);
|
||||
|
||||
if (sqlite3_exec(pdb, s, lws_struct_sq3_deser_cb, &a, NULL) != SQLITE_OK) {
|
||||
lwsl_err("%s: fail\n", sqlite3_errmsg(pdb));
|
||||
lwsac_free(&a.ac);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ac = a.ac;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_struct_sq3_create_table(sqlite3 *pdb, const lws_struct_map_t *schema)
|
||||
{
|
||||
const lws_struct_map_t *map = schema->child_map;
|
||||
int map_size = schema->child_map_size, subsequent = 0;
|
||||
char s[2048], *p = s, *end = &s[sizeof(s) - 1], *pri = "primary key";
|
||||
|
||||
p += lws_snprintf(p, end - p, "create table if not exists %s (",
|
||||
schema->colname);
|
||||
|
||||
while (map_size--) {
|
||||
if (map->type > LSMT_STRING_PTR) {
|
||||
map++;
|
||||
continue;
|
||||
}
|
||||
if (subsequent && (end - p) > 3)
|
||||
*p++ = ',';
|
||||
subsequent = 1;
|
||||
if (map->type < LSMT_STRING_CHAR_ARRAY)
|
||||
p += lws_snprintf(p, end - p, "%s integer %s",
|
||||
map->colname, pri);
|
||||
else
|
||||
p += lws_snprintf(p, end - p, "%s varchar %s",
|
||||
map->colname, pri);
|
||||
pri = "";
|
||||
map++;
|
||||
}
|
||||
|
||||
p += lws_snprintf(p, end - p, ");");
|
||||
|
||||
if (sqlite3_exec(pdb, s, NULL, NULL, NULL) != SQLITE_OK) {
|
||||
lwsl_err("%s: %s: fail\n", __func__, sqlite3_errmsg(pdb));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_struct_sq3_open(struct lws_context *context, const char *sqlite3_path,
|
||||
sqlite3 **pdb)
|
||||
{
|
||||
int uid = 0, gid = 0;
|
||||
|
||||
if (sqlite3_open_v2(sqlite3_path, pdb,
|
||||
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
|
||||
NULL) != SQLITE_OK) {
|
||||
lwsl_err("%s: Unable to open db %s: %s\n",
|
||||
__func__, sqlite3_path, sqlite3_errmsg(*pdb));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lws_get_effective_uid_gid(context, &uid, &gid);
|
||||
if (uid)
|
||||
chown(sqlite3_path, uid, gid);
|
||||
chmod(sqlite3_path, 0600);
|
||||
|
||||
sqlite3_extended_result_codes(*pdb, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
lws_struct_sq3_close(sqlite3 **pdb)
|
||||
{
|
||||
if (!*pdb)
|
||||
return 0;
|
||||
|
||||
sqlite3_close(*pdb);
|
||||
*pdb = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -158,6 +158,7 @@ lwsac_free(struct lwsac **head)
|
|||
{
|
||||
struct lwsac *it = *head;
|
||||
|
||||
*head = NULL;
|
||||
lwsl_debug("%s: head %p\n", __func__, *head);
|
||||
|
||||
while (it) {
|
||||
|
@ -166,14 +167,15 @@ lwsac_free(struct lwsac **head)
|
|||
free(it);
|
||||
it = tmp;
|
||||
}
|
||||
|
||||
*head = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lwsac_info(struct lwsac *head)
|
||||
{
|
||||
lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head,
|
||||
if (!head)
|
||||
lwsl_debug("%s: empty\n", __func__);
|
||||
else
|
||||
lwsl_debug("%s: lac %p: %dKiB in %d blocks\n", __func__, head,
|
||||
(int)(head->total_alloc_size >> 10), head->total_blocks);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ These are buildable test apps that run in CI to confirm correct api operation.
|
|||
|name|tests|
|
||||
---|---
|
||||
api-test-lwsac|LWS Allocated Chunks api
|
||||
api-test-lws_struct-json|Selftests for lws_struct JSON serialization and deserialization
|
||||
api-test-lws_tokenize|Generic secure string tokenizer api
|
||||
api-test-fts|LWS Full-text Search api
|
||||
api-test-gencrypto|LWS Generic Crypto apis
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-api-test-lws_struct-json)
|
||||
set(SRCS main.c)
|
||||
|
||||
# If we are being built as part of lws, confirm current build config supports
|
||||
# reqconfig, else skip building ourselves.
|
||||
#
|
||||
# If we are being built externally, confirm installed lws was configured to
|
||||
# support reqconfig, else error out with a helpful message about the problem.
|
||||
#
|
||||
MACRO(require_lws_config reqconfig _val result)
|
||||
|
||||
if (DEFINED ${reqconfig})
|
||||
if (${reqconfig})
|
||||
set (rq 1)
|
||||
else()
|
||||
set (rq 0)
|
||||
endif()
|
||||
else()
|
||||
set(rq 0)
|
||||
endif()
|
||||
|
||||
if (${_val} EQUAL ${rq})
|
||||
set(SAME 1)
|
||||
else()
|
||||
set(SAME 0)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
|
||||
if (${_val})
|
||||
message("${SAMP}: skipping as lws being built without ${reqconfig}")
|
||||
else()
|
||||
message("${SAMP}: skipping as lws built with ${reqconfig}")
|
||||
endif()
|
||||
set(${result} 0)
|
||||
else()
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES)
|
||||
set(MET ${SAME})
|
||||
else()
|
||||
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
|
||||
if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
|
||||
set(HAS_${reqconfig} 0)
|
||||
else()
|
||||
set(HAS_${reqconfig} 1)
|
||||
endif()
|
||||
if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
|
||||
set(MET 1)
|
||||
else()
|
||||
set(MET 0)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT MET)
|
||||
if (${_val})
|
||||
message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
|
||||
else()
|
||||
message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
ENDMACRO()
|
||||
|
||||
|
||||
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared)
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets)
|
||||
endif()
|
|
@ -0,0 +1,56 @@
|
|||
# lws api test lws_struct JSON
|
||||
|
||||
Demonstrates how to use and performs selftests for lws_struct
|
||||
JSON serialization and deserialization
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
Commandline option|Meaning
|
||||
---|---
|
||||
-d <loglevel>|Debug verbosity in decimal, eg, -d15
|
||||
|
||||
```
|
||||
$ ./lws-api-test-lws_struct-json
|
||||
[2019/03/30 22:09:09:2529] USER: LWS API selftest: lws_struct JSON
|
||||
[2019/03/30 22:09:09:2625] NOTICE: main: ++++++++++++++++ test 1
|
||||
[2019/03/30 22:09:09:2812] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (2)
|
||||
[2019/03/30 22:09:09:2822] NOTICE: target.name 'target1' (target 0x543a830)
|
||||
[2019/03/30 22:09:09:2824] NOTICE: target.name 'target2' (target 0x543a860)
|
||||
[2019/03/30 22:09:09:2826] NOTICE: main: .... strarting serialization of test 1
|
||||
[2019/03/30 22:09:09:2899] NOTICE: ser says 1
|
||||
{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1"},{"name":"target2"}]}
|
||||
[2019/03/30 22:09:09:2929] NOTICE: main: ++++++++++++++++ test 2
|
||||
[2019/03/30 22:09:09:2932] NOTICE: builder.hostname = 'learn', timeout = 0, targets (3)
|
||||
[2019/03/30 22:09:09:2932] NOTICE: target.name 'target1' (target 0x543b060)
|
||||
[2019/03/30 22:09:09:2933] NOTICE: target.name 'target2' (target 0x543b090)
|
||||
[2019/03/30 22:09:09:2933] NOTICE: target.name 'target3' (target 0x543b0c0)
|
||||
[2019/03/30 22:09:09:2934] NOTICE: main: .... strarting serialization of test 2
|
||||
[2019/03/30 22:09:09:2935] NOTICE: ser says 1
|
||||
{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":0,"targets":[{"name":"target1"},{"name":"target2"},{"name":"target3"}]}
|
||||
[2019/03/30 22:09:09:2940] NOTICE: main: ++++++++++++++++ test 3
|
||||
[2019/03/30 22:09:09:2959] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (2)
|
||||
[2019/03/30 22:09:09:2960] NOTICE: target.name 'target1' (target 0x543b450)
|
||||
[2019/03/30 22:09:09:2961] NOTICE: child 0x543b480, target.child.somename 'abc'
|
||||
[2019/03/30 22:09:09:2961] NOTICE: target.name 'target2' (target 0x543b490)
|
||||
[2019/03/30 22:09:09:2962] NOTICE: main: .... strarting serialization of test 3
|
||||
[2019/03/30 22:09:09:2969] NOTICE: ser says 1
|
||||
{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800,"targets":[{"name":"target1","child":{"somename":"abc"}},{"name":"target2"}]}
|
||||
[2019/03/30 22:09:09:2970] NOTICE: main: ++++++++++++++++ test 4
|
||||
[2019/03/30 22:09:09:2971] NOTICE: builder.hostname = 'learn', timeout = 1800, targets (0)
|
||||
[2019/03/30 22:09:09:2971] NOTICE: main: .... strarting serialization of test 4
|
||||
[2019/03/30 22:09:09:2973] NOTICE: ser says 1
|
||||
{"schema":"com-warmcat-sai-builder","hostname":"learn","nspawn_timeout":1800}
|
||||
[2019/03/30 22:09:09:2974] NOTICE: main: ++++++++++++++++ test 5
|
||||
[2019/03/30 22:09:09:2978] NOTICE: builder.hostname = '', timeout = 0, targets (0)
|
||||
[2019/03/30 22:09:09:2979] NOTICE: main: .... strarting serialization of test 5
|
||||
[2019/03/30 22:09:09:2980] NOTICE: ser says 1
|
||||
{"schema":"com-warmcat-sai-builder","hostname":"","nspawn_timeout":0}
|
||||
[2019/03/30 22:09:09:2982] USER: Completed: PASS
|
||||
```
|
||||
|
365
minimal-examples/api-tests/api-test-lws_struct-json/main.c
Normal file
365
minimal-examples/api-tests/api-test-lws_struct-json/main.c
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* lws-api-test-lws_struct-json
|
||||
*
|
||||
* Copyright (C) 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* The API test shows how to serialize and deserialize a struct with a linked-
|
||||
* list of child structs in JSON using lws_struct APIs.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
|
||||
/*
|
||||
* in this example, the JSON is for one "builder" object, which may specify
|
||||
* a child list "targets" of zero or more "target" objects.
|
||||
*/
|
||||
|
||||
static const char * const json_tests[] = {
|
||||
"{" /* test 1 */
|
||||
"\"schema\":\"com-warmcat-sai-builder\","
|
||||
|
||||
"\"hostname\":\"learn\","
|
||||
"\"nspawn_timeout\":1800,"
|
||||
"\"targets\":["
|
||||
"{"
|
||||
"\"name\":\"target1\","
|
||||
"\"someflag\":true"
|
||||
"},"
|
||||
"{"
|
||||
"\"name\":\"target2\","
|
||||
"\"someflag\":false"
|
||||
"}"
|
||||
"]"
|
||||
"}",
|
||||
"{" /* test 2 */
|
||||
"\"schema\":\"com-warmcat-sai-builder\","
|
||||
|
||||
"\"hostname\":\"learn\","
|
||||
"\"targets\":["
|
||||
"{"
|
||||
"\"name\":\"target1\""
|
||||
"},"
|
||||
"{"
|
||||
"\"name\":\"target2\""
|
||||
"},"
|
||||
"{"
|
||||
"\"name\":\"target3\""
|
||||
"}"
|
||||
"]"
|
||||
"}", "{" /* test 3 */
|
||||
"\"schema\":\"com-warmcat-sai-builder\","
|
||||
|
||||
"\"hostname\":\"learn\","
|
||||
"\"nspawn_timeout\":1800,"
|
||||
"\"targets\":["
|
||||
"{"
|
||||
"\"name\":\"target1\","
|
||||
"\"unrecognized\":\"xyz\","
|
||||
"\"child\": {"
|
||||
"\"somename\": \"abc\","
|
||||
"\"junk\": { \"x\": \"y\" }"
|
||||
"}"
|
||||
"},"
|
||||
"{"
|
||||
"\"name\":\"target2\""
|
||||
"}"
|
||||
"]"
|
||||
"}",
|
||||
"{" /* test 4 */
|
||||
"\"schema\":\"com-warmcat-sai-builder\","
|
||||
|
||||
"\"hostname\":\"learn\","
|
||||
"\"nspawn_timeout\":1800"
|
||||
"}",
|
||||
"{" /* test 5 */
|
||||
"\"schema\":\"com-warmcat-sai-builder\""
|
||||
"}",
|
||||
"{" /* test 6 ... check huge strings into smaller fixed char array */
|
||||
"\"schema\":\"com-warmcat-sai-builder\","
|
||||
"\"hostname\":\""
|
||||
"PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6A"
|
||||
"zefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/"
|
||||
"CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr5"
|
||||
"3FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV"
|
||||
"8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1"
|
||||
"NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIG"
|
||||
"JYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkG"
|
||||
"LUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MW"
|
||||
"v+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9"
|
||||
"eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsY"
|
||||
"VkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/"
|
||||
"uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yu"
|
||||
"yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx"
|
||||
"+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\""
|
||||
"}",
|
||||
"{" /* test 7 ... check huge strings into char * */
|
||||
"\"schema\":\"com-warmcat-sai-builder\","
|
||||
"\"targets\":["
|
||||
"{"
|
||||
"\"name\":\""
|
||||
"PYvtan6kqppjnS0KpYTCaiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6A"
|
||||
"zefzoWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9D1QKIWqg5RJ/"
|
||||
"CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6bzhA+A/xAsFzSBnb3MHYWzGMprr5"
|
||||
"3FAP1ISo5Ec9i+2ehV40sG6Q470sH3PGQZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV"
|
||||
"8sq3ZgcxKNB7tNfN7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1"
|
||||
"NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEhdZgxky2+g5hhlSIG"
|
||||
"JYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/RrfOV+oV4R26IDq+KqUiJBENeo8/GXkG"
|
||||
"LUH/87iPyzXKEMavr6fkrK0vTGto8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MW"
|
||||
"v+B/t1eZZ+1euLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZvstK9"
|
||||
"eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6O/grHnvJZm2vBkxuXgsY"
|
||||
"VkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0WaCqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/"
|
||||
"uZjjEGGLhJR1jPqA9D1Ej3ChV+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yu"
|
||||
"yJln+v4RIWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5vMETteZlx"
|
||||
"+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\"}]}"
|
||||
"}",
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the expected outputs for each test, without pretty formatting.
|
||||
*
|
||||
* There are some differences to do with missing elements being rendered with
|
||||
* default values.
|
||||
*/
|
||||
|
||||
static const char * const json_expected[] = {
|
||||
"{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"learn\","
|
||||
"\"nspawn_timeout\":1800,\"targets\":[{\"name\":\"target1\",\"someflag\":true},"
|
||||
"{\"name\":\"target2\",\"someflag\":false}]}",
|
||||
|
||||
"{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"learn\","
|
||||
"\"nspawn_timeout\":0,\"targets\":[{\"name\":\"target1\",\"someflag\":false},"
|
||||
"{\"name\":\"target2\",\"someflag\":false},{\"name\":\"target3\",\"someflag\":false}]}",
|
||||
|
||||
"{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"learn\","
|
||||
"\"nspawn_timeout\":1800,\"targets\":[{\"name\":\"target1\",\"someflag\":false,"
|
||||
"\"child\":{\"somename\":\"abc\"}},{\"name\":\"target2\",\"someflag\":false}]}",
|
||||
|
||||
"{\"schema\":\"com-warmcat-sai-builder\","
|
||||
"\"hostname\":\"learn\",\"nspawn_timeout\":1800}",
|
||||
|
||||
"{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"\","
|
||||
"\"nspawn_timeout\":0}",
|
||||
|
||||
"{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":"
|
||||
"\"PYvtan6kqppjnS0KpYTCaiOLsJkc7Xe\","
|
||||
"\"nspawn_timeout\":0}",
|
||||
|
||||
"{\"schema\":\"com-warmcat-sai-builder\",\"hostname\":\"\","
|
||||
"\"nspawn_timeout\":0,\"targets\":[{\"name\":\"PYvtan6kqppjnS0KpYTC"
|
||||
"aiOLsJkc7XecAr1kcE0aCIciewYB+JcLG82mO1Vb1mJtjDwUjBxy2I6Azefz"
|
||||
"oWUWmqZbsv4MXR55j9bKlyz1liiSX63iO0x6JAwACMtE2MkgcLwR86TSWAD9"
|
||||
"D1QKIWqg5RJ/CRuVsW0DKAUMD52ql4JmPFuJpJgTq28z6PhYNzN3yI3bmQt6"
|
||||
"bzhA+A/xAsFzSBnb3MHYWzGMprr53FAP1ISo5Ec9i+2ehV40sG6Q470sH3PG"
|
||||
"QZ0YRPO7Sh/SyrSQ/scONmxRc3AcXl7X/CSs417ii+CV8sq3ZgcxKNB7tNfN"
|
||||
"7idNx3upZ00G2BZy9jSy03cLKKLNaNUt0TQsxXbH55uDHzSEeZWvxJgT6zB1"
|
||||
"NoMhdC02w+oXim94M6z6COCnqT3rgkGk8PHMry9Bkh4yVpRmzIRfMmln/lEh"
|
||||
"dZgxky2+g5hhlSIGJYDCrdynD9kCfvfy6KGOpNIi1X+mhbbWn4lnL9ZKihL/"
|
||||
"RrfOV+oV4R26IDq+KqUiJBENeo8/GXkGLUH/87iPyzXKEMavr6fkrK0vTGto"
|
||||
"8yEYxmOyaVz8phG5rwf4jJgmYNoMbGo8gWvhqO7UAGy2g7MWv+B/t1eZZ+1e"
|
||||
"uLsNrWAsFJiFbQKgdFfQT3RjB14iU8knlQ8usoy+pXssY2ddGJGVcGC21oZv"
|
||||
"stK9eu1eRZftda/wP+N5unT1Hw7kCoVzqxHieiYt47EGIOaaQ7XjZDK6qPN6"
|
||||
"O/grHnvJZm2vBkxuXgsYVkRQ7AuTWIecphqFsq7Wbc1YNbMW47SVU5zMD0Wa"
|
||||
"CqbaaI0t4uIzRvPlD8cpiiTzFTrEHlIBTf8/uZjjEGGLhJR1jPqA9D1Ej3Ch"
|
||||
"V+ye6F9JTUMlozRMsGuF8U4btDzH5xdnmvRS4Ar6LKEtAXGkj2yuyJln+v4R"
|
||||
"IWj2xOGPJovOqiXwi0FyM61f8U8gj0OiNA2/QlvrqQVDF7sMXgjvaE7iQt5v"
|
||||
"METteZlx+z3f+jTFM/aon511W4+ZkRD+6AHwucvM9BEC\""
|
||||
",\"someflag\":false}]}"
|
||||
};
|
||||
|
||||
/*
|
||||
* These annotate the members in the struct that will be serialized and
|
||||
* deserialized with type and size information, as well as the name to use
|
||||
* in the serialization format.
|
||||
*
|
||||
* Struct members that aren't annotated like this won't be serialized and
|
||||
* when the struct is created during deserialiation, the will be set to 0
|
||||
* or NULL.
|
||||
*/
|
||||
|
||||
/* child object */
|
||||
|
||||
typedef struct sai_child {
|
||||
const char * somename;
|
||||
} sai_child_t;
|
||||
|
||||
lws_struct_map_t lsm_child[] = { /* describes serializable members */
|
||||
LSM_STRING_PTR (sai_child_t, somename, "somename"),
|
||||
};
|
||||
|
||||
/* target object */
|
||||
|
||||
typedef struct sai_target {
|
||||
struct lws_dll2 target_list;
|
||||
sai_child_t * child;
|
||||
|
||||
const char * name;
|
||||
char someflag;
|
||||
} sai_target_t;
|
||||
|
||||
static const lws_struct_map_t lsm_target[] = {
|
||||
LSM_STRING_PTR (sai_target_t, name, "name"),
|
||||
LSM_BOOLEAN (sai_target_t, someflag, "someflag"),
|
||||
LSM_CHILD_PTR (sai_target_t, child, sai_child_t,
|
||||
NULL, lsm_child, "child"),
|
||||
};
|
||||
|
||||
/* builder object */
|
||||
|
||||
typedef struct sai_builder {
|
||||
struct lws_dll2_owner targets;
|
||||
|
||||
char hostname[32];
|
||||
unsigned int nspawn_timeout;
|
||||
} sai_builder_t;
|
||||
|
||||
static const lws_struct_map_t lsm_builder[] = {
|
||||
LSM_CARRAY (sai_builder_t, hostname, "hostname"),
|
||||
LSM_UNSIGNED (sai_builder_t, nspawn_timeout, "nspawn_timeout"),
|
||||
LSM_LIST (sai_builder_t, targets,
|
||||
sai_target_t, target_list,
|
||||
NULL, lsm_target, "targets"),
|
||||
};
|
||||
|
||||
/* Schema table
|
||||
*
|
||||
* Before we can understand the serialization top level format, we must read
|
||||
* the schema, use the table below to create the right toplevel object for the
|
||||
* schema name, and select the correct map tables to interpret the rest of the
|
||||
* serialization.
|
||||
*
|
||||
* Therefore the schema tables below are the starting point for the
|
||||
* JSON deserialization.
|
||||
*/
|
||||
|
||||
static const lws_struct_map_t lsm_schema_map[] = {
|
||||
LSM_SCHEMA (sai_builder_t, NULL,
|
||||
lsm_builder, "com-warmcat-sai-builder"),
|
||||
};
|
||||
|
||||
static int
|
||||
show_target(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
sai_target_t *t = lws_container_of(d, sai_target_t, target_list);
|
||||
|
||||
lwsl_notice(" target.name '%s' (target %p)\n", t->name, t);
|
||||
|
||||
if (t->child)
|
||||
lwsl_notice(" child %p, target.child.somename '%s'\n",
|
||||
t->child, t->child->somename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int n, m, e = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
||||
#if 1
|
||||
lws_struct_serialize_t *ser;
|
||||
uint8_t buf[4096];
|
||||
size_t written;
|
||||
#endif
|
||||
struct lejp_ctx ctx;
|
||||
lws_struct_args_t a;
|
||||
sai_builder_t *b;
|
||||
const char *p;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS API selftest: lws_struct JSON\n");
|
||||
|
||||
for (m = 0; m < (int)LWS_ARRAY_SIZE(json_tests); m++) {
|
||||
|
||||
/* 1. deserialize the canned JSON into structs */
|
||||
|
||||
lwsl_notice("%s: ++++++++++++++++ test %d\n", __func__, m + 1);
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
a.map_st[0] = lsm_schema_map;
|
||||
a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_map);
|
||||
a.ac_block_size = 512;
|
||||
|
||||
lws_struct_json_init_parse(&ctx, NULL, &a);
|
||||
n = (int)(signed char)lejp_parse(&ctx, (uint8_t *)json_tests[m],
|
||||
strlen(json_tests[m]));
|
||||
if (n < 0) {
|
||||
lwsl_err("%s: notification JSON decode failed '%s'\n",
|
||||
__func__, lejp_error_to_string(n));
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
lwsac_info(a.ac);
|
||||
|
||||
b = a.dest;
|
||||
if (!b) {
|
||||
lwsl_err("%s: didn't produce any output\n", __func__);
|
||||
e++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
lwsl_notice("builder.hostname = '%s', timeout = %d, targets (%d)\n",
|
||||
b->hostname, b->nspawn_timeout,
|
||||
b->targets.count);
|
||||
|
||||
lws_dll2_foreach_safe(&b->targets, NULL, show_target);
|
||||
|
||||
/* 2. serialize the structs into JSON and confirm */
|
||||
|
||||
lwsl_notice("%s: .... strarting serialization of test %d\n",
|
||||
__func__, m + 1);
|
||||
ser = lws_struct_json_serialize_create(lsm_schema_map,
|
||||
LWS_ARRAY_SIZE(lsm_schema_map),
|
||||
0//LSSERJ_FLAG_PRETTY
|
||||
, b);
|
||||
if (!ser) {
|
||||
lwsl_err("%s: unable to init serialization\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
do {
|
||||
n = lws_struct_json_serialize(ser, buf, sizeof(buf),
|
||||
&written);
|
||||
lwsl_notice("ser says %d\n", n);
|
||||
switch (n) {
|
||||
case LSJS_RESULT_CONTINUE:
|
||||
case LSJS_RESULT_FINISH:
|
||||
puts((const char *)buf);
|
||||
break;
|
||||
case LSJS_RESULT_ERROR:
|
||||
goto bail;
|
||||
}
|
||||
} while(n == LSJS_RESULT_CONTINUE);
|
||||
|
||||
if (strcmp(json_expected[m], (char *)buf)) {
|
||||
lwsl_err("%s: test %d: expected %s\n", __func__, m + 1,
|
||||
json_expected[m]);
|
||||
e++;
|
||||
}
|
||||
|
||||
lws_struct_json_serialize_destroy(&ser);
|
||||
|
||||
done:
|
||||
lwsac_free(&a.ac);
|
||||
}
|
||||
|
||||
if (e)
|
||||
goto bail;
|
||||
|
||||
lwsl_user("Completed: PASS\n");
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lwsl_user("Completed: FAIL\n");
|
||||
|
||||
return 1;
|
||||
}
|
24
minimal-examples/api-tests/api-test-lws_struct-json/selftest.sh
Executable file
24
minimal-examples/api-tests/api-test-lws_struct-json/selftest.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# $1: path to minimal example binaries...
|
||||
# if lws is built with -DLWS_WITH_MINIMAL_EXAMPLES=1
|
||||
# that will be ./bin from your build dir
|
||||
#
|
||||
# $2: path for logs and results. The results will go
|
||||
# in a subdir named after the directory this script
|
||||
# is in
|
||||
#
|
||||
# $3: offset for test index count
|
||||
#
|
||||
# $4: total test count
|
||||
#
|
||||
# $5: path to ./minimal-examples dir in lws
|
||||
#
|
||||
# Test return code 0: OK, 254: timed out, other: error indication
|
||||
|
||||
. $5/selftests-library.sh
|
||||
|
||||
COUNT_TESTS=1
|
||||
|
||||
dotest $1 $2 apiselftest
|
||||
exit $FAILS
|
Loading…
Add table
Reference in a new issue