summaryrefslogtreecommitdiff
path: root/thirdparty/libwebsockets/misc
diff options
context:
space:
mode:
authorRémi Verschelde <rverschelde@gmail.com>2019-05-02 08:15:23 +0200
committerGitHub <noreply@github.com>2019-05-02 08:15:23 +0200
commitb7cd9794fe5b38b6a60c9ce64ca9bf1bab1d7813 (patch)
tree3b0f365ad3ea1cebd50985293cd49617153b5ac6 /thirdparty/libwebsockets/misc
parentc2c56ee3975ec9744088d5328462818a5980a5a0 (diff)
parentbe414e4476371567a824099767b6c91a0123d626 (diff)
Merge pull request #28568 from Faless/net/lws_rollback_3.0.1_pr
Roll back libwebsockets to version 3.0.1
Diffstat (limited to 'thirdparty/libwebsockets/misc')
-rw-r--r--thirdparty/libwebsockets/misc/base64-decode.c242
-rw-r--r--thirdparty/libwebsockets/misc/getifaddrs.c270
-rw-r--r--thirdparty/libwebsockets/misc/getifaddrs.h80
-rw-r--r--thirdparty/libwebsockets/misc/lejp.c753
-rw-r--r--thirdparty/libwebsockets/misc/sha-1.c300
5 files changed, 1645 insertions, 0 deletions
diff --git a/thirdparty/libwebsockets/misc/base64-decode.c b/thirdparty/libwebsockets/misc/base64-decode.c
new file mode 100644
index 0000000000..64b84d78fa
--- /dev/null
+++ b/thirdparty/libwebsockets/misc/base64-decode.c
@@ -0,0 +1,242 @@
+/*
+ * This code originally came from here
+ *
+ * http://base64.sourceforge.net/b64.c
+ *
+ * with the following license:
+ *
+ * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the
+ * Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+ * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+ * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * VERSION HISTORY:
+ * Bob Trower 08/04/01 -- Create Version 0.00.00B
+ *
+ * I cleaned it up quite a bit to match the (linux kernel) style of the rest
+ * of libwebsockets; this version is under LGPL2.1 + SLE like the rest of lws
+ * since he explicitly allows sublicensing, but I give the URL above so you can
+ * get the original with Bob's super-liberal terms directly if you prefer.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "core/private.h"
+
+static const char encode_orig[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char encode_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz0123456789-_";
+static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
+ "$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+
+static int
+_lws_b64_encode_string(const char *encode, const char *in, int in_len,
+ char *out, int out_size)
+{
+ unsigned char triple[3];
+ int i;
+ int len;
+ int line = 0;
+ int done = 0;
+
+ while (in_len) {
+ len = 0;
+ for (i = 0; i < 3; i++) {
+ if (in_len) {
+ triple[i] = *in++;
+ len++;
+ in_len--;
+ } else
+ triple[i] = 0;
+ }
+
+ if (done + 4 >= out_size)
+ return -1;
+
+ *out++ = encode[triple[0] >> 2];
+ *out++ = encode[((triple[0] & 0x03) << 4) |
+ ((triple[1] & 0xf0) >> 4)];
+ *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
+ ((triple[2] & 0xc0) >> 6)] : '=');
+ *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
+
+ done += 4;
+ line += 4;
+ }
+
+ if (done + 1 >= out_size)
+ return -1;
+
+ *out++ = '\0';
+
+ return done;
+}
+
+LWS_VISIBLE int
+lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
+{
+ return _lws_b64_encode_string(encode_orig, in, in_len, out, out_size);
+}
+
+LWS_VISIBLE int
+lws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size)
+{
+ return _lws_b64_encode_string(encode_url, in, in_len, out, out_size);
+}
+
+/*
+ * returns length of decoded string in out, or -1 if out was too small
+ * according to out_size
+ *
+ * Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
+ * the first NUL in the input.
+ */
+
+static int
+_lws_b64_decode_string(const char *in, int in_len, char *out, int out_size)
+{
+ int len, i, c = 0, done = 0;
+ unsigned char v, quad[4];
+
+ while (in_len && *in) {
+
+ len = 0;
+ for (i = 0; i < 4 && in_len && *in; i++) {
+
+ v = 0;
+ c = 0;
+ while (in_len && *in && !v) {
+ c = v = *in++;
+ in_len--;
+ /* support the url base64 variant too */
+ if (v == '-')
+ c = v = '+';
+ if (v == '_')
+ c = v = '/';
+ v = (v < 43 || v > 122) ? 0 : decode[v - 43];
+ if (v)
+ v = (v == '$') ? 0 : v - 61;
+ }
+ if (c) {
+ len++;
+ if (v)
+ quad[i] = v - 1;
+ } else
+ quad[i] = 0;
+ }
+
+ if (out_size < (done + len - 1))
+ /* out buffer is too small */
+ return -1;
+
+ /*
+ * "The '==' sequence indicates that the last group contained
+ * only one byte, and '=' indicates that it contained two
+ * bytes." (wikipedia)
+ */
+
+ if ((!in_len || !*in) && c == '=')
+ len--;
+
+ if (len >= 2)
+ *out++ = quad[0] << 2 | quad[1] >> 4;
+ if (len >= 3)
+ *out++ = quad[1] << 4 | quad[2] >> 2;
+ if (len >= 4)
+ *out++ = ((quad[2] << 6) & 0xc0) | quad[3];
+
+ done += len - 1;
+ }
+
+ if (done + 1 >= out_size)
+ return -1;
+
+ *out = '\0';
+
+ return done;
+}
+
+LWS_VISIBLE int
+lws_b64_decode_string(const char *in, char *out, int out_size)
+{
+ return _lws_b64_decode_string(in, -1, out, out_size);
+}
+
+LWS_VISIBLE int
+lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size)
+{
+ return _lws_b64_decode_string(in, in_len, out, out_size);
+}
+
+#if 0
+int
+lws_b64_selftest(void)
+{
+ char buf[64];
+ unsigned int n, r = 0;
+ unsigned int test;
+ /* examples from https://en.wikipedia.org/wiki/Base64 */
+ static const char * const plaintext[] = {
+ "any carnal pleasure.",
+ "any carnal pleasure",
+ "any carnal pleasur",
+ "any carnal pleasu",
+ "any carnal pleas",
+ "Admin:kloikloi"
+ };
+ static const char * const coded[] = {
+ "YW55IGNhcm5hbCBwbGVhc3VyZS4=",
+ "YW55IGNhcm5hbCBwbGVhc3VyZQ==",
+ "YW55IGNhcm5hbCBwbGVhc3Vy",
+ "YW55IGNhcm5hbCBwbGVhc3U=",
+ "YW55IGNhcm5hbCBwbGVhcw==",
+ "QWRtaW46a2xvaWtsb2k="
+ };
+
+ for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) {
+
+ buf[sizeof(buf) - 1] = '\0';
+ n = lws_b64_encode_string(plaintext[test],
+ strlen(plaintext[test]), buf, sizeof buf);
+ if (n != strlen(coded[test]) || strcmp(buf, coded[test])) {
+ lwsl_err("Failed lws_b64 encode selftest "
+ "%d result '%s' %d\n", test, buf, n);
+ r = -1;
+ }
+
+ buf[sizeof(buf) - 1] = '\0';
+ n = lws_b64_decode_string(coded[test], buf, sizeof buf);
+ if (n != strlen(plaintext[test]) ||
+ strcmp(buf, plaintext[test])) {
+ lwsl_err("Failed lws_b64 decode selftest "
+ "%d result '%s' / '%s', %d / %d\n",
+ test, buf, plaintext[test], n, strlen(plaintext[test]));
+ r = -1;
+ }
+ }
+
+ lwsl_notice("Base 64 selftests passed\n");
+
+ return r;
+}
+#endif
diff --git a/thirdparty/libwebsockets/misc/getifaddrs.c b/thirdparty/libwebsockets/misc/getifaddrs.c
new file mode 100644
index 0000000000..735b899f48
--- /dev/null
+++ b/thirdparty/libwebsockets/misc/getifaddrs.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * originally downloaded from
+ *
+ * http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include "core/private.h"
+
+#ifdef LWS_HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
+#ifdef LWS_HAVE_NETINET_IN6_VAR_H
+#include <netinet/in6_var.h>
+#endif
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#include "getifaddrs.h"
+
+static int
+getifaddrs2(struct ifaddrs **ifap, int af, int siocgifconf, int siocgifflags,
+ size_t ifreq_sz)
+{
+ int ret;
+ int fd;
+ size_t buf_size;
+ char *buf;
+ struct ifconf ifconf;
+ char *p;
+ size_t sz;
+ struct sockaddr sa_zero;
+ struct ifreq *ifr;
+ struct ifaddrs *start, **end = &start;
+
+ buf = NULL;
+
+ memset(&sa_zero, 0, sizeof(sa_zero));
+ fd = socket(af, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -1;
+
+ buf_size = 8192;
+ for (;;) {
+ buf = lws_zalloc(buf_size, "getifaddrs2");
+ if (buf == NULL) {
+ ret = ENOMEM;
+ goto error_out;
+ }
+ ifconf.ifc_len = buf_size;
+ ifconf.ifc_buf = buf;
+
+ /*
+ * Solaris returns EINVAL when the buffer is too small.
+ */
+ if (ioctl(fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
+ ret = errno;
+ goto error_out;
+ }
+ /*
+ * Can the difference between a full and a overfull buf
+ * be determined?
+ */
+
+ if (ifconf.ifc_len < (int)buf_size)
+ break;
+ lws_free(buf);
+ buf_size *= 2;
+ }
+
+ for (p = ifconf.ifc_buf; p < ifconf.ifc_buf + ifconf.ifc_len; p += sz) {
+ struct ifreq ifreq;
+ struct sockaddr *sa;
+ size_t salen;
+
+ ifr = (struct ifreq *)p;
+ sa = &ifr->ifr_addr;
+
+ sz = ifreq_sz;
+ salen = sizeof(struct sockaddr);
+#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
+ salen = sa->sa_len;
+ sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
+#endif
+#ifdef SA_LEN
+ salen = SA_LEN(sa);
+ sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
+#endif
+ memset(&ifreq, 0, sizeof(ifreq));
+ memcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
+
+ if (ioctl(fd, siocgifflags, &ifreq) < 0) {
+ ret = errno;
+ goto error_out;
+ }
+
+ *end = lws_malloc(sizeof(**end), "getifaddrs");
+
+ (*end)->ifa_next = NULL;
+ (*end)->ifa_name = strdup(ifr->ifr_name);
+ (*end)->ifa_flags = ifreq.ifr_flags;
+ (*end)->ifa_addr = lws_malloc(salen, "getifaddrs");
+ memcpy((*end)->ifa_addr, sa, salen);
+ (*end)->ifa_netmask = NULL;
+
+#if 0
+ /* fix these when we actually need them */
+ if (ifreq.ifr_flags & IFF_BROADCAST) {
+ (*end)->ifa_broadaddr =
+ lws_malloc(sizeof(ifr->ifr_broadaddr), "getifaddrs");
+ memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
+ sizeof(ifr->ifr_broadaddr));
+ } else if (ifreq.ifr_flags & IFF_POINTOPOINT) {
+ (*end)->ifa_dstaddr =
+ lws_malloc(sizeof(ifr->ifr_dstaddr), "getifaddrs");
+ memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
+ sizeof(ifr->ifr_dstaddr));
+ } else
+ (*end)->ifa_dstaddr = NULL;
+#else
+ (*end)->ifa_dstaddr = NULL;
+#endif
+ (*end)->ifa_data = NULL;
+
+ end = &(*end)->ifa_next;
+
+ }
+ *ifap = start;
+ close(fd);
+ lws_free(buf);
+ return 0;
+
+error_out:
+ close(fd);
+ lws_free(buf);
+ errno = ret;
+
+ return -1;
+}
+
+int
+getifaddrs(struct ifaddrs **ifap)
+{
+ int ret = -1;
+ errno = ENXIO;
+#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
+ if (ret)
+ ret = getifaddrs2(ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
+ sizeof(struct in6_ifreq));
+#endif
+#if defined(LWS_HAVE_IPV6) && defined(SIOCGIFCONF)
+ if (ret)
+ ret = getifaddrs2(ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
+ sizeof(struct ifreq));
+#endif
+#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
+ if (ret)
+ ret = getifaddrs2(ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
+ sizeof(struct ifreq));
+#endif
+ return ret;
+}
+
+void
+freeifaddrs(struct ifaddrs *ifp)
+{
+ struct ifaddrs *p, *q;
+
+ for (p = ifp; p; ) {
+ lws_free(p->ifa_name);
+ lws_free(p->ifa_addr);
+ lws_free(p->ifa_dstaddr);
+ lws_free(p->ifa_netmask);
+ lws_free(p->ifa_data);
+ q = p;
+ p = p->ifa_next;
+ lws_free(q);
+ }
+}
+
+#ifdef TEST
+
+void
+print_addr(const char *s, struct sockaddr *sa)
+{
+ int i;
+ printf(" %s=%d/", s, sa->sa_family);
+#ifdef LWS_HAVE_STRUCT_SOCKADDR_SA_LEN
+ for (i = 0;
+ i < sa->sa_len - ((lws_intptr_t)sa->sa_data - (lws_intptr_t)&sa->sa_family); i++)
+ printf("%02x", ((unsigned char *)sa->sa_data)[i]);
+#else
+ for (i = 0; i < sizeof(sa->sa_data); i++)
+ printf("%02x", ((unsigned char *)sa->sa_data)[i]);
+#endif
+ printf("\n");
+}
+
+void
+print_ifaddrs(struct ifaddrs *x)
+{
+ struct ifaddrs *p;
+
+ for (p = x; p; p = p->ifa_next) {
+ printf("%s\n", p->ifa_name);
+ printf(" flags=%x\n", p->ifa_flags);
+ if (p->ifa_addr)
+ print_addr("addr", p->ifa_addr);
+ if (p->ifa_dstaddr)
+ print_addr("dstaddr", p->ifa_dstaddr);
+ if (p->ifa_netmask)
+ print_addr("netmask", p->ifa_netmask);
+ printf(" %p\n", p->ifa_data);
+ }
+}
+
+int
+main()
+{
+ struct ifaddrs *a = NULL, *b;
+ getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
+ sizeof(struct ifreq));
+ print_ifaddrs(a);
+ printf("---\n");
+ getifaddrs(&b);
+ print_ifaddrs(b);
+ return 0;
+}
+#endif
diff --git a/thirdparty/libwebsockets/misc/getifaddrs.h b/thirdparty/libwebsockets/misc/getifaddrs.h
new file mode 100644
index 0000000000..d26670c082
--- /dev/null
+++ b/thirdparty/libwebsockets/misc/getifaddrs.h
@@ -0,0 +1,80 @@
+#ifndef LWS_HAVE_GETIFADDRS
+#define LWS_HAVE_GETIFADDRS 0
+#endif
+
+#if LWS_HAVE_GETIFADDRS
+#include <sys/types.h>
+#include <ifaddrs.h>
+#else
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Copyright (c) 2000 Kungliga Tekniska H�gskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */
+
+#ifndef ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791
+#define ifaddrs_h_7467027A95AD4B5C8DDD40FE7D973791
+
+/*
+ * the interface is defined in terms of the fields below, and this is
+ * sometimes #define'd, so there seems to be no simple way of solving
+ * this and this seemed the best. */
+
+#undef ifa_dstaddr
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr
+#endif
+
+int getifaddrs(struct ifaddrs **);
+
+void freeifaddrs(struct ifaddrs *);
+
+#endif /* __ifaddrs_h__ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/thirdparty/libwebsockets/misc/lejp.c b/thirdparty/libwebsockets/misc/lejp.c
new file mode 100644
index 0000000000..99142b9553
--- /dev/null
+++ b/thirdparty/libwebsockets/misc/lejp.c
@@ -0,0 +1,753 @@
+/*
+ * Lightweight Embedded JSON Parser
+ *
+ * Copyright (C) 2013-2017 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 <string.h>
+#include <stdio.h>
+
+/**
+ * lejp_construct - prepare a struct lejp_ctx for use
+ *
+ * \param ctx: pointer to your struct lejp_ctx
+ * \param callback: your user callback which will received parsed tokens
+ * \param user: optional user data pointer untouched by lejp
+ * \param paths: your array of name elements you are interested in
+ * \param count_paths: LWS_ARRAY_SIZE() of @paths
+ *
+ * Prepares your context struct for use with lejp
+ */
+
+void
+lejp_construct(struct lejp_ctx *ctx,
+ signed char (*callback)(struct lejp_ctx *ctx, char reason), void *user,
+ const char * const *paths, unsigned char count_paths)
+{
+ ctx->st[0].s = 0;
+ ctx->st[0].p = 0;
+ ctx->st[0].i = 0;
+ ctx->st[0].b = 0;
+ ctx->sp = 0;
+ ctx->ipos = 0;
+ ctx->ppos = 0;
+ ctx->path_match = 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);
+}
+
+/**
+ * lejp_destruct - retire a previously constructed struct lejp_ctx
+ *
+ * \param ctx: pointer to your struct lejp_ctx
+ *
+ * lejp does not perform any allocations, but since your user code might, this
+ * provides a one-time LEJPCB_DESTRUCTED callback at destruction time where
+ * you can clean up in your callback.
+ */
+
+void
+lejp_destruct(struct lejp_ctx *ctx)
+{
+ /* no allocations... just let callback know what it happening */
+ ctx->callback(ctx, LEJPCB_DESTRUCTED);
+}
+
+/**
+ * lejp_change_callback - switch to a different callback from now on
+ *
+ * \param ctx: pointer to your struct lejp_ctx
+ * \param callback: your user callback which will received parsed tokens
+ *
+ * This tells the old callback it was destroyed, in case you want to take any
+ * action because that callback "lost focus", then changes to the new
+ * callback and tells it first that it was constructed, and then started.
+ *
+ * Changing callback is a cheap and powerful trick to split out handlers
+ * according to information earlier in the parse. For example you may have
+ * a JSON pair "schema" whose value defines what can be expected for the rest
+ * of the JSON. Rather than having one huge callback for all cases, you can
+ * have an initial one looking for "schema" which then calls
+ * lejp_change_callback() to a handler specific for the schema.
+ *
+ * Notice that afterwards, you need to construct the context again anyway to
+ * parse another JSON object, and the callback is reset then to the main,
+ * schema-interpreting one. The construction action is very lightweight.
+ */
+
+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);
+}
+
+static void
+lejp_check_path_match(struct lejp_ctx *ctx)
+{
+ const char *p, *q;
+ int n;
+
+ /* we only need to check if a match is not active */
+ for (n = 0; !ctx->path_match && n < ctx->count_paths; n++) {
+ ctx->wildcount = 0;
+ p = ctx->path;
+ q = ctx->paths[n];
+ while (*p && *q) {
+ if (*q != '*') {
+ if (*p != *q)
+ break;
+ p++;
+ q++;
+ continue;
+ }
+ ctx->wild[ctx->wildcount++] = p - ctx->path;
+ q++;
+ /*
+ * if * has something after it, match to .
+ * if ends with *, eat everything.
+ * This implies match sequences must be ordered like
+ * x.*.*
+ * x.*
+ * if both options are possible
+ */
+ while (*p && (*p != '.' || !*q))
+ p++;
+ }
+ if (*p || *q)
+ continue;
+
+ ctx->path_match = n + 1;
+ ctx->path_match_len = ctx->ppos;
+ return;
+ }
+
+ if (!ctx->path_match)
+ ctx->wildcount = 0;
+}
+
+int
+lejp_get_wildcard(struct lejp_ctx *ctx, int wildcard, char *dest, int len)
+{
+ int n;
+
+ if (wildcard >= ctx->wildcount || !len)
+ return 0;
+
+ n = ctx->wild[wildcard];
+
+ while (--len && n < ctx->ppos &&
+ (n == ctx->wild[wildcard] || ctx->path[n] != '.'))
+ *dest++ = ctx->path[n++];
+
+ *dest = '\0';
+ n++;
+
+ return n - ctx->wild[wildcard];
+}
+
+/**
+ * lejp_parse - interpret some more incoming data incrementally
+ *
+ * \param ctx: previously constructed parsing context
+ * \param json: char buffer with the new data to interpret
+ * \param len: amount of data in the buffer
+ *
+ * Because lejp is a stream parser, it incrementally parses as new data
+ * becomes available, maintaining all state in the context struct. So an
+ * incomplete JSON is a normal situation, getting you a LEJP_CONTINUE
+ * return, signalling there's no error but to call again with more data when
+ * it comes to complete the parsing. Successful parsing completes with a
+ * 0 or positive integer indicating how much of the last input buffer was
+ * unused.
+ */
+
+int
+lejp_parse(struct lejp_ctx *ctx, const unsigned char *json, int len)
+{
+ unsigned char c, n, s, ret = LEJP_REJECT_UNKNOWN;
+ static const char esc_char[] = "\"\\/bfnrt";
+ 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);
+
+ while (len--) {
+ c = *json++;
+ s = ctx->st[ctx->sp].s;
+
+ /* skip whitespace unless we should care */
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '#') {
+ if (c == '\n') {
+ ctx->line++;
+ ctx->st[ctx->sp].s &= ~LEJP_FLAG_WS_COMMENTLINE;
+ }
+ if (!(s & LEJP_FLAG_WS_KEEP)) {
+ if (c == '#')
+ ctx->st[ctx->sp].s |=
+ LEJP_FLAG_WS_COMMENTLINE;
+ continue;
+ }
+ }
+
+ if (ctx->st[ctx->sp].s & LEJP_FLAG_WS_COMMENTLINE)
+ continue;
+
+ switch (s) {
+ case LEJP_IDLE:
+ if (c != '{') {
+ ret = LEJP_REJECT_IDLE_NO_BRACE;
+ goto reject;
+ }
+ if (ctx->callback(ctx, LEJPCB_OBJECT_START)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ ctx->st[ctx->sp].s = LEJP_MEMBERS;
+ break;
+ case LEJP_MEMBERS:
+ if (c == '}') {
+ ctx->st[ctx->sp].s = LEJP_IDLE;
+ ret = LEJP_REJECT_MEMBERS_NO_CLOSE;
+ goto reject;
+ }
+ ctx->st[ctx->sp].s = LEJP_M_P;
+ goto redo_character;
+ case LEJP_M_P:
+ if (c != '\"') {
+ ret = LEJP_REJECT_MP_NO_OPEN_QUOTE;
+ goto reject;
+ }
+ /* push */
+ ctx->st[ctx->sp].s = LEJP_MP_DELIM;
+ c = LEJP_MP_STRING;
+ goto add_stack_level;
+
+ case LEJP_MP_STRING:
+ if (c == '\"') {
+ if (!ctx->sp) { /* JSON can't end on quote */
+ ret = LEJP_REJECT_MP_STRING_UNDERRUN;
+ goto reject;
+ }
+ if (ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
+ ctx->buf[ctx->npos] = '\0';
+ if (ctx->callback(ctx,
+ LEJPCB_VAL_STR_END) < 0) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ }
+ /* pop */
+ ctx->sp--;
+ break;
+ }
+ if (c == '\\') {
+ ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC;
+ break;
+ }
+ if (c < ' ') {/* "control characters" not allowed */
+ ret = LEJP_REJECT_MP_ILLEGAL_CTRL;
+ goto reject;
+ }
+ goto emit_string_char;
+
+ case LEJP_MP_STRING_ESC:
+ if (c == 'u') {
+ ctx->st[ctx->sp].s = LEJP_MP_STRING_ESC_U1;
+ ctx->uni = 0;
+ break;
+ }
+ for (n = 0; n < sizeof(esc_char); n++) {
+ if (c != esc_char[n])
+ continue;
+ /* found it */
+ c = esc_tran[n];
+ ctx->st[ctx->sp].s = LEJP_MP_STRING;
+ goto emit_string_char;
+ }
+ ret = LEJP_REJECT_MP_STRING_ESC_ILLEGAL_ESC;
+ /* illegal escape char */
+ goto reject;
+
+ case LEJP_MP_STRING_ESC_U1:
+ case LEJP_MP_STRING_ESC_U2:
+ case LEJP_MP_STRING_ESC_U3:
+ case LEJP_MP_STRING_ESC_U4:
+ ctx->uni <<= 4;
+ if (c >= '0' && c <= '9')
+ ctx->uni |= c - '0';
+ else
+ if (c >= 'a' && c <= 'f')
+ ctx->uni = c - 'a' + 10;
+ else
+ if (c >= 'A' && c <= 'F')
+ ctx->uni = c - 'A' + 10;
+ else {
+ ret = LEJP_REJECT_ILLEGAL_HEX;
+ goto reject;
+ }
+ ctx->st[ctx->sp].s++;
+ switch (s) {
+ case LEJP_MP_STRING_ESC_U2:
+ if (ctx->uni < 0x08)
+ break;
+ /*
+ * 0x08-0xff (0x0800 - 0xffff)
+ * emit 3-byte UTF-8
+ */
+ c = 0xe0 | ((ctx->uni >> 4) & 0xf);
+ goto emit_string_char;
+
+ case LEJP_MP_STRING_ESC_U3:
+ if (ctx->uni >= 0x080) {
+ /*
+ * 0x080 - 0xfff (0x0800 - 0xffff)
+ * middle 3-byte seq
+ * send ....XXXXXX..
+ */
+ c = 0x80 | ((ctx->uni >> 2) & 0x3f);
+ goto emit_string_char;
+ }
+ if (ctx->uni < 0x008)
+ break;
+ /*
+ * 0x008 - 0x7f (0x0080 - 0x07ff)
+ * start 2-byte seq
+ */
+ c = 0xc0 | (ctx->uni >> 2);
+ goto emit_string_char;
+
+ case LEJP_MP_STRING_ESC_U4:
+ if (ctx->uni >= 0x0080)
+ /* end of 2 or 3-byte seq */
+ c = 0x80 | (ctx->uni & 0x3f);
+ else
+ /* literal */
+ c = (unsigned char)ctx->uni;
+
+ ctx->st[ctx->sp].s = LEJP_MP_STRING;
+ goto emit_string_char;
+ default:
+ break;
+ }
+ break;
+
+ case LEJP_MP_DELIM:
+ if (c != ':') {
+ ret = LEJP_REJECT_MP_DELIM_MISSING_COLON;
+ goto reject;
+ }
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE;
+ ctx->path[ctx->ppos] = '\0';
+
+ lejp_check_path_match(ctx);
+ if (ctx->callback(ctx, LEJPCB_PAIR_NAME)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ break;
+
+ case LEJP_MP_VALUE:
+ if (c >= '0' && c <= '9') {
+ ctx->npos = 0;
+ ctx->dcount = 0;
+ ctx->f = 0;
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
+ goto redo_character;
+ }
+ switch (c) {
+ case'\"':
+ /* push */
+ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
+ c = LEJP_MP_STRING;
+ ctx->npos = 0;
+ ctx->buf[0] = '\0';
+ if (ctx->callback(ctx, LEJPCB_VAL_STR_START)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ goto add_stack_level;
+
+ case '{':
+ /* push */
+ 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)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ ctx->path_match = 0;
+ goto add_stack_level;
+
+ case '[':
+ /* 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)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ ctx->i[ctx->ipos++] = 0;
+ if (ctx->ipos > LWS_ARRAY_SIZE(ctx->i)) {
+ ret = LEJP_REJECT_MP_DELIM_ISTACK;
+ goto reject;
+ }
+ goto add_stack_level;
+
+ case ']':
+ /* pop */
+ if (!ctx->sp) { /* JSON can't end on ] */
+ ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
+ goto reject;
+ }
+ ctx->sp--;
+ if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
+ ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
+ goto reject;
+ }
+ /* drop the path [n] bit */
+ if (ctx->sp) {
+ ctx->ppos = ctx->st[ctx->sp - 1].p;
+ ctx->ipos = ctx->st[ctx->sp - 1].i;
+ }
+ ctx->path[ctx->ppos] = '\0';
+ if (ctx->path_match &&
+ ctx->ppos <= ctx->path_match_len)
+ /*
+ * we shrank the path to be
+ * smaller than the matching point
+ */
+ ctx->path_match = 0;
+ goto array_end;
+
+ case 't': /* true */
+ ctx->uni = 0;
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
+ break;
+
+ case 'f':
+ ctx->uni = 4;
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
+ break;
+
+ case 'n':
+ ctx->uni = 4 + 5;
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE_TOK;
+ break;
+ default:
+ ret = LEJP_REJECT_MP_DELIM_BAD_VALUE_START;
+ goto reject;
+ }
+ break;
+
+ case LEJP_MP_VALUE_NUM_INT:
+ if (!ctx->npos && c == '-') {
+ ctx->f |= LEJP_SEEN_MINUS;
+ goto append_npos;
+ }
+
+ if (ctx->dcount < 10 && c >= '0' && c <= '9') {
+ if (ctx->f & LEJP_SEEN_POINT)
+ ctx->f |= LEJP_SEEN_POST_POINT;
+ ctx->dcount++;
+ goto append_npos;
+ }
+ if (c == '.') {
+ if (!ctx->dcount || (ctx->f & LEJP_SEEN_POINT)) {
+ ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
+ goto reject;
+ }
+ ctx->f |= LEJP_SEEN_POINT;
+ goto append_npos;
+ }
+ /*
+ * before exponent, if we had . we must have had at
+ * least one more digit
+ */
+ if ((ctx->f &
+ (LEJP_SEEN_POINT | LEJP_SEEN_POST_POINT)) ==
+ LEJP_SEEN_POINT) {
+ ret = LEJP_REJECT_MP_VAL_NUM_INT_NO_FRAC;
+ goto reject;
+ }
+ if (c == 'e' || c == 'E') {
+ if (ctx->f & LEJP_SEEN_EXP) {
+ ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
+ goto reject;
+ }
+ ctx->f |= LEJP_SEEN_EXP;
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_EXP;
+ goto append_npos;
+ }
+ /* if none of the above, did we even have a number? */
+ if (!ctx->dcount) {
+ ret = LEJP_REJECT_MP_VAL_NUM_FORMAT;
+ goto reject;
+ }
+
+ ctx->buf[ctx->npos] = '\0';
+ if (ctx->f & LEJP_SEEN_POINT) {
+ if (ctx->callback(ctx, LEJPCB_VAL_NUM_FLOAT)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ } else {
+ if (ctx->callback(ctx, LEJPCB_VAL_NUM_INT)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ }
+
+ /* then this is the post-number character, loop */
+ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
+ goto redo_character;
+
+ case LEJP_MP_VALUE_NUM_EXP:
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE_NUM_INT;
+ if (c >= '0' && c <= '9')
+ goto redo_character;
+ if (c == '+' || c == '-')
+ goto append_npos;
+ ret = LEJP_REJECT_MP_VAL_NUM_EXP_BAD_EXP;
+ goto reject;
+
+ case LEJP_MP_VALUE_TOK: /* true, false, null */
+ if (c != tokens[ctx->uni]) {
+ ret = LEJP_REJECT_MP_VAL_TOK_UNKNOWN;
+ goto reject;
+ }
+ ctx->uni++;
+ if (tokens[ctx->uni] != ' ')
+ break;
+ switch (ctx->uni) {
+ case 3:
+ ctx->buf[0] = '1';
+ ctx->buf[1] = '\0';
+ if (ctx->callback(ctx, LEJPCB_VAL_TRUE)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ break;
+ case 8:
+ ctx->buf[0] = '0';
+ ctx->buf[1] = '\0';
+ if (ctx->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)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ break;
+ }
+ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
+ break;
+
+ case LEJP_MP_COMMA_OR_END:
+ ctx->path[ctx->ppos] = '\0';
+ if (c == ',') {
+ /* increment this stack level's index */
+ ctx->st[ctx->sp].s = LEJP_M_P;
+ if (!ctx->sp) {
+ ctx->ppos = 0;
+ /*
+ * since we came back to root level,
+ * no path can still match
+ */
+ ctx->path_match = 0;
+ break;
+ }
+ ctx->ppos = ctx->st[ctx->sp - 1].p;
+ ctx->path[ctx->ppos] = '\0';
+ if (ctx->path_match &&
+ ctx->ppos <= ctx->path_match_len)
+ /*
+ * we shrank the path to be
+ * smaller than the matching point
+ */
+ ctx->path_match = 0;
+
+ if (ctx->st[ctx->sp - 1].s != LEJP_MP_ARRAY_END)
+ break;
+ /* top level is definitely an array... */
+ if (ctx->ipos)
+ ctx->i[ctx->ipos - 1]++;
+ ctx->st[ctx->sp].s = LEJP_MP_VALUE;
+ break;
+ }
+ if (c == ']') {
+ if (!ctx->sp) { /* JSON can't end on ] */
+ ret = LEJP_REJECT_MP_C_OR_E_UNDERF;
+ goto reject;
+ }
+ /* pop */
+ ctx->sp--;
+ if (ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END) {
+ ret = LEJP_REJECT_MP_C_OR_E_NOTARRAY;
+ goto reject;
+ }
+ /* drop the path [n] bit */
+ if (ctx->sp) {
+ ctx->ppos = ctx->st[ctx->sp - 1].p;
+ ctx->ipos = ctx->st[ctx->sp - 1].i;
+ }
+ ctx->path[ctx->ppos] = '\0';
+ if (ctx->path_match &&
+ ctx->ppos <= ctx->path_match_len)
+ /*
+ * we shrank the path to be
+ * smaller than the matching point
+ */
+ ctx->path_match = 0;
+
+ /* do LEJP_MP_ARRAY_END processing */
+ goto redo_character;
+ }
+ if (c == '}') {
+ if (!ctx->sp) {
+ lejp_check_path_match(ctx);
+ if (ctx->callback(ctx, LEJPCB_OBJECT_END)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ ctx->callback(ctx, LEJPCB_COMPLETE);
+ /* done, return unused amount */
+ return len;
+ }
+ /* pop */
+ ctx->sp--;
+ if (ctx->sp) {
+ ctx->ppos = ctx->st[ctx->sp - 1].p;
+ ctx->ipos = ctx->st[ctx->sp - 1].i;
+ }
+ ctx->path[ctx->ppos] = '\0';
+ if (ctx->path_match &&
+ ctx->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)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ break;
+ }
+
+ ret = LEJP_REJECT_MP_C_OR_E_NEITHER;
+ goto reject;
+
+ case LEJP_MP_ARRAY_END:
+array_end:
+ ctx->path[ctx->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';
+ break;
+ }
+ if (c != ']') {
+ ret = LEJP_REJECT_MP_ARRAY_END_MISSING;
+ goto reject;
+ }
+
+ ctx->st[ctx->sp].s = LEJP_MP_COMMA_OR_END;
+ ctx->callback(ctx, LEJPCB_ARRAY_END);
+ break;
+ }
+
+ continue;
+
+emit_string_char:
+ if (!ctx->sp || ctx->st[ctx->sp - 1].s != LEJP_MP_DELIM) {
+ /* 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)) {
+ ret = LEJP_REJECT_CALLBACK;
+ goto reject;
+ }
+ ctx->npos = 0;
+ }
+ continue;
+ }
+ /* name part of name:value pair */
+ ctx->path[ctx->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 &&
+ ctx->st[ctx->sp].s != LEJP_MP_ARRAY_END)
+ ctx->path[ctx->ppos++] = '.';
+
+ ctx->st[ctx->sp].p = ctx->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->st[ctx->sp].s = c;
+ ctx->st[ctx->sp].b = 0;
+ continue;
+
+append_npos:
+ if (ctx->npos >= sizeof(ctx->buf)) {
+ ret = LEJP_REJECT_NUM_TOO_LONG;
+ goto reject;
+ }
+ ctx->buf[ctx->npos++] = c;
+ continue;
+
+redo_character:
+ json--;
+ len++;
+ }
+
+ return LEJP_CONTINUE;
+
+reject:
+ ctx->callback(ctx, LEJPCB_FAILED);
+ return ret;
+}
diff --git a/thirdparty/libwebsockets/misc/sha-1.c b/thirdparty/libwebsockets/misc/sha-1.c
new file mode 100644
index 0000000000..2e4db52693
--- /dev/null
+++ b/thirdparty/libwebsockets/misc/sha-1.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
+ * based on: http://csrc.nist.gov/fips/fip180-1.txt
+ * implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
+ */
+
+#include "core/private.h"
+
+#ifdef LWS_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+struct sha1_ctxt {
+ union {
+ unsigned char b8[20];
+ unsigned int b32[5];
+ } h;
+ union {
+ unsigned char b8[8];
+ uint64_t b64[1];
+ } c;
+ union {
+ unsigned char b8[64];
+ unsigned int b32[16];
+ } m;
+ unsigned char count;
+};
+
+/* sanity check */
+#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
+# define unsupported 1
+#elif BYTE_ORDER != BIG_ENDIAN
+# if BYTE_ORDER != LITTLE_ENDIAN
+# define unsupported 1
+# endif
+#endif
+
+#ifndef unsupported
+
+/* constant table */
+static const unsigned int _K[] =
+ { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
+#define K(t) _K[(t) / 20]
+
+#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
+#define F1(b, c, d) (((b) ^ (c)) ^ (d))
+#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
+#define F3(b, c, d) (((b) ^ (c)) ^ (d))
+
+#define S(n, x) (((x) << (n)) | ((x) >> (32 - n)))
+
+#define H(n) (ctxt->h.b32[(n)])
+#define COUNT (ctxt->count)
+#define BCOUNT (ctxt->c.b64[0] / 8)
+#define W(n) (ctxt->m.b32[(n)])
+
+#define PUTBYTE(x) { \
+ ctxt->m.b8[(COUNT % 64)] = (x); \
+ COUNT++; \
+ COUNT %= 64; \
+ ctxt->c.b64[0] += 8; \
+ if (COUNT % 64 == 0) \
+ sha1_step(ctxt); \
+ }
+
+#define PUTPAD(x) { \
+ ctxt->m.b8[(COUNT % 64)] = (x); \
+ COUNT++; \
+ COUNT %= 64; \
+ if (COUNT % 64 == 0) \
+ sha1_step(ctxt); \
+ }
+
+
+static void
+sha1_step(struct sha1_ctxt *ctxt)
+{
+ unsigned int a, b, c, d, e, tmp;
+ size_t t, s;
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ struct sha1_ctxt tctxt;
+
+ memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64);
+ ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
+ ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
+ ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
+ ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
+ ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
+ ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
+ ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
+ ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
+ ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
+ ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
+ ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
+ ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
+ ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
+ ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
+ ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
+ ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
+ ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
+ ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
+ ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
+ ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
+ ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
+ ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
+ ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
+ ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
+ ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
+ ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
+ ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
+ ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
+ ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
+ ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
+ ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
+ ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
+#endif
+
+ a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
+
+ for (t = 0; t < 20; t++) {
+ s = t & 0x0f;
+ if (t >= 16)
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+ W((s+2) & 0x0f) ^ W(s));
+
+ tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+ for (t = 20; t < 40; t++) {
+ s = t & 0x0f;
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+ W((s+2) & 0x0f) ^ W(s));
+ tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+ for (t = 40; t < 60; t++) {
+ s = t & 0x0f;
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+ W((s+2) & 0x0f) ^ W(s));
+ tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+ for (t = 60; t < 80; t++) {
+ s = t & 0x0f;
+ W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
+ W((s+2) & 0x0f) ^ W(s));
+ tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
+ e = d; d = c; c = S(30, b); b = a; a = tmp;
+ }
+
+ H(0) = H(0) + a;
+ H(1) = H(1) + b;
+ H(2) = H(2) + c;
+ H(3) = H(3) + d;
+ H(4) = H(4) + e;
+
+ bzero(&ctxt->m.b8[0], 64);
+}
+
+/*------------------------------------------------------------*/
+
+static void
+_sha1_init(struct sha1_ctxt *ctxt)
+{
+ bzero(ctxt, sizeof(struct sha1_ctxt));
+ H(0) = 0x67452301;
+ H(1) = 0xefcdab89;
+ H(2) = 0x98badcfe;
+ H(3) = 0x10325476;
+ H(4) = 0xc3d2e1f0;
+}
+
+void
+sha1_pad(struct sha1_ctxt *ctxt)
+{
+ size_t padlen; /*pad length in bytes*/
+ size_t padstart;
+
+ PUTPAD(0x80);
+
+ padstart = COUNT % 64;
+ padlen = 64 - padstart;
+ if (padlen < 8) {
+ bzero(&ctxt->m.b8[padstart], padlen);
+ COUNT += (unsigned char)padlen;
+ COUNT %= 64;
+ sha1_step(ctxt);
+ padstart = COUNT % 64; /* should be 0 */
+ padlen = 64 - padstart; /* should be 64 */
+ }
+ bzero(&ctxt->m.b8[padstart], padlen - 8);
+ COUNT += ((unsigned char)padlen - 8);
+ COUNT %= 64;
+#if BYTE_ORDER == BIG_ENDIAN
+ PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
+ PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
+ PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
+ PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
+#else
+ PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
+ PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
+ PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
+ PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
+#endif
+}
+
+void
+sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)
+{
+ size_t gaplen;
+ size_t gapstart;
+ size_t off;
+ size_t copysiz;
+
+ off = 0;
+
+ while (off < len) {
+ gapstart = COUNT % 64;
+ gaplen = 64 - gapstart;
+
+ copysiz = (gaplen < len - off) ? gaplen : len - off;
+ memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz);
+ COUNT += (unsigned char)copysiz;
+ COUNT %= 64;
+ ctxt->c.b64[0] += copysiz * 8;
+ if (COUNT % 64 == 0)
+ sha1_step(ctxt);
+ off += copysiz;
+ }
+}
+
+void
+sha1_result(struct sha1_ctxt *ctxt, void *digest0)
+{
+ unsigned char *digest;
+
+ digest = (unsigned char *)digest0;
+ sha1_pad(ctxt);
+#if BYTE_ORDER == BIG_ENDIAN
+ memcpy(digest, &ctxt->h.b8[0], 20);
+#else
+ digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
+ digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
+ digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
+ digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
+ digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
+ digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
+ digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
+ digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
+ digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
+ digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
+#endif
+}
+
+/*
+ * This should look and work like the libcrypto implementation
+ */
+
+LWS_VISIBLE unsigned char *
+lws_SHA1(const unsigned char *d, size_t n, unsigned char *md)
+{
+ struct sha1_ctxt ctx;
+
+ _sha1_init(&ctx);
+ sha1_loop(&ctx, d, n);
+ sha1_result(&ctx, (void *)md);
+
+ return md;
+}
+
+#endif /*unsupported*/