From d60c99b01c3e0d3446f65ca97a9634b152fd713c Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov <rojer@cesanta.com> Date: Sat, 31 Oct 2015 16:26:19 +0000 Subject: [PATCH] Make MG debug go to stderr PUBLISHED_FROM=11618b6b2a50c62dd612d241c6b13a9aab357909 --- mongoose.c | 2739 ++++++++++++++++++++++++++-------------------------- mongoose.h | 32 +- 2 files changed, 1398 insertions(+), 1373 deletions(-) diff --git a/mongoose.c b/mongoose.c index c71ea92d0..5f7d442ad 100644 --- a/mongoose.c +++ b/mongoose.c @@ -111,7 +111,7 @@ extern void *(*test_calloc)(size_t, size_t); #endif /* MG_INTERNAL_HEADER_INCLUDED */ #ifdef NS_MODULE_LINES -#line 1 "src/../../common/mbuf.c" +#line 1 "src/../../common/base64.c" /**/ #endif /* @@ -121,1629 +121,1644 @@ extern void *(*test_calloc)(size_t, size_t); #ifndef EXCLUDE_COMMON -#include <assert.h> +/* Amalgamated: #include "base64.h" */ #include <string.h> -/* Amalgamated: #include "mbuf.h" */ -#ifndef MBUF_REALLOC -#define MBUF_REALLOC realloc -#endif +/* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */ -#ifndef MBUF_FREE -#define MBUF_FREE free -#endif +#define NUM_UPPERCASES ('Z' - 'A' + 1) +#define NUM_LETTERS (NUM_UPPERCASES * 2) +#define NUM_DIGITS ('9' - '0' + 1) -void mbuf_init(struct mbuf *mbuf, size_t initial_size) { - mbuf->len = mbuf->size = 0; - mbuf->buf = NULL; - mbuf_resize(mbuf, initial_size); +/* + * Emit a base64 code char. + * + * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps + */ +static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) { + if (v < NUM_UPPERCASES) { + ctx->b64_putc(v + 'A', ctx->user_data); + } else if (v < (NUM_LETTERS)) { + ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data); + } else if (v < (NUM_LETTERS + NUM_DIGITS)) { + ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data); + } else { + ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/', + ctx->user_data); + } } -void mbuf_free(struct mbuf *mbuf) { - if (mbuf->buf != NULL) { - MBUF_FREE(mbuf->buf); - mbuf_init(mbuf, 0); +static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) { + int a, b, c; + + a = ctx->chunk[0]; + b = ctx->chunk[1]; + c = ctx->chunk[2]; + + cs_base64_emit_code(ctx, a >> 2); + cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4)); + if (ctx->chunk_size > 1) { + cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6)); + } + if (ctx->chunk_size > 2) { + cs_base64_emit_code(ctx, c & 63); } } -void mbuf_resize(struct mbuf *a, size_t new_size) { - if (new_size > a->size || (new_size < a->size && new_size >= a->len)) { - char *buf = (char *) MBUF_REALLOC(a->buf, new_size); - /* - * In case realloc fails, there's not much we can do, except keep things as - * they are. Note that NULL is a valid return value from realloc when - * size == 0, but that is covered too. - */ - if (buf == NULL && new_size != 0) return; - a->buf = buf; - a->size = new_size; +void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc, + void *user_data) { + ctx->chunk_size = 0; + ctx->b64_putc = b64_putc; + ctx->user_data = user_data; +} + +void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) { + const unsigned char *src = (const unsigned char *) str; + size_t i; + for (i = 0; i < len; i++) { + ctx->chunk[ctx->chunk_size++] = src[i]; + if (ctx->chunk_size == 3) { + cs_base64_emit_chunk(ctx); + ctx->chunk_size = 0; + } } } -void mbuf_trim(struct mbuf *mbuf) { - mbuf_resize(mbuf, mbuf->len); +void cs_base64_finish(struct cs_base64_ctx *ctx) { + if (ctx->chunk_size > 0) { + int i; + memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size); + cs_base64_emit_chunk(ctx); + for (i = 0; i < (3 - ctx->chunk_size); i++) { + ctx->b64_putc('=', ctx->user_data); + } + } } -size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) { - char *p = NULL; +#define BASE64_ENCODE_BODY \ + static const char *b64 = \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \ + int i, j, a, b, c; \ + \ + for (i = j = 0; i < src_len; i += 3) { \ + a = src[i]; \ + b = i + 1 >= src_len ? 0 : src[i + 1]; \ + c = i + 2 >= src_len ? 0 : src[i + 2]; \ + \ + BASE64_OUT(b64[a >> 2]); \ + BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \ + if (i + 1 < src_len) { \ + BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \ + } \ + if (i + 2 < src_len) { \ + BASE64_OUT(b64[c & 63]); \ + } \ + } \ + \ + while (j % 4 != 0) { \ + BASE64_OUT('='); \ + } \ + BASE64_FLUSH() - assert(a != NULL); - assert(a->len <= a->size); - assert(off <= a->len); +#define BASE64_OUT(ch) \ + do { \ + dst[j++] = (ch); \ + } while (0) - /* check overflow */ - if (~(size_t) 0 - (size_t) a->buf < len) return 0; +#define BASE64_FLUSH() \ + do { \ + dst[j++] = '\0'; \ + } while (0) - if (a->len + len <= a->size) { - memmove(a->buf + off + len, a->buf + off, a->len - off); - if (buf != NULL) { - memcpy(a->buf + off, buf, len); - } - a->len += len; - } else if ((p = (char *) MBUF_REALLOC( - a->buf, (a->len + len) * MBUF_SIZE_MULTIPLIER)) != NULL) { - a->buf = p; - memmove(a->buf + off + len, a->buf + off, a->len - off); - if (buf != NULL) { - memcpy(a->buf + off, buf, len); - } - a->len += len; - a->size = a->len * MBUF_SIZE_MULTIPLIER; - } else { - len = 0; - } +void cs_base64_encode(const unsigned char *src, int src_len, char *dst) { + BASE64_ENCODE_BODY; +} - return len; +#undef BASE64_OUT +#undef BASE64_FLUSH + +#define BASE64_OUT(ch) \ + do { \ + fprintf(f, "%c", (ch)); \ + j++; \ + } while (0) + +#define BASE64_FLUSH() + +void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) { + BASE64_ENCODE_BODY; } -size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) { - return mbuf_insert(a, a->len, buf, len); +#undef BASE64_OUT +#undef BASE64_FLUSH + +/* Convert one byte of encoded base64 input stream to 6-bit chunk */ +static unsigned char from_b64(unsigned char ch) { + /* Inverse lookup map */ + static const unsigned char tab[128] = { + 255, 255, 255, 255, + 255, 255, 255, 255, /* 0 */ + 255, 255, 255, 255, + 255, 255, 255, 255, /* 8 */ + 255, 255, 255, 255, + 255, 255, 255, 255, /* 16 */ + 255, 255, 255, 255, + 255, 255, 255, 255, /* 24 */ + 255, 255, 255, 255, + 255, 255, 255, 255, /* 32 */ + 255, 255, 255, 62, + 255, 255, 255, 63, /* 40 */ + 52, 53, 54, 55, + 56, 57, 58, 59, /* 48 */ + 60, 61, 255, 255, + 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */ + 255, 0, 1, 2, + 3, 4, 5, 6, /* 64 */ + 7, 8, 9, 10, + 11, 12, 13, 14, /* 72 */ + 15, 16, 17, 18, + 19, 20, 21, 22, /* 80 */ + 23, 24, 25, 255, + 255, 255, 255, 255, /* 88 */ + 255, 26, 27, 28, + 29, 30, 31, 32, /* 96 */ + 33, 34, 35, 36, + 37, 38, 39, 40, /* 104 */ + 41, 42, 43, 44, + 45, 46, 47, 48, /* 112 */ + 49, 50, 51, 255, + 255, 255, 255, 255, /* 120 */ + }; + return tab[ch & 127]; } -void mbuf_remove(struct mbuf *mb, size_t n) { - if (n > 0 && n <= mb->len) { - memmove(mb->buf, mb->buf + n, mb->len - n); - mb->len -= n; +int cs_base64_decode(const unsigned char *s, int len, char *dst) { + unsigned char a, b, c, d; + int orig_len = len; + while (len >= 4 && (a = from_b64(s[0])) != 255 && + (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 && + (d = from_b64(s[3])) != 255) { + s += 4; + len -= 4; + if (a == 200 || b == 200) break; /* '=' can't be there */ + *dst++ = a << 2 | b >> 4; + if (c == 200) break; + *dst++ = b << 4 | c >> 2; + if (d == 200) break; + *dst++ = c << 6 | d; } + *dst = 0; + return orig_len - len; } #endif /* EXCLUDE_COMMON */ #ifdef NS_MODULE_LINES -#line 1 "src/../../common/sha1.c" +#line 1 "src/../../common/cs_dbg.c" /**/ #endif -/* Copyright(c) By Steve Reid <steve@edmweb.com> */ -/* 100% Public Domain */ - -#if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON) - -/* Amalgamated: #include "sha1.h" */ +#include <stdarg.h> +#include <stdio.h> -#define SHA1HANDSOFF -#if defined(__sun) -/* Amalgamated: #include "solarisfixes.h" */ +void cs_dbg_printf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + fflush(stderr); +} +#ifdef NS_MODULE_LINES +#line 1 "src/../../common/dirent.c" +/**/ #endif +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ -union char64long16 { - unsigned char c[64]; - uint32_t l[16]; -}; +#ifndef EXCLUDE_COMMON -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) +/* Amalgamated: #include "osdep.h" */ -static uint32_t blk0(union char64long16 *block, int i) { -/* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */ -#if BYTE_ORDER == LITTLE_ENDIAN - block->l[i] = - (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF); +/* + * This file contains POSIX opendir/closedir/readdir API implementation + * for systems which do not natively support it (e.g. Windows). + */ + +#ifndef MG_FREE +#define MG_FREE free #endif - return block->l[i]; -} -/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ -#undef blk -#undef R0 -#undef R1 -#undef R2 -#undef R3 -#undef R4 +#ifndef MG_MALLOC +#define MG_MALLOC malloc +#endif -#define blk(i) \ - (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ - block->l[(i + 2) & 15] ^ block->l[i & 15], \ - 1)) -#define R0(v, w, x, y, z, i) \ - z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ - w = rol(w, 30); -#define R1(v, w, x, y, z, i) \ - z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ - w = rol(w, 30); -#define R2(v, w, x, y, z, i) \ - z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ - w = rol(w, 30); -#define R3(v, w, x, y, z, i) \ - z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ - w = rol(w, 30); -#define R4(v, w, x, y, z, i) \ - z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ - w = rol(w, 30); +#ifdef _WIN32 +DIR *opendir(const char *name) { + DIR *dir = NULL; + wchar_t wpath[MAX_PATH]; + DWORD attrs; -void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) { - uint32_t a, b, c, d, e; - union char64long16 block[1]; + if (name == NULL) { + SetLastError(ERROR_BAD_ARGUMENTS); + } else if ((dir = (DIR *) MG_MALLOC(sizeof(*dir))) == NULL) { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + } else { + to_wchar(name, wpath, ARRAY_SIZE(wpath)); + attrs = GetFileAttributesW(wpath); + if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + (void) wcscat(wpath, L"\\*"); + dir->handle = FindFirstFileW(wpath, &dir->info); + dir->result.d_name[0] = '\0'; + } else { + MG_FREE(dir); + dir = NULL; + } + } - memcpy(block, buffer, 64); - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - R0(a, b, c, d, e, 0); - R0(e, a, b, c, d, 1); - R0(d, e, a, b, c, 2); - R0(c, d, e, a, b, 3); - R0(b, c, d, e, a, 4); - R0(a, b, c, d, e, 5); - R0(e, a, b, c, d, 6); - R0(d, e, a, b, c, 7); - R0(c, d, e, a, b, 8); - R0(b, c, d, e, a, 9); - R0(a, b, c, d, e, 10); - R0(e, a, b, c, d, 11); - R0(d, e, a, b, c, 12); - R0(c, d, e, a, b, 13); - R0(b, c, d, e, a, 14); - R0(a, b, c, d, e, 15); - R1(e, a, b, c, d, 16); - R1(d, e, a, b, c, 17); - R1(c, d, e, a, b, 18); - R1(b, c, d, e, a, 19); - R2(a, b, c, d, e, 20); - R2(e, a, b, c, d, 21); - R2(d, e, a, b, c, 22); - R2(c, d, e, a, b, 23); - R2(b, c, d, e, a, 24); - R2(a, b, c, d, e, 25); - R2(e, a, b, c, d, 26); - R2(d, e, a, b, c, 27); - R2(c, d, e, a, b, 28); - R2(b, c, d, e, a, 29); - R2(a, b, c, d, e, 30); - R2(e, a, b, c, d, 31); - R2(d, e, a, b, c, 32); - R2(c, d, e, a, b, 33); - R2(b, c, d, e, a, 34); - R2(a, b, c, d, e, 35); - R2(e, a, b, c, d, 36); - R2(d, e, a, b, c, 37); - R2(c, d, e, a, b, 38); - R2(b, c, d, e, a, 39); - R3(a, b, c, d, e, 40); - R3(e, a, b, c, d, 41); - R3(d, e, a, b, c, 42); - R3(c, d, e, a, b, 43); - R3(b, c, d, e, a, 44); - R3(a, b, c, d, e, 45); - R3(e, a, b, c, d, 46); - R3(d, e, a, b, c, 47); - R3(c, d, e, a, b, 48); - R3(b, c, d, e, a, 49); - R3(a, b, c, d, e, 50); - R3(e, a, b, c, d, 51); - R3(d, e, a, b, c, 52); - R3(c, d, e, a, b, 53); - R3(b, c, d, e, a, 54); - R3(a, b, c, d, e, 55); - R3(e, a, b, c, d, 56); - R3(d, e, a, b, c, 57); - R3(c, d, e, a, b, 58); - R3(b, c, d, e, a, 59); - R4(a, b, c, d, e, 60); - R4(e, a, b, c, d, 61); - R4(d, e, a, b, c, 62); - R4(c, d, e, a, b, 63); - R4(b, c, d, e, a, 64); - R4(a, b, c, d, e, 65); - R4(e, a, b, c, d, 66); - R4(d, e, a, b, c, 67); - R4(c, d, e, a, b, 68); - R4(b, c, d, e, a, 69); - R4(a, b, c, d, e, 70); - R4(e, a, b, c, d, 71); - R4(d, e, a, b, c, 72); - R4(c, d, e, a, b, 73); - R4(b, c, d, e, a, 74); - R4(a, b, c, d, e, 75); - R4(e, a, b, c, d, 76); - R4(d, e, a, b, c, 77); - R4(c, d, e, a, b, 78); - R4(b, c, d, e, a, 79); - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - /* Erase working structures. The order of operations is important, - * used to ensure that compiler doesn't optimize those out. */ - memset(block, 0, sizeof(block)); - a = b = c = d = e = 0; - (void) a; - (void) b; - (void) c; - (void) d; - (void) e; + return dir; } -void cs_sha1_init(cs_sha1_ctx *context) { - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} +int closedir(DIR *dir) { + int result = 0; -void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len) { - uint32_t i, j; + if (dir != NULL) { + if (dir->handle != INVALID_HANDLE_VALUE) + result = FindClose(dir->handle) ? 0 : -1; + MG_FREE(dir); + } else { + result = -1; + SetLastError(ERROR_BAD_ARGUMENTS); + } - j = context->count[0]; - if ((context->count[0] += len << 3) < j) context->count[1]++; - context->count[1] += (len >> 29); - j = (j >> 3) & 63; - if ((j + len) > 63) { - memcpy(&context->buffer[j], data, (i = 64 - j)); - cs_sha1_transform(context->state, context->buffer); - for (; i + 63 < len; i += 64) { - cs_sha1_transform(context->state, &data[i]); - } - j = 0; - } else - i = 0; - memcpy(&context->buffer[j], &data[i], len - i); + return result; } -void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) { - unsigned i; - unsigned char finalcount[8], c; +struct dirent *readdir(DIR *dir) { + struct dirent *result = 0; - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> - ((3 - (i & 3)) * 8)) & - 255); - } - c = 0200; - cs_sha1_update(context, &c, 1); - while ((context->count[0] & 504) != 448) { - c = 0000; - cs_sha1_update(context, &c, 1); - } - cs_sha1_update(context, finalcount, 8); - for (i = 0; i < 20; i++) { - digest[i] = - (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); - } - memset(context, '\0', sizeof(*context)); - memset(&finalcount, '\0', sizeof(finalcount)); -} + if (dir) { + if (dir->handle != INVALID_HANDLE_VALUE) { + result = &dir->result; + (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1, + result->d_name, sizeof(result->d_name), NULL, + NULL); -void cs_hmac_sha1(const unsigned char *key, size_t keylen, - const unsigned char *data, size_t datalen, - unsigned char out[20]) { - cs_sha1_ctx ctx; - unsigned char buf1[64], buf2[64], tmp_key[20], i; + if (!FindNextFileW(dir->handle, &dir->info)) { + (void) FindClose(dir->handle); + dir->handle = INVALID_HANDLE_VALUE; + } - if (keylen > sizeof(buf1)) { - cs_sha1_init(&ctx); - cs_sha1_update(&ctx, key, keylen); - cs_sha1_final(tmp_key, &ctx); - key = tmp_key; - keylen = sizeof(tmp_key); + } else { + SetLastError(ERROR_FILE_NOT_FOUND); + } + } else { + SetLastError(ERROR_BAD_ARGUMENTS); } - memset(buf1, 0, sizeof(buf1)); - memset(buf2, 0, sizeof(buf2)); - memcpy(buf1, key, keylen); - memcpy(buf2, key, keylen); - - for (i = 0; i < sizeof(buf1); i++) { - buf1[i] ^= 0x36; - buf2[i] ^= 0x5c; - } - - cs_sha1_init(&ctx); - cs_sha1_update(&ctx, buf1, sizeof(buf1)); - cs_sha1_update(&ctx, data, datalen); - cs_sha1_final(out, &ctx); - - cs_sha1_init(&ctx); - cs_sha1_update(&ctx, buf2, sizeof(buf2)); - cs_sha1_update(&ctx, out, 20); - cs_sha1_final(out, &ctx); + return result; } +#endif #endif /* EXCLUDE_COMMON */ #ifdef NS_MODULE_LINES -#line 1 "src/../../common/md5.c" +#line 1 "src/../deps/frozen/frozen.c" /**/ #endif /* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. + * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com> + * Copyright (c) 2013 Cesanta Software Limited + * All rights reserved * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. + * This library is dual-licensed: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. For the terms of this + * license, see <http: *www.gnu.org/licenses/>. * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. + * You are free to use this library under the terms of the GNU General + * Public License, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * Alternatively, you can license this library under a commercial + * license, as set out in <https://www.cesanta.com/license>. */ -#if !defined(DISABLE_MD5) && !defined(EXCLUDE_COMMON) +#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */ -/* Amalgamated: #include "md5.h" */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +/* Amalgamated: #include "frozen.h" */ -#ifndef CS_ENABLE_NATIVE_MD5 -static void byteReverse(unsigned char *buf, unsigned longs) { -/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */ -#if BYTE_ORDER == BIG_ENDIAN - do { - uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32_t *) buf = t; - buf += 4; - } while (--longs); -#else - (void) buf; - (void) longs; +#ifdef _WIN32 +#define snprintf _snprintf #endif -} - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -#define MD5STEP(f, w, x, y, z, data, s) \ - (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5_Init(MD5_CTX *ctx) { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} +#ifndef FROZEN_REALLOC +#define FROZEN_REALLOC realloc +#endif -static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { - register uint32_t a, b, c, d; +#ifndef FROZEN_FREE +#define FROZEN_FREE free +#endif - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; +struct frozen { + const char *end; + const char *cur; + struct json_token *tokens; + int max_tokens; + int num_tokens; + int do_realloc; +}; - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); +static int parse_object(struct frozen *f); +static int parse_value(struct frozen *f); - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); +#define EXPECT(cond, err_code) do { if (!(cond)) return (err_code); } while (0) +#define TRY(expr) do { int _n = expr; if (_n < 0) return _n; } while (0) +#define END_OF_STRING (-1) - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); +static int left(const struct frozen *f) { + return f->end - f->cur; +} - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); +static int is_space(int ch) { + return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; +} - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; +static void skip_whitespaces(struct frozen *f) { + while (f->cur < f->end && is_space(*f->cur)) f->cur++; } -void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { - uint32_t t; +static int cur(struct frozen *f) { + skip_whitespaces(f); + return f->cur >= f->end ? END_OF_STRING : * (unsigned char *) f->cur; +} - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; - ctx->bits[1] += (uint32_t) len >> 29; +static int test_and_skip(struct frozen *f, int expected) { + int ch = cur(f); + if (ch == expected) { f->cur++; return 0; } + return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; +} - t = (t >> 3) & 0x3f; +static int is_alpha(int ch) { + return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); +} - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; +static int is_digit(int ch) { + return ch >= '0' && ch <= '9'; +} - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += t; - len -= t; - } +static int is_hex_digit(int ch) { + return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +} - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += 64; - len -= 64; +static int get_escape_len(const char *s, int len) { + switch (*s) { + case 'u': + return len < 6 ? JSON_STRING_INCOMPLETE : + is_hex_digit(s[1]) && is_hex_digit(s[2]) && + is_hex_digit(s[3]) && is_hex_digit(s[4]) ? 5 : JSON_STRING_INVALID; + case '"': case '\\': case '/': case 'b': + case 'f': case 'n': case 'r': case 't': + return len < 2 ? JSON_STRING_INCOMPLETE : 1; + default: + return JSON_STRING_INVALID; } - - memcpy(ctx->in, buf, len); } -void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { - unsigned count; - unsigned char *p; - uint32_t *a; - - count = (ctx->bits[0] >> 3) & 0x3F; - - p = ctx->in + count; - *p++ = 0x80; - count = 64 - 1 - count; - if (count < 8) { - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - memset(ctx->in, 0, 56); - } else { - memset(p, 0, count - 8); +static int capture_ptr(struct frozen *f, const char *ptr, enum json_type type) { + if (f->do_realloc && f->num_tokens >= f->max_tokens) { + int new_size = f->max_tokens == 0 ? 100 : f->max_tokens * 2; + void *p = FROZEN_REALLOC(f->tokens, new_size * sizeof(f->tokens[0])); + if (p == NULL) return JSON_TOKEN_ARRAY_TOO_SMALL; + f->max_tokens = new_size; + f->tokens = (struct json_token *) p; } - byteReverse(ctx->in, 14); - - a = (uint32_t *) ctx->in; - a[14] = ctx->bits[0]; - a[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset((char *) ctx, 0, sizeof(*ctx)); + if (f->tokens == NULL || f->max_tokens == 0) return 0; + if (f->num_tokens >= f->max_tokens) return JSON_TOKEN_ARRAY_TOO_SMALL; + f->tokens[f->num_tokens].ptr = ptr; + f->tokens[f->num_tokens].type = type; + f->num_tokens++; + return 0; } -#endif /* CS_ENABLE_NATIVE_MD5 */ -/* - * Stringify binary data. Output buffer size must be 2 * size_of_input + 1 - * because each byte of input takes 2 bytes in string representation - * plus 1 byte for the terminating \0 character. - */ -void cs_to_hex(char *to, const unsigned char *p, size_t len) { - static const char *hex = "0123456789abcdef"; +static int capture_len(struct frozen *f, int token_index, const char *ptr) { + if (f->tokens == 0 || f->max_tokens == 0) return 0; + EXPECT(token_index >= 0 && token_index < f->max_tokens, JSON_STRING_INVALID); + f->tokens[token_index].len = ptr - f->tokens[token_index].ptr; + f->tokens[token_index].num_desc = (f->num_tokens - 1) - token_index; + return 0; +} - for (; len--; p++) { - *to++ = hex[p[0] >> 4]; - *to++ = hex[p[0] & 0x0f]; +/* identifier = letter { letter | digit | '_' } */ +static int parse_identifier(struct frozen *f) { + EXPECT(is_alpha(cur(f)), JSON_STRING_INVALID); + TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING)); + while (f->cur < f->end && + (*f->cur == '_' || is_alpha(*f->cur) || is_digit(*f->cur))) { + f->cur++; } - *to = '\0'; + capture_len(f, f->num_tokens - 1, f->cur); + return 0; } -char *cs_md5(char buf[33], ...) { - unsigned char hash[16]; - const unsigned char *p; - va_list ap; - MD5_CTX ctx; +static int get_utf8_char_len(unsigned char ch) { + if ((ch & 0x80) == 0) return 1; + switch (ch & 0xf0) { + case 0xf0: return 4; + case 0xe0: return 3; + default: return 2; + } +} - MD5_Init(&ctx); +/* string = '"' { quoted_printable_chars } '"' */ +static int parse_string(struct frozen *f) { + int n, ch = 0, len = 0; + TRY(test_and_skip(f, '"')); + TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING)); + for (; f->cur < f->end; f->cur += len) { + ch = * (unsigned char *) f->cur; + len = get_utf8_char_len((unsigned char) ch); + EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */ + EXPECT(len < left(f), JSON_STRING_INCOMPLETE); + if (ch == '\\') { + EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n); + len += n; + } else if (ch == '"') { + capture_len(f, f->num_tokens - 1, f->cur); + f->cur++; + break; + }; + } + return ch == '"' ? 0 : JSON_STRING_INCOMPLETE; +} - va_start(ap, buf); - while ((p = va_arg(ap, const unsigned char *) ) != NULL) { - size_t len = va_arg(ap, size_t); - MD5_Update(&ctx, p, len); +/* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */ +static int parse_number(struct frozen *f) { + int ch = cur(f); + TRY(capture_ptr(f, f->cur, JSON_TYPE_NUMBER)); + if (ch == '-') f->cur++; + EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); + EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); + while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; + if (f->cur < f->end && f->cur[0] == '.') { + f->cur++; + EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); + EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); + while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; } - va_end(ap); + if (f->cur < f->end && (f->cur[0] == 'e' || f->cur[0] == 'E')) { + f->cur++; + EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); + if ((f->cur[0] == '+' || f->cur[0] == '-')) f->cur++; + EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); + EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); + while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; + } + capture_len(f, f->num_tokens - 1, f->cur); + return 0; +} - MD5_Final(hash, &ctx); - cs_to_hex(buf, hash, sizeof(hash)); +/* array = '[' [ value { ',' value } ] ']' */ +static int parse_array(struct frozen *f) { + int ind; + TRY(test_and_skip(f, '[')); + TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_ARRAY)); + ind = f->num_tokens - 1; + while (cur(f) != ']') { + TRY(parse_value(f)); + if (cur(f) == ',') f->cur++; + } + TRY(test_and_skip(f, ']')); + capture_len(f, ind, f->cur); + return 0; +} - return buf; +static int compare(const char *s, const char *str, int len) { + int i = 0; + while (i < len && s[i] == str[i]) i++; + return i == len ? 1 : 0; } -#endif /* EXCLUDE_COMMON */ -#ifdef NS_MODULE_LINES -#line 1 "src/../../common/base64.c" -/**/ -#endif -/* - * Copyright (c) 2014 Cesanta Software Limited - * All rights reserved - */ +static int expect(struct frozen *f, const char *s, int len, enum json_type t) { + int i, n = left(f); -#ifndef EXCLUDE_COMMON + TRY(capture_ptr(f, f->cur, t)); + for (i = 0; i < len; i++) { + if (i >= n) return JSON_STRING_INCOMPLETE; + if (f->cur[i] != s[i]) return JSON_STRING_INVALID; + } + f->cur += len; + TRY(capture_len(f, f->num_tokens - 1, f->cur)); -/* Amalgamated: #include "base64.h" */ -#include <string.h> + return 0; +} -/* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */ +/* value = 'null' | 'true' | 'false' | number | string | array | object */ +static int parse_value(struct frozen *f) { + int ch = cur(f); -#define NUM_UPPERCASES ('Z' - 'A' + 1) -#define NUM_LETTERS (NUM_UPPERCASES * 2) -#define NUM_DIGITS ('9' - '0' + 1) + switch (ch) { + case '"': TRY(parse_string(f)); break; + case '{': TRY(parse_object(f)); break; + case '[': TRY(parse_array(f)); break; + case 'n': TRY(expect(f, "null", 4, JSON_TYPE_NULL)); break; + case 't': TRY(expect(f, "true", 4, JSON_TYPE_TRUE)); break; + case 'f': TRY(expect(f, "false", 5, JSON_TYPE_FALSE)); break; + case '-': case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + TRY(parse_number(f)); + break; + default: + return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; + } -/* - * Emit a base64 code char. - * - * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps - */ -static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) { - if (v < NUM_UPPERCASES) { - ctx->b64_putc(v + 'A', ctx->user_data); - } else if (v < (NUM_LETTERS)) { - ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data); - } else if (v < (NUM_LETTERS + NUM_DIGITS)) { - ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data); + return 0; +} + +/* key = identifier | string */ +static int parse_key(struct frozen *f) { + int ch = cur(f); +#if 0 + printf("%s 1 [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur); +#endif + if (is_alpha(ch)) { + TRY(parse_identifier(f)); + } else if (ch == '"') { + TRY(parse_string(f)); } else { - ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/', - ctx->user_data); + return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; } + return 0; } -static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) { - int a, b, c; - - a = ctx->chunk[0]; - b = ctx->chunk[1]; - c = ctx->chunk[2]; +/* pair = key ':' value */ +static int parse_pair(struct frozen *f) { + TRY(parse_key(f)); + TRY(test_and_skip(f, ':')); + TRY(parse_value(f)); + return 0; +} - cs_base64_emit_code(ctx, a >> 2); - cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4)); - if (ctx->chunk_size > 1) { - cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6)); - } - if (ctx->chunk_size > 2) { - cs_base64_emit_code(ctx, c & 63); +/* object = '{' pair { ',' pair } '}' */ +static int parse_object(struct frozen *f) { + int ind; + TRY(test_and_skip(f, '{')); + TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_OBJECT)); + ind = f->num_tokens - 1; + while (cur(f) != '}') { + TRY(parse_pair(f)); + if (cur(f) == ',') f->cur++; } + TRY(test_and_skip(f, '}')); + capture_len(f, ind, f->cur); + return 0; } -void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc, - void *user_data) { - ctx->chunk_size = 0; - ctx->b64_putc = b64_putc; - ctx->user_data = user_data; -} - -void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) { - const unsigned char *src = (const unsigned char *) str; - size_t i; - for (i = 0; i < len; i++) { - ctx->chunk[ctx->chunk_size++] = src[i]; - if (ctx->chunk_size == 3) { - cs_base64_emit_chunk(ctx); - ctx->chunk_size = 0; - } - } -} - -void cs_base64_finish(struct cs_base64_ctx *ctx) { - if (ctx->chunk_size > 0) { - int i; - memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size); - cs_base64_emit_chunk(ctx); - for (i = 0; i < (3 - ctx->chunk_size); i++) { - ctx->b64_putc('=', ctx->user_data); - } - } +static int doit(struct frozen *f) { + if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID; + if (f->end == f->cur) return JSON_STRING_INCOMPLETE; + TRY(parse_object(f)); + TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF)); + capture_len(f, f->num_tokens, f->cur); + return 0; } -#define BASE64_ENCODE_BODY \ - static const char *b64 = \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \ - int i, j, a, b, c; \ - \ - for (i = j = 0; i < src_len; i += 3) { \ - a = src[i]; \ - b = i + 1 >= src_len ? 0 : src[i + 1]; \ - c = i + 2 >= src_len ? 0 : src[i + 2]; \ - \ - BASE64_OUT(b64[a >> 2]); \ - BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \ - if (i + 1 < src_len) { \ - BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \ - } \ - if (i + 2 < src_len) { \ - BASE64_OUT(b64[c & 63]); \ - } \ - } \ - \ - while (j % 4 != 0) { \ - BASE64_OUT('='); \ - } \ - BASE64_FLUSH() +/* json = object */ +int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) { + struct frozen frozen; -#define BASE64_OUT(ch) \ - do { \ - dst[j++] = (ch); \ - } while (0) + memset(&frozen, 0, sizeof(frozen)); + frozen.end = s + s_len; + frozen.cur = s; + frozen.tokens = arr; + frozen.max_tokens = arr_len; -#define BASE64_FLUSH() \ - do { \ - dst[j++] = '\0'; \ - } while (0) + TRY(doit(&frozen)); -void cs_base64_encode(const unsigned char *src, int src_len, char *dst) { - BASE64_ENCODE_BODY; + return frozen.cur - s; } -#undef BASE64_OUT -#undef BASE64_FLUSH +struct json_token *parse_json2(const char *s, int s_len) { + struct frozen frozen; -#define BASE64_OUT(ch) \ - do { \ - fprintf(f, "%c", (ch)); \ - j++; \ - } while (0) + memset(&frozen, 0, sizeof(frozen)); + frozen.end = s + s_len; + frozen.cur = s; + frozen.do_realloc = 1; -#define BASE64_FLUSH() + if (doit(&frozen) < 0) { + FROZEN_FREE((void *) frozen.tokens); + frozen.tokens = NULL; + } + return frozen.tokens; +} -void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) { - BASE64_ENCODE_BODY; +static int path_part_len(const char *p) { + int i = 0; + while (p[i] != '\0' && p[i] != '[' && p[i] != '.') i++; + return i; } -#undef BASE64_OUT -#undef BASE64_FLUSH +struct json_token *find_json_token(struct json_token *toks, const char *path) { + while (path != 0 && path[0] != '\0') { + int i, ind2 = 0, ind = -1, skip = 2, n = path_part_len(path); + if (path[0] == '[') { + if (toks->type != JSON_TYPE_ARRAY || !is_digit(path[1])) return 0; + for (ind = 0, n = 1; path[n] != ']' && path[n] != '\0'; n++) { + if (!is_digit(path[n])) return 0; + ind *= 10; + ind += path[n] - '0'; + } + if (path[n++] != ']') return 0; + skip = 1; /* In objects, we skip 2 elems while iterating, in arrays 1. */ + } else if (toks->type != JSON_TYPE_OBJECT) return 0; + toks++; + for (i = 0; i < toks[-1].num_desc; i += skip, ind2++) { + /* ind == -1 indicated that we're iterating an array, not object */ + if (ind == -1 && toks[i].type != JSON_TYPE_STRING) return 0; + if (ind2 == ind || + (ind == -1 && toks[i].len == n && compare(path, toks[i].ptr, n))) { + i += skip - 1; + break; + }; + if (toks[i - 1 + skip].type == JSON_TYPE_ARRAY || + toks[i - 1 + skip].type == JSON_TYPE_OBJECT) { + i += toks[i - 1 + skip].num_desc; + } + } + if (i == toks[-1].num_desc) return 0; + path += n; + if (path[0] == '.') path++; + if (path[0] == '\0') return &toks[i]; + toks += i; + } + return 0; +} -/* Convert one byte of encoded base64 input stream to 6-bit chunk */ -static unsigned char from_b64(unsigned char ch) { - /* Inverse lookup map */ - static const unsigned char tab[128] = { - 255, 255, 255, 255, - 255, 255, 255, 255, /* 0 */ - 255, 255, 255, 255, - 255, 255, 255, 255, /* 8 */ - 255, 255, 255, 255, - 255, 255, 255, 255, /* 16 */ - 255, 255, 255, 255, - 255, 255, 255, 255, /* 24 */ - 255, 255, 255, 255, - 255, 255, 255, 255, /* 32 */ - 255, 255, 255, 62, - 255, 255, 255, 63, /* 40 */ - 52, 53, 54, 55, - 56, 57, 58, 59, /* 48 */ - 60, 61, 255, 255, - 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */ - 255, 0, 1, 2, - 3, 4, 5, 6, /* 64 */ - 7, 8, 9, 10, - 11, 12, 13, 14, /* 72 */ - 15, 16, 17, 18, - 19, 20, 21, 22, /* 80 */ - 23, 24, 25, 255, - 255, 255, 255, 255, /* 88 */ - 255, 26, 27, 28, - 29, 30, 31, 32, /* 96 */ - 33, 34, 35, 36, - 37, 38, 39, 40, /* 104 */ - 41, 42, 43, 44, - 45, 46, 47, 48, /* 112 */ - 49, 50, 51, 255, - 255, 255, 255, 255, /* 120 */ - }; - return tab[ch & 127]; +int json_emit_long(char *buf, int buf_len, long int value) { + char tmp[20]; + int n = snprintf(tmp, sizeof(tmp), "%ld", value); + strncpy(buf, tmp, buf_len > 0 ? buf_len : 0); + return n; } -int cs_base64_decode(const unsigned char *s, int len, char *dst) { - unsigned char a, b, c, d; - int orig_len = len; - while (len >= 4 && (a = from_b64(s[0])) != 255 && - (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 && - (d = from_b64(s[3])) != 255) { - s += 4; - len -= 4; - if (a == 200 || b == 200) break; /* '=' can't be there */ - *dst++ = a << 2 | b >> 4; - if (c == 200) break; - *dst++ = b << 4 | c >> 2; - if (d == 200) break; - *dst++ = c << 6 | d; - } - *dst = 0; - return orig_len - len; +int json_emit_double(char *buf, int buf_len, double value) { + char tmp[20]; + int n = snprintf(tmp, sizeof(tmp), "%g", value); + strncpy(buf, tmp, buf_len > 0 ? buf_len : 0); + return n; } -#endif /* EXCLUDE_COMMON */ -#ifdef NS_MODULE_LINES -#line 1 "src/../../common/str_util.c" -/**/ -#endif -/* - * Copyright (c) 2015 Cesanta Software Limited - * All rights reserved - */ +int json_emit_quoted_str(char *s, int s_len, const char *str, int len) { + const char *begin = s, *end = s + s_len, *str_end = str + len; + char ch; -#ifndef EXCLUDE_COMMON +#define EMIT(x) do { if (s < end) *s = x; s++; } while (0) -/* Amalgamated: #include "osdep.h" */ -/* Amalgamated: #include "str_util.h" */ + EMIT('"'); + while (str < str_end) { + ch = *str++; + switch (ch) { + case '"': EMIT('\\'); EMIT('"'); break; + case '\\': EMIT('\\'); EMIT('\\'); break; + case '\b': EMIT('\\'); EMIT('b'); break; + case '\f': EMIT('\\'); EMIT('f'); break; + case '\n': EMIT('\\'); EMIT('n'); break; + case '\r': EMIT('\\'); EMIT('r'); break; + case '\t': EMIT('\\'); EMIT('t'); break; + default: EMIT(ch); + } + } + EMIT('"'); + if (s < end) { + *s = '\0'; + } -#if !(_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L) && \ - !(__DARWIN_C_LEVEL >= 200809L) && !defined(RTOS_SDK) || \ - defined(_WIN32) -size_t strnlen(const char *s, size_t maxlen) { - size_t l = 0; - for (; l < maxlen && s[l] != '\0'; l++) { + return s - begin; +} + +int json_emit_unquoted_str(char *buf, int buf_len, const char *str, int len) { + if (buf_len > 0 && len > 0) { + int n = len < buf_len ? len : buf_len; + memcpy(buf, str, n); + if (n < buf_len) { + buf[n] = '\0'; + } } - return l; + return len; } -#endif -#define C_SNPRINTF_APPEND_CHAR(ch) \ - do { \ - if (i < (int) buf_size) buf[i] = ch; \ - i++; \ - } while (0) - -#define C_SNPRINTF_FLAG_ZERO 1 - -#ifdef C_DISABLE_BUILTIN_SNPRINTF -int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) { - return vsnprintf(buf, buf_size, fmt, ap); -} -#else -static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags, - int field_width) { - char tmp[40]; - int i = 0, k = 0, neg = 0; - - if (num < 0) { - neg++; - num = -num; - } - - /* Print into temporary buffer - in reverse order */ - do { - int rem = num % base; - if (rem < 10) { - tmp[k++] = '0' + rem; - } else { - tmp[k++] = 'a' + (rem - 10); - } - num /= base; - } while (num > 0); - - /* Zero padding */ - if (flags && C_SNPRINTF_FLAG_ZERO) { - while (k < field_width && k < (int) sizeof(tmp) - 1) { - tmp[k++] = '0'; - } - } - - /* And sign */ - if (neg) { - tmp[k++] = '-'; - } - - /* Now output */ - while (--k >= 0) { - C_SNPRINTF_APPEND_CHAR(tmp[k]); - } - - return i; -} - -int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) { - int ch, i = 0, len_mod, flags, precision, field_width; - - while ((ch = *fmt++) != '\0') { - if (ch != '%') { - C_SNPRINTF_APPEND_CHAR(ch); - } else { - /* - * Conversion specification: - * zero or more flags (one of: # 0 - <space> + ') - * an optional minimum field width (digits) - * an optional precision (. followed by digits, or *) - * an optional length modifier (one of: hh h l ll L q j z t) - * conversion specifier (one of: d i o u x X e E f F g G a A c s p n) - */ - flags = field_width = precision = len_mod = 0; - - /* Flags. only zero-pad flag is supported. */ - if (*fmt == '0') { - flags |= C_SNPRINTF_FLAG_ZERO; - } - - /* Field width */ - while (*fmt >= '0' && *fmt <= '9') { - field_width *= 10; - field_width += *fmt++ - '0'; - } - /* Dynamic field width */ - if (*fmt == '*') { - field_width = va_arg(ap, int); - fmt++; - } - - /* Precision */ - if (*fmt == '.') { - fmt++; - if (*fmt == '*') { - precision = va_arg(ap, int); - fmt++; - } else { - while (*fmt >= '0' && *fmt <= '9') { - precision *= 10; - precision += *fmt++ - '0'; - } - } - } - - /* Length modifier */ - switch (*fmt) { - case 'h': - case 'l': - case 'L': - case 'I': - case 'q': - case 'j': - case 'z': - case 't': - len_mod = *fmt++; - if (*fmt == 'h') { - len_mod = 'H'; - fmt++; - } - if (*fmt == 'l') { - len_mod = 'q'; - fmt++; - } - break; - } - - ch = *fmt++; - if (ch == 's') { - const char *s = va_arg(ap, const char *); /* Always fetch parameter */ - int j; - int pad = field_width - (precision >= 0 ? strnlen(s, precision) : 0); - for (j = 0; j < pad; j++) { - C_SNPRINTF_APPEND_CHAR(' '); - } +int json_emit_va(char *s, int s_len, const char *fmt, va_list ap) { + const char *end = s + s_len, *str, *orig = s; + size_t len; - /* Ignore negative and 0 precisions */ - for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) { - C_SNPRINTF_APPEND_CHAR(s[j]); + while (*fmt != '\0') { + switch (*fmt) { + case '[': case ']': case '{': case '}': case ',': case ':': + case ' ': case '\r': case '\n': case '\t': + if (s < end) { + *s = *fmt; } - } else if (ch == 'c') { - ch = va_arg(ap, int); /* Always fetch parameter */ - C_SNPRINTF_APPEND_CHAR(ch); - } else if (ch == 'd' && len_mod == 0) { - i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags, - field_width); - } else if (ch == 'd' && len_mod == 'l') { - i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags, - field_width); - } else if ((ch == 'x' || ch == 'u') && len_mod == 0) { - i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned), - ch == 'x' ? 16 : 10, flags, field_width); - } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') { - i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long), - ch == 'x' ? 16 : 10, flags, field_width); - } else if (ch == 'p') { - unsigned long num = (unsigned long) va_arg(ap, void *); - C_SNPRINTF_APPEND_CHAR('0'); - C_SNPRINTF_APPEND_CHAR('x'); - i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0); - } else { -#ifndef NO_LIBC - /* - * TODO(lsm): abort is not nice in a library, remove it - * Also, ESP8266 SDK doesn't have it - */ - abort(); -#endif - } + s++; + break; + case 'i': + s += json_emit_long(s, end - s, va_arg(ap, long)); + break; + case 'f': + s += json_emit_double(s, end - s, va_arg(ap, double)); + break; + case 'v': + str = va_arg(ap, char *); + len = va_arg(ap, size_t); + s += json_emit_quoted_str(s, end - s, str, len); + break; + case 'V': + str = va_arg(ap, char *); + len = va_arg(ap, size_t); + s += json_emit_unquoted_str(s, end - s, str, len); + break; + case 's': + str = va_arg(ap, char *); + s += json_emit_quoted_str(s, end - s, str, strlen(str)); + break; + case 'S': + str = va_arg(ap, char *); + s += json_emit_unquoted_str(s, end - s, str, strlen(str)); + break; + case 'T': + s += json_emit_unquoted_str(s, end - s, "true", 4); + break; + case 'F': + s += json_emit_unquoted_str(s, end - s, "false", 5); + break; + case 'N': + s += json_emit_unquoted_str(s, end - s, "null", 4); + break; + default: + return 0; } + fmt++; } - /* Zero-terminate the result */ - if (buf_size > 0) { - buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0'; + /* Best-effort to 0-terminate generated string */ + if (s < end) { + *s = '\0'; } - return i; + return s - orig; } -#endif -int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) { - int result; +int json_emit(char *buf, int buf_len, const char *fmt, ...) { + int len; va_list ap; + va_start(ap, fmt); - result = c_vsnprintf(buf, buf_size, fmt, ap); + len = json_emit_va(buf, buf_len, fmt, ap); va_end(ap); - return result; -} - -#ifdef _WIN32 -void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) { - char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p; - strncpy(buf, path, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - - /* Trim trailing slashes. Leave backslash for paths like "X:\" */ - p = buf + strlen(buf) - 1; - while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0'; - - /* - * Convert to Unicode and back. If doubly-converted string does not - * match the original, something is fishy, reject. - */ - memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); - WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), - NULL, NULL); - if (strcmp(buf, buf2) != 0) { - wbuf[0] = L'\0'; - } + return len; } -#endif /* _WIN32 */ - -#endif /* EXCLUDE_COMMON */ #ifdef NS_MODULE_LINES -#line 1 "src/../../common/dirent.c" +#line 1 "src/../../common/md5.c" /**/ #endif /* - * Copyright (c) 2015 Cesanta Software Limited - * All rights reserved + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. */ -#ifndef EXCLUDE_COMMON +#if !defined(DISABLE_MD5) && !defined(EXCLUDE_COMMON) -/* Amalgamated: #include "osdep.h" */ +/* Amalgamated: #include "md5.h" */ + +#ifndef CS_ENABLE_NATIVE_MD5 +static void byteReverse(unsigned char *buf, unsigned longs) { +/* Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN */ +#if BYTE_ORDER == BIG_ENDIAN + do { + uint32_t t = (uint32_t)((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--longs); +#else + (void) buf; + (void) longs; +#endif +} + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) /* - * This file contains POSIX opendir/closedir/readdir API implementation - * for systems which do not natively support it (e.g. Windows). + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. */ +void MD5_Init(MD5_CTX *ctx) { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; -#ifndef MG_FREE -#define MG_FREE free -#endif + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} -#ifndef MG_MALLOC -#define MG_MALLOC malloc -#endif +static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { + register uint32_t a, b, c, d; -#ifdef _WIN32 -DIR *opendir(const char *name) { - DIR *dir = NULL; - wchar_t wpath[MAX_PATH]; - DWORD attrs; + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; - if (name == NULL) { - SetLastError(ERROR_BAD_ARGUMENTS); - } else if ((dir = (DIR *) MG_MALLOC(sizeof(*dir))) == NULL) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - } else { - to_wchar(name, wpath, ARRAY_SIZE(wpath)); - attrs = GetFileAttributesW(wpath); - if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { - (void) wcscat(wpath, L"\\*"); - dir->handle = FindFirstFileW(wpath, &dir->info); - dir->result.d_name[0] = '\0'; - } else { - MG_FREE(dir); - dir = NULL; - } - } + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - return dir; -} + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); -int closedir(DIR *dir) { - int result = 0; + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - if (dir != NULL) { - if (dir->handle != INVALID_HANDLE_VALUE) - result = FindClose(dir->handle) ? 0 : -1; - MG_FREE(dir); - } else { - result = -1; - SetLastError(ERROR_BAD_ARGUMENTS); - } + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - return result; + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; } -struct dirent *readdir(DIR *dir) { - struct dirent *result = 0; +void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { + uint32_t t; - if (dir) { - if (dir->handle != INVALID_HANDLE_VALUE) { - result = &dir->result; - (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1, - result->d_name, sizeof(result->d_name), NULL, - NULL); + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; + ctx->bits[1] += (uint32_t) len >> 29; - if (!FindNextFileW(dir->handle, &dir->info)) { - (void) FindClose(dir->handle); - dir->handle = INVALID_HANDLE_VALUE; - } + t = (t >> 3) & 0x3f; - } else { - SetLastError(ERROR_FILE_NOT_FOUND); + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; } - } else { - SetLastError(ERROR_BAD_ARGUMENTS); + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; } - return result; -} -#endif - -#endif /* EXCLUDE_COMMON */ -#ifdef NS_MODULE_LINES -#line 1 "src/../deps/frozen/frozen.c" -/**/ -#endif -/* - * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com> - * Copyright (c) 2013 Cesanta Software Limited - * All rights reserved - * - * This library is dual-licensed: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. For the terms of this - * license, see <http: *www.gnu.org/licenses/>. - * - * You are free to use this library under the terms of the GNU General - * Public License, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * Alternatively, you can license this library under a commercial - * license, as set out in <https://www.cesanta.com/license>. - */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } -#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */ + memcpy(ctx->in, buf, len); +} -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -/* Amalgamated: #include "frozen.h" */ +void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) { + unsigned count; + unsigned char *p; + uint32_t *a; -#ifdef _WIN32 -#define snprintf _snprintf -#endif + count = (ctx->bits[0] >> 3) & 0x3F; -#ifndef FROZEN_REALLOC -#define FROZEN_REALLOC realloc -#endif - -#ifndef FROZEN_FREE -#define FROZEN_FREE free -#endif + p = ctx->in + count; + *p++ = 0x80; + count = 64 - 1 - count; + if (count < 8) { + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); -struct frozen { - const char *end; - const char *cur; - struct json_token *tokens; - int max_tokens; - int num_tokens; - int do_realloc; -}; + a = (uint32_t *) ctx->in; + a[14] = ctx->bits[0]; + a[15] = ctx->bits[1]; -static int parse_object(struct frozen *f); -static int parse_value(struct frozen *f); + MD5Transform(ctx->buf, (uint32_t *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(*ctx)); +} +#endif /* CS_ENABLE_NATIVE_MD5 */ -#define EXPECT(cond, err_code) do { if (!(cond)) return (err_code); } while (0) -#define TRY(expr) do { int _n = expr; if (_n < 0) return _n; } while (0) -#define END_OF_STRING (-1) +/* + * Stringify binary data. Output buffer size must be 2 * size_of_input + 1 + * because each byte of input takes 2 bytes in string representation + * plus 1 byte for the terminating \0 character. + */ +void cs_to_hex(char *to, const unsigned char *p, size_t len) { + static const char *hex = "0123456789abcdef"; -static int left(const struct frozen *f) { - return f->end - f->cur; + for (; len--; p++) { + *to++ = hex[p[0] >> 4]; + *to++ = hex[p[0] & 0x0f]; + } + *to = '\0'; } -static int is_space(int ch) { - return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; -} +char *cs_md5(char buf[33], ...) { + unsigned char hash[16]; + const unsigned char *p; + va_list ap; + MD5_CTX ctx; -static void skip_whitespaces(struct frozen *f) { - while (f->cur < f->end && is_space(*f->cur)) f->cur++; -} + MD5_Init(&ctx); -static int cur(struct frozen *f) { - skip_whitespaces(f); - return f->cur >= f->end ? END_OF_STRING : * (unsigned char *) f->cur; -} + va_start(ap, buf); + while ((p = va_arg(ap, const unsigned char *) ) != NULL) { + size_t len = va_arg(ap, size_t); + MD5_Update(&ctx, p, len); + } + va_end(ap); -static int test_and_skip(struct frozen *f, int expected) { - int ch = cur(f); - if (ch == expected) { f->cur++; return 0; } - return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; -} + MD5_Final(hash, &ctx); + cs_to_hex(buf, hash, sizeof(hash)); -static int is_alpha(int ch) { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); + return buf; } -static int is_digit(int ch) { - return ch >= '0' && ch <= '9'; -} +#endif /* EXCLUDE_COMMON */ +#ifdef NS_MODULE_LINES +#line 1 "src/../../common/mbuf.c" +/**/ +#endif +/* + * Copyright (c) 2014 Cesanta Software Limited + * All rights reserved + */ -static int is_hex_digit(int ch) { - return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +#ifndef EXCLUDE_COMMON + +#include <assert.h> +#include <string.h> +/* Amalgamated: #include "mbuf.h" */ + +#ifndef MBUF_REALLOC +#define MBUF_REALLOC realloc +#endif + +#ifndef MBUF_FREE +#define MBUF_FREE free +#endif + +void mbuf_init(struct mbuf *mbuf, size_t initial_size) { + mbuf->len = mbuf->size = 0; + mbuf->buf = NULL; + mbuf_resize(mbuf, initial_size); } -static int get_escape_len(const char *s, int len) { - switch (*s) { - case 'u': - return len < 6 ? JSON_STRING_INCOMPLETE : - is_hex_digit(s[1]) && is_hex_digit(s[2]) && - is_hex_digit(s[3]) && is_hex_digit(s[4]) ? 5 : JSON_STRING_INVALID; - case '"': case '\\': case '/': case 'b': - case 'f': case 'n': case 'r': case 't': - return len < 2 ? JSON_STRING_INCOMPLETE : 1; - default: - return JSON_STRING_INVALID; +void mbuf_free(struct mbuf *mbuf) { + if (mbuf->buf != NULL) { + MBUF_FREE(mbuf->buf); + mbuf_init(mbuf, 0); } } -static int capture_ptr(struct frozen *f, const char *ptr, enum json_type type) { - if (f->do_realloc && f->num_tokens >= f->max_tokens) { - int new_size = f->max_tokens == 0 ? 100 : f->max_tokens * 2; - void *p = FROZEN_REALLOC(f->tokens, new_size * sizeof(f->tokens[0])); - if (p == NULL) return JSON_TOKEN_ARRAY_TOO_SMALL; - f->max_tokens = new_size; - f->tokens = (struct json_token *) p; +void mbuf_resize(struct mbuf *a, size_t new_size) { + if (new_size > a->size || (new_size < a->size && new_size >= a->len)) { + char *buf = (char *) MBUF_REALLOC(a->buf, new_size); + /* + * In case realloc fails, there's not much we can do, except keep things as + * they are. Note that NULL is a valid return value from realloc when + * size == 0, but that is covered too. + */ + if (buf == NULL && new_size != 0) return; + a->buf = buf; + a->size = new_size; } - if (f->tokens == NULL || f->max_tokens == 0) return 0; - if (f->num_tokens >= f->max_tokens) return JSON_TOKEN_ARRAY_TOO_SMALL; - f->tokens[f->num_tokens].ptr = ptr; - f->tokens[f->num_tokens].type = type; - f->num_tokens++; - return 0; } -static int capture_len(struct frozen *f, int token_index, const char *ptr) { - if (f->tokens == 0 || f->max_tokens == 0) return 0; - EXPECT(token_index >= 0 && token_index < f->max_tokens, JSON_STRING_INVALID); - f->tokens[token_index].len = ptr - f->tokens[token_index].ptr; - f->tokens[token_index].num_desc = (f->num_tokens - 1) - token_index; - return 0; +void mbuf_trim(struct mbuf *mbuf) { + mbuf_resize(mbuf, mbuf->len); } -/* identifier = letter { letter | digit | '_' } */ -static int parse_identifier(struct frozen *f) { - EXPECT(is_alpha(cur(f)), JSON_STRING_INVALID); - TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING)); - while (f->cur < f->end && - (*f->cur == '_' || is_alpha(*f->cur) || is_digit(*f->cur))) { - f->cur++; +size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) { + char *p = NULL; + + assert(a != NULL); + assert(a->len <= a->size); + assert(off <= a->len); + + /* check overflow */ + if (~(size_t) 0 - (size_t) a->buf < len) return 0; + + if (a->len + len <= a->size) { + memmove(a->buf + off + len, a->buf + off, a->len - off); + if (buf != NULL) { + memcpy(a->buf + off, buf, len); + } + a->len += len; + } else if ((p = (char *) MBUF_REALLOC( + a->buf, (a->len + len) * MBUF_SIZE_MULTIPLIER)) != NULL) { + a->buf = p; + memmove(a->buf + off + len, a->buf + off, a->len - off); + if (buf != NULL) { + memcpy(a->buf + off, buf, len); + } + a->len += len; + a->size = a->len * MBUF_SIZE_MULTIPLIER; + } else { + len = 0; } - capture_len(f, f->num_tokens - 1, f->cur); - return 0; + + return len; } -static int get_utf8_char_len(unsigned char ch) { - if ((ch & 0x80) == 0) return 1; - switch (ch & 0xf0) { - case 0xf0: return 4; - case 0xe0: return 3; - default: return 2; - } +size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) { + return mbuf_insert(a, a->len, buf, len); } -/* string = '"' { quoted_printable_chars } '"' */ -static int parse_string(struct frozen *f) { - int n, ch = 0, len = 0; - TRY(test_and_skip(f, '"')); - TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING)); - for (; f->cur < f->end; f->cur += len) { - ch = * (unsigned char *) f->cur; - len = get_utf8_char_len((unsigned char) ch); - EXPECT(ch >= 32 && len > 0, JSON_STRING_INVALID); /* No control chars */ - EXPECT(len < left(f), JSON_STRING_INCOMPLETE); - if (ch == '\\') { - EXPECT((n = get_escape_len(f->cur + 1, left(f))) > 0, n); - len += n; - } else if (ch == '"') { - capture_len(f, f->num_tokens - 1, f->cur); - f->cur++; - break; - }; +void mbuf_remove(struct mbuf *mb, size_t n) { + if (n > 0 && n <= mb->len) { + memmove(mb->buf, mb->buf + n, mb->len - n); + mb->len -= n; } - return ch == '"' ? 0 : JSON_STRING_INCOMPLETE; } -/* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */ -static int parse_number(struct frozen *f) { - int ch = cur(f); - TRY(capture_ptr(f, f->cur, JSON_TYPE_NUMBER)); - if (ch == '-') f->cur++; - EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); - EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); - while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; - if (f->cur < f->end && f->cur[0] == '.') { - f->cur++; - EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); - EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); - while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; - } - if (f->cur < f->end && (f->cur[0] == 'e' || f->cur[0] == 'E')) { - f->cur++; - EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); - if ((f->cur[0] == '+' || f->cur[0] == '-')) f->cur++; - EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); - EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); - while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; - } - capture_len(f, f->num_tokens - 1, f->cur); - return 0; +#endif /* EXCLUDE_COMMON */ +#ifdef NS_MODULE_LINES +#line 1 "src/../../common/sha1.c" +/**/ +#endif +/* Copyright(c) By Steve Reid <steve@edmweb.com> */ +/* 100% Public Domain */ + +#if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON) + +/* Amalgamated: #include "sha1.h" */ + +#define SHA1HANDSOFF +#if defined(__sun) +/* Amalgamated: #include "solarisfixes.h" */ +#endif + +union char64long16 { + unsigned char c[64]; + uint32_t l[16]; +}; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +static uint32_t blk0(union char64long16 *block, int i) { +/* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */ +#if BYTE_ORDER == LITTLE_ENDIAN + block->l[i] = + (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF); +#endif + return block->l[i]; } -/* array = '[' [ value { ',' value } ] ']' */ -static int parse_array(struct frozen *f) { - int ind; - TRY(test_and_skip(f, '[')); - TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_ARRAY)); - ind = f->num_tokens - 1; - while (cur(f) != ']') { - TRY(parse_value(f)); - if (cur(f) == ',') f->cur++; - } - TRY(test_and_skip(f, ']')); - capture_len(f, ind, f->cur); - return 0; +/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ +#undef blk +#undef R0 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +#define blk(i) \ + (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ + block->l[(i + 2) & 15] ^ block->l[i & 15], \ + 1)) +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +void cs_sha1_transform(uint32_t state[5], const unsigned char buffer[64]) { + uint32_t a, b, c, d, e; + union char64long16 block[1]; + + memcpy(block, buffer, 64); + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Erase working structures. The order of operations is important, + * used to ensure that compiler doesn't optimize those out. */ + memset(block, 0, sizeof(block)); + a = b = c = d = e = 0; + (void) a; + (void) b; + (void) c; + (void) d; + (void) e; } -static int compare(const char *s, const char *str, int len) { - int i = 0; - while (i < len && s[i] == str[i]) i++; - return i == len ? 1 : 0; +void cs_sha1_init(cs_sha1_ctx *context) { + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; } -static int expect(struct frozen *f, const char *s, int len, enum json_type t) { - int i, n = left(f); - - TRY(capture_ptr(f, f->cur, t)); - for (i = 0; i < len; i++) { - if (i >= n) return JSON_STRING_INCOMPLETE; - if (f->cur[i] != s[i]) return JSON_STRING_INVALID; - } - f->cur += len; - TRY(capture_len(f, f->num_tokens - 1, f->cur)); +void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len) { + uint32_t i, j; - return 0; + j = context->count[0]; + if ((context->count[0] += len << 3) < j) context->count[1]++; + context->count[1] += (len >> 29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64 - j)); + cs_sha1_transform(context->state, context->buffer); + for (; i + 63 < len; i += 64) { + cs_sha1_transform(context->state, &data[i]); + } + j = 0; + } else + i = 0; + memcpy(&context->buffer[j], &data[i], len - i); } -/* value = 'null' | 'true' | 'false' | number | string | array | object */ -static int parse_value(struct frozen *f) { - int ch = cur(f); +void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) { + unsigned i; + unsigned char finalcount[8], c; - switch (ch) { - case '"': TRY(parse_string(f)); break; - case '{': TRY(parse_object(f)); break; - case '[': TRY(parse_array(f)); break; - case 'n': TRY(expect(f, "null", 4, JSON_TYPE_NULL)); break; - case 't': TRY(expect(f, "true", 4, JSON_TYPE_TRUE)); break; - case 'f': TRY(expect(f, "false", 5, JSON_TYPE_FALSE)); break; - case '-': case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - TRY(parse_number(f)); - break; - default: - return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> + ((3 - (i & 3)) * 8)) & + 255); } - - return 0; + c = 0200; + cs_sha1_update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + cs_sha1_update(context, &c, 1); + } + cs_sha1_update(context, finalcount, 8); + for (i = 0; i < 20; i++) { + digest[i] = + (unsigned char) ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); } -/* key = identifier | string */ -static int parse_key(struct frozen *f) { - int ch = cur(f); -#if 0 - printf("%s 1 [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur); -#endif - if (is_alpha(ch)) { - TRY(parse_identifier(f)); - } else if (ch == '"') { - TRY(parse_string(f)); - } else { - return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; +void cs_hmac_sha1(const unsigned char *key, size_t keylen, + const unsigned char *data, size_t datalen, + unsigned char out[20]) { + cs_sha1_ctx ctx; + unsigned char buf1[64], buf2[64], tmp_key[20], i; + + if (keylen > sizeof(buf1)) { + cs_sha1_init(&ctx); + cs_sha1_update(&ctx, key, keylen); + cs_sha1_final(tmp_key, &ctx); + key = tmp_key; + keylen = sizeof(tmp_key); } - return 0; -} -/* pair = key ':' value */ -static int parse_pair(struct frozen *f) { - TRY(parse_key(f)); - TRY(test_and_skip(f, ':')); - TRY(parse_value(f)); - return 0; -} + memset(buf1, 0, sizeof(buf1)); + memset(buf2, 0, sizeof(buf2)); + memcpy(buf1, key, keylen); + memcpy(buf2, key, keylen); -/* object = '{' pair { ',' pair } '}' */ -static int parse_object(struct frozen *f) { - int ind; - TRY(test_and_skip(f, '{')); - TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_OBJECT)); - ind = f->num_tokens - 1; - while (cur(f) != '}') { - TRY(parse_pair(f)); - if (cur(f) == ',') f->cur++; + for (i = 0; i < sizeof(buf1); i++) { + buf1[i] ^= 0x36; + buf2[i] ^= 0x5c; } - TRY(test_and_skip(f, '}')); - capture_len(f, ind, f->cur); - return 0; -} -static int doit(struct frozen *f) { - if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID; - if (f->end == f->cur) return JSON_STRING_INCOMPLETE; - TRY(parse_object(f)); - TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF)); - capture_len(f, f->num_tokens, f->cur); - return 0; + cs_sha1_init(&ctx); + cs_sha1_update(&ctx, buf1, sizeof(buf1)); + cs_sha1_update(&ctx, data, datalen); + cs_sha1_final(out, &ctx); + + cs_sha1_init(&ctx); + cs_sha1_update(&ctx, buf2, sizeof(buf2)); + cs_sha1_update(&ctx, out, 20); + cs_sha1_final(out, &ctx); } -/* json = object */ -int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) { - struct frozen frozen; +#endif /* EXCLUDE_COMMON */ +#ifdef NS_MODULE_LINES +#line 1 "src/../../common/str_util.c" +/**/ +#endif +/* + * Copyright (c) 2015 Cesanta Software Limited + * All rights reserved + */ - memset(&frozen, 0, sizeof(frozen)); - frozen.end = s + s_len; - frozen.cur = s; - frozen.tokens = arr; - frozen.max_tokens = arr_len; +#ifndef EXCLUDE_COMMON - TRY(doit(&frozen)); +/* Amalgamated: #include "osdep.h" */ +/* Amalgamated: #include "str_util.h" */ - return frozen.cur - s; +#if !(_XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L) && \ + !(__DARWIN_C_LEVEL >= 200809L) && !defined(RTOS_SDK) || \ + defined(_WIN32) +size_t strnlen(const char *s, size_t maxlen) { + size_t l = 0; + for (; l < maxlen && s[l] != '\0'; l++) { + } + return l; } +#endif -struct json_token *parse_json2(const char *s, int s_len) { - struct frozen frozen; +#define C_SNPRINTF_APPEND_CHAR(ch) \ + do { \ + if (i < (int) buf_size) buf[i] = ch; \ + i++; \ + } while (0) - memset(&frozen, 0, sizeof(frozen)); - frozen.end = s + s_len; - frozen.cur = s; - frozen.do_realloc = 1; +#define C_SNPRINTF_FLAG_ZERO 1 - if (doit(&frozen) < 0) { - FROZEN_FREE((void *) frozen.tokens); - frozen.tokens = NULL; - } - return frozen.tokens; +#ifdef C_DISABLE_BUILTIN_SNPRINTF +int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) { + return vsnprintf(buf, buf_size, fmt, ap); } +#else +static int c_itoa(char *buf, size_t buf_size, int64_t num, int base, int flags, + int field_width) { + char tmp[40]; + int i = 0, k = 0, neg = 0; -static int path_part_len(const char *p) { - int i = 0; - while (p[i] != '\0' && p[i] != '[' && p[i] != '.') i++; - return i; -} + if (num < 0) { + neg++; + num = -num; + } -struct json_token *find_json_token(struct json_token *toks, const char *path) { - while (path != 0 && path[0] != '\0') { - int i, ind2 = 0, ind = -1, skip = 2, n = path_part_len(path); - if (path[0] == '[') { - if (toks->type != JSON_TYPE_ARRAY || !is_digit(path[1])) return 0; - for (ind = 0, n = 1; path[n] != ']' && path[n] != '\0'; n++) { - if (!is_digit(path[n])) return 0; - ind *= 10; - ind += path[n] - '0'; - } - if (path[n++] != ']') return 0; - skip = 1; /* In objects, we skip 2 elems while iterating, in arrays 1. */ - } else if (toks->type != JSON_TYPE_OBJECT) return 0; - toks++; - for (i = 0; i < toks[-1].num_desc; i += skip, ind2++) { - /* ind == -1 indicated that we're iterating an array, not object */ - if (ind == -1 && toks[i].type != JSON_TYPE_STRING) return 0; - if (ind2 == ind || - (ind == -1 && toks[i].len == n && compare(path, toks[i].ptr, n))) { - i += skip - 1; - break; - }; - if (toks[i - 1 + skip].type == JSON_TYPE_ARRAY || - toks[i - 1 + skip].type == JSON_TYPE_OBJECT) { - i += toks[i - 1 + skip].num_desc; - } + /* Print into temporary buffer - in reverse order */ + do { + int rem = num % base; + if (rem < 10) { + tmp[k++] = '0' + rem; + } else { + tmp[k++] = 'a' + (rem - 10); + } + num /= base; + } while (num > 0); + + /* Zero padding */ + if (flags && C_SNPRINTF_FLAG_ZERO) { + while (k < field_width && k < (int) sizeof(tmp) - 1) { + tmp[k++] = '0'; } - if (i == toks[-1].num_desc) return 0; - path += n; - if (path[0] == '.') path++; - if (path[0] == '\0') return &toks[i]; - toks += i; } - return 0; -} -int json_emit_long(char *buf, int buf_len, long int value) { - char tmp[20]; - int n = snprintf(tmp, sizeof(tmp), "%ld", value); - strncpy(buf, tmp, buf_len > 0 ? buf_len : 0); - return n; -} + /* And sign */ + if (neg) { + tmp[k++] = '-'; + } -int json_emit_double(char *buf, int buf_len, double value) { - char tmp[20]; - int n = snprintf(tmp, sizeof(tmp), "%g", value); - strncpy(buf, tmp, buf_len > 0 ? buf_len : 0); - return n; + /* Now output */ + while (--k >= 0) { + C_SNPRINTF_APPEND_CHAR(tmp[k]); + } + + return i; } -int json_emit_quoted_str(char *s, int s_len, const char *str, int len) { - const char *begin = s, *end = s + s_len, *str_end = str + len; - char ch; +int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) { + int ch, i = 0, len_mod, flags, precision, field_width; -#define EMIT(x) do { if (s < end) *s = x; s++; } while (0) + while ((ch = *fmt++) != '\0') { + if (ch != '%') { + C_SNPRINTF_APPEND_CHAR(ch); + } else { + /* + * Conversion specification: + * zero or more flags (one of: # 0 - <space> + ') + * an optional minimum field width (digits) + * an optional precision (. followed by digits, or *) + * an optional length modifier (one of: hh h l ll L q j z t) + * conversion specifier (one of: d i o u x X e E f F g G a A c s p n) + */ + flags = field_width = precision = len_mod = 0; - EMIT('"'); - while (str < str_end) { - ch = *str++; - switch (ch) { - case '"': EMIT('\\'); EMIT('"'); break; - case '\\': EMIT('\\'); EMIT('\\'); break; - case '\b': EMIT('\\'); EMIT('b'); break; - case '\f': EMIT('\\'); EMIT('f'); break; - case '\n': EMIT('\\'); EMIT('n'); break; - case '\r': EMIT('\\'); EMIT('r'); break; - case '\t': EMIT('\\'); EMIT('t'); break; - default: EMIT(ch); - } - } - EMIT('"'); - if (s < end) { - *s = '\0'; - } + /* Flags. only zero-pad flag is supported. */ + if (*fmt == '0') { + flags |= C_SNPRINTF_FLAG_ZERO; + } - return s - begin; -} + /* Field width */ + while (*fmt >= '0' && *fmt <= '9') { + field_width *= 10; + field_width += *fmt++ - '0'; + } + /* Dynamic field width */ + if (*fmt == '*') { + field_width = va_arg(ap, int); + fmt++; + } -int json_emit_unquoted_str(char *buf, int buf_len, const char *str, int len) { - if (buf_len > 0 && len > 0) { - int n = len < buf_len ? len : buf_len; - memcpy(buf, str, n); - if (n < buf_len) { - buf[n] = '\0'; - } - } - return len; -} + /* Precision */ + if (*fmt == '.') { + fmt++; + if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + } else { + while (*fmt >= '0' && *fmt <= '9') { + precision *= 10; + precision += *fmt++ - '0'; + } + } + } -int json_emit_va(char *s, int s_len, const char *fmt, va_list ap) { - const char *end = s + s_len, *str, *orig = s; - size_t len; + /* Length modifier */ + switch (*fmt) { + case 'h': + case 'l': + case 'L': + case 'I': + case 'q': + case 'j': + case 'z': + case 't': + len_mod = *fmt++; + if (*fmt == 'h') { + len_mod = 'H'; + fmt++; + } + if (*fmt == 'l') { + len_mod = 'q'; + fmt++; + } + break; + } - while (*fmt != '\0') { - switch (*fmt) { - case '[': case ']': case '{': case '}': case ',': case ':': - case ' ': case '\r': case '\n': case '\t': - if (s < end) { - *s = *fmt; + ch = *fmt++; + if (ch == 's') { + const char *s = va_arg(ap, const char *); /* Always fetch parameter */ + int j; + int pad = field_width - (precision >= 0 ? strnlen(s, precision) : 0); + for (j = 0; j < pad; j++) { + C_SNPRINTF_APPEND_CHAR(' '); } - s++; - break; - case 'i': - s += json_emit_long(s, end - s, va_arg(ap, long)); - break; - case 'f': - s += json_emit_double(s, end - s, va_arg(ap, double)); - break; - case 'v': - str = va_arg(ap, char *); - len = va_arg(ap, size_t); - s += json_emit_quoted_str(s, end - s, str, len); - break; - case 'V': - str = va_arg(ap, char *); - len = va_arg(ap, size_t); - s += json_emit_unquoted_str(s, end - s, str, len); - break; - case 's': - str = va_arg(ap, char *); - s += json_emit_quoted_str(s, end - s, str, strlen(str)); - break; - case 'S': - str = va_arg(ap, char *); - s += json_emit_unquoted_str(s, end - s, str, strlen(str)); - break; - case 'T': - s += json_emit_unquoted_str(s, end - s, "true", 4); - break; - case 'F': - s += json_emit_unquoted_str(s, end - s, "false", 5); - break; - case 'N': - s += json_emit_unquoted_str(s, end - s, "null", 4); - break; - default: - return 0; + + /* Ignore negative and 0 precisions */ + for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) { + C_SNPRINTF_APPEND_CHAR(s[j]); + } + } else if (ch == 'c') { + ch = va_arg(ap, int); /* Always fetch parameter */ + C_SNPRINTF_APPEND_CHAR(ch); + } else if (ch == 'd' && len_mod == 0) { + i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags, + field_width); + } else if (ch == 'd' && len_mod == 'l') { + i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags, + field_width); + } else if ((ch == 'x' || ch == 'u') && len_mod == 0) { + i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned), + ch == 'x' ? 16 : 10, flags, field_width); + } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') { + i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long), + ch == 'x' ? 16 : 10, flags, field_width); + } else if (ch == 'p') { + unsigned long num = (unsigned long) va_arg(ap, void *); + C_SNPRINTF_APPEND_CHAR('0'); + C_SNPRINTF_APPEND_CHAR('x'); + i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0); + } else { +#ifndef NO_LIBC + /* + * TODO(lsm): abort is not nice in a library, remove it + * Also, ESP8266 SDK doesn't have it + */ + abort(); +#endif + } } - fmt++; } - /* Best-effort to 0-terminate generated string */ - if (s < end) { - *s = '\0'; + /* Zero-terminate the result */ + if (buf_size > 0) { + buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0'; } - return s - orig; + return i; } +#endif -int json_emit(char *buf, int buf_len, const char *fmt, ...) { - int len; +int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) { + int result; va_list ap; - va_start(ap, fmt); - len = json_emit_va(buf, buf_len, fmt, ap); + result = c_vsnprintf(buf, buf_size, fmt, ap); va_end(ap); + return result; +} - return len; +#ifdef _WIN32 +void to_wchar(const char *path, wchar_t *wbuf, size_t wbuf_len) { + char buf[MAX_PATH * 2], buf2[MAX_PATH * 2], *p; + + strncpy(buf, path, sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + + /* Trim trailing slashes. Leave backslash for paths like "X:\" */ + p = buf + strlen(buf) - 1; + while (p > buf && p[-1] != ':' && (p[0] == '\\' || p[0] == '/')) *p-- = '\0'; + + /* + * Convert to Unicode and back. If doubly-converted string does not + * match the original, something is fishy, reject. + */ + memset(wbuf, 0, wbuf_len * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len); + WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2), + NULL, NULL); + if (strcmp(buf, buf2) != 0) { + wbuf[0] = L'\0'; + } } +#endif /* _WIN32 */ + +#endif /* EXCLUDE_COMMON */ #ifdef NS_MODULE_LINES #line 1 "src/net.c" /**/ diff --git a/mongoose.h b/mongoose.h index fbcec51be..cbab9e092 100644 --- a/mongoose.h +++ b/mongoose.h @@ -26,6 +26,10 @@ #ifdef MG_LOCALS #include <mg_locals.h> #endif + +#if defined(MG_ENABLE_DEBUG) && !defined(CS_ENABLE_DEBUG) +#define CS_ENABLE_DEBUG +#endif /* * Copyright (c) 2015 Cesanta Software Limited * All rights reserved @@ -260,25 +264,31 @@ int64_t strtoll(const char *str, char **endptr, int base); #endif #endif /* !_WIN32 */ -#define __DBG(x) \ +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#endif + +#endif /* OSDEP_HEADER_INCLUDED */ +#ifndef _CS_DBG_H_ +#define _CS_DBG_H_ + +#ifdef CS_ENABLE_DEBUG + +void cs_dbg_printf(const char *fmt, ...); +#define __DBG(x) \ do { \ - printf("%-20s ", __func__); \ - printf x; \ - putchar('\n'); \ - fflush(stdout); \ + fprintf(stderr, "%-20s ", __func__); \ + cs_dbg_printf x; \ } while (0) - -#ifdef MG_ENABLE_DEBUG #define DBG __DBG + #else + #define DBG(x) -#endif -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) #endif -#endif /* OSDEP_HEADER_INCLUDED */ +#endif /* _CS_DBG_H_ */ /* * Copyright (c) 2015 Cesanta Software Limited * All rights reserved -- GitLab