Commit d60c99b0 authored by Deomid Ryabkov's avatar Deomid Ryabkov Committed by Sergey Lyubka

Make MG debug go to stderr

    PUBLISHED_FROM=11618b6b2a50c62dd612d241c6b13a9aab357909
parent b8aeba06
...@@ -111,7 +111,7 @@ extern void *(*test_calloc)(size_t, size_t); ...@@ -111,7 +111,7 @@ extern void *(*test_calloc)(size_t, size_t);
#endif /* MG_INTERNAL_HEADER_INCLUDED */ #endif /* MG_INTERNAL_HEADER_INCLUDED */
#ifdef NS_MODULE_LINES #ifdef NS_MODULE_LINES
#line 1 "src/../../common/mbuf.c" #line 1 "src/../../common/base64.c"
/**/ /**/
#endif #endif
/* /*
...@@ -121,1629 +121,1644 @@ extern void *(*test_calloc)(size_t, size_t); ...@@ -121,1629 +121,1644 @@ extern void *(*test_calloc)(size_t, size_t);
#ifndef EXCLUDE_COMMON #ifndef EXCLUDE_COMMON
#include <assert.h> /* Amalgamated: #include "base64.h" */
#include <string.h> #include <string.h>
/* Amalgamated: #include "mbuf.h" */
#ifndef MBUF_REALLOC /* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */
#define MBUF_REALLOC realloc
#endif
#ifndef MBUF_FREE #define NUM_UPPERCASES ('Z' - 'A' + 1)
#define MBUF_FREE free #define NUM_LETTERS (NUM_UPPERCASES * 2)
#endif #define NUM_DIGITS ('9' - '0' + 1)
void mbuf_init(struct mbuf *mbuf, size_t initial_size) { /*
mbuf->len = mbuf->size = 0; * Emit a base64 code char.
mbuf->buf = NULL; *
mbuf_resize(mbuf, initial_size); * 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) { static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) {
if (mbuf->buf != NULL) { int a, b, c;
MBUF_FREE(mbuf->buf);
mbuf_init(mbuf, 0); 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) { void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc,
if (new_size > a->size || (new_size < a->size && new_size >= a->len)) { void *user_data) {
char *buf = (char *) MBUF_REALLOC(a->buf, new_size); ctx->chunk_size = 0;
/* ctx->b64_putc = b64_putc;
* In case realloc fails, there's not much we can do, except keep things as ctx->user_data = user_data;
* they are. Note that NULL is a valid return value from realloc when }
* size == 0, but that is covered too.
*/ void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) {
if (buf == NULL && new_size != 0) return; const unsigned char *src = (const unsigned char *) str;
a->buf = buf; size_t i;
a->size = new_size; 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) { void cs_base64_finish(struct cs_base64_ctx *ctx) {
mbuf_resize(mbuf, mbuf->len); 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) { #define BASE64_ENCODE_BODY \
char *p = NULL; 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); #define BASE64_OUT(ch) \
assert(a->len <= a->size); do { \
assert(off <= a->len); dst[j++] = (ch); \
} while (0)
/* check overflow */ #define BASE64_FLUSH() \
if (~(size_t) 0 - (size_t) a->buf < len) return 0; do { \
dst[j++] = '\0'; \
} while (0)
if (a->len + len <= a->size) { void cs_base64_encode(const unsigned char *src, int src_len, char *dst) {
memmove(a->buf + off + len, a->buf + off, a->len - off); BASE64_ENCODE_BODY;
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;
}
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) { #undef BASE64_OUT
return mbuf_insert(a, a->len, buf, len); #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) { int cs_base64_decode(const unsigned char *s, int len, char *dst) {
if (n > 0 && n <= mb->len) { unsigned char a, b, c, d;
memmove(mb->buf, mb->buf + n, mb->len - n); int orig_len = len;
mb->len -= n; 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 */ #endif /* EXCLUDE_COMMON */
#ifdef NS_MODULE_LINES #ifdef NS_MODULE_LINES
#line 1 "src/../../common/sha1.c" #line 1 "src/../../common/cs_dbg.c"
/**/ /**/
#endif #endif
/* Copyright(c) By Steve Reid <steve@edmweb.com> */ #include <stdarg.h>
/* 100% Public Domain */ #include <stdio.h>
#if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON)
/* Amalgamated: #include "sha1.h" */
#define SHA1HANDSOFF void cs_dbg_printf(const char *fmt, ...) {
#if defined(__sun) va_list ap;
/* Amalgamated: #include "solarisfixes.h" */ 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 #endif
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*/
union char64long16 { #ifndef EXCLUDE_COMMON
unsigned char c[64];
uint32_t l[16];
};
#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 */ * This file contains POSIX opendir/closedir/readdir API implementation
#if BYTE_ORDER == LITTLE_ENDIAN * for systems which do not natively support it (e.g. Windows).
block->l[i] = */
(rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
#ifndef MG_FREE
#define MG_FREE free
#endif #endif
return block->l[i];
}
/* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */ #ifndef MG_MALLOC
#undef blk #define MG_MALLOC malloc
#undef R0 #endif
#undef R1
#undef R2
#undef R3
#undef R4
#define blk(i) \ #ifdef _WIN32
(block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \ DIR *opendir(const char *name) {
block->l[(i + 2) & 15] ^ block->l[i & 15], \ DIR *dir = NULL;
1)) wchar_t wpath[MAX_PATH];
#define R0(v, w, x, y, z, i) \ DWORD attrs;
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]) { if (name == NULL) {
uint32_t a, b, c, d, e; SetLastError(ERROR_BAD_ARGUMENTS);
union char64long16 block[1]; } 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); return dir;
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;
} }
void cs_sha1_init(cs_sha1_ctx *context) { int closedir(DIR *dir) {
context->state[0] = 0x67452301; int result = 0;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len) { if (dir != NULL) {
uint32_t i, j; 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]; return result;
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);
} }
void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) { struct dirent *readdir(DIR *dir) {
unsigned i; struct dirent *result = 0;
unsigned char finalcount[8], c;
for (i = 0; i < 8; i++) { if (dir) {
finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> if (dir->handle != INVALID_HANDLE_VALUE) {
((3 - (i & 3)) * 8)) & result = &dir->result;
255); (void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
} result->d_name, sizeof(result->d_name), NULL,
c = 0200; NULL);
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));
}
void cs_hmac_sha1(const unsigned char *key, size_t keylen, if (!FindNextFileW(dir->handle, &dir->info)) {
const unsigned char *data, size_t datalen, (void) FindClose(dir->handle);
unsigned char out[20]) { dir->handle = INVALID_HANDLE_VALUE;
cs_sha1_ctx ctx; }
unsigned char buf1[64], buf2[64], tmp_key[20], i;
if (keylen > sizeof(buf1)) { } else {
cs_sha1_init(&ctx); SetLastError(ERROR_FILE_NOT_FOUND);
cs_sha1_update(&ctx, key, keylen); }
cs_sha1_final(tmp_key, &ctx); } else {
key = tmp_key; SetLastError(ERROR_BAD_ARGUMENTS);
keylen = sizeof(tmp_key);
} }
memset(buf1, 0, sizeof(buf1)); return result;
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);
} }
#endif
#endif /* EXCLUDE_COMMON */ #endif /* EXCLUDE_COMMON */
#ifdef NS_MODULE_LINES #ifdef NS_MODULE_LINES
#line 1 "src/../../common/md5.c" #line 1 "src/../deps/frozen/frozen.c"
/**/ /**/
#endif #endif
/* /*
* This code implements the MD5 message-digest algorithm. * Copyright (c) 2004-2013 Sergey Lyubka <valenok@gmail.com>
* The algorithm is due to Ron Rivest. This code was * Copyright (c) 2013 Cesanta Software Limited
* written by Colin Plumb in 1993, no copyright is claimed. * All rights reserved
* This code is in the public domain; do with it what you wish.
* *
* Equivalent code is available from RSA Data Security, Inc. * This library is dual-licensed: you can redistribute it and/or modify
* This code has been tested against that, and is equivalent, * it under the terms of the GNU General Public License version 2 as
* except that you don't need to include two pages of legalese * published by the Free Software Foundation. For the terms of this
* with every copy. * license, see <http: *www.gnu.org/licenses/>.
* *
* To compute the message digest of a chunk of bytes, declare an * You are free to use this library under the terms of the GNU General
* MD5Context structure, pass it to MD5Init, call MD5Update as * Public License, but WITHOUT ANY WARRANTY; without even the implied
* needed on buffers full of bytes, and then call MD5Final, which * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* will fill a supplied 16-byte array with the digest. * 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 #ifdef _WIN32
static void byteReverse(unsigned char *buf, unsigned longs) { #define snprintf _snprintf
/* 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 #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)
/* #ifndef FROZEN_REALLOC
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious #define FROZEN_REALLOC realloc
* initialization constants. #endif
*/
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;
}
static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { #ifndef FROZEN_FREE
register uint32_t a, b, c, d; #define FROZEN_FREE free
#endif
a = buf[0]; struct frozen {
b = buf[1]; const char *end;
c = buf[2]; const char *cur;
d = buf[3]; struct json_token *tokens;
int max_tokens;
int num_tokens;
int do_realloc;
};
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); static int parse_object(struct frozen *f);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); static int parse_value(struct frozen *f);
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);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); #define EXPECT(cond, err_code) do { if (!(cond)) return (err_code); } while (0)
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); #define TRY(expr) do { int _n = expr; if (_n < 0) return _n; } while (0)
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); #define END_OF_STRING (-1)
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);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); static int left(const struct frozen *f) {
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); return f->end - f->cur;
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);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); static int is_space(int ch) {
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
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);
buf[0] += a; static void skip_whitespaces(struct frozen *f) {
buf[1] += b; while (f->cur < f->end && is_space(*f->cur)) f->cur++;
buf[2] += c;
buf[3] += d;
} }
void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) { static int cur(struct frozen *f) {
uint32_t t; skip_whitespaces(f);
return f->cur >= f->end ? END_OF_STRING : * (unsigned char *) f->cur;
}
t = ctx->bits[0]; static int test_and_skip(struct frozen *f, int expected) {
if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++; int ch = cur(f);
ctx->bits[1] += (uint32_t) len >> 29; 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) { static int is_digit(int ch) {
unsigned char *p = (unsigned char *) ctx->in + t; return ch >= '0' && ch <= '9';
}
t = 64 - t; static int is_hex_digit(int ch) {
if (len < t) { return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
memcpy(p, buf, len); }
return;
}
memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
buf += t;
len -= t;
}
while (len >= 64) { static int get_escape_len(const char *s, int len) {
memcpy(ctx->in, buf, 64); switch (*s) {
byteReverse(ctx->in, 16); case 'u':
MD5Transform(ctx->buf, (uint32_t *) ctx->in); return len < 6 ? JSON_STRING_INCOMPLETE :
buf += 64; is_hex_digit(s[1]) && is_hex_digit(s[2]) &&
len -= 64; 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) { static int capture_ptr(struct frozen *f, const char *ptr, enum json_type type) {
unsigned count; if (f->do_realloc && f->num_tokens >= f->max_tokens) {
unsigned char *p; int new_size = f->max_tokens == 0 ? 100 : f->max_tokens * 2;
uint32_t *a; void *p = FROZEN_REALLOC(f->tokens, new_size * sizeof(f->tokens[0]));
if (p == NULL) return JSON_TOKEN_ARRAY_TOO_SMALL;
count = (ctx->bits[0] >> 3) & 0x3F; f->max_tokens = new_size;
f->tokens = (struct json_token *) p;
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); if (f->tokens == NULL || f->max_tokens == 0) return 0;
if (f->num_tokens >= f->max_tokens) return JSON_TOKEN_ARRAY_TOO_SMALL;
a = (uint32_t *) ctx->in; f->tokens[f->num_tokens].ptr = ptr;
a[14] = ctx->bits[0]; f->tokens[f->num_tokens].type = type;
a[15] = ctx->bits[1]; f->num_tokens++;
return 0;
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 */
/* static int capture_len(struct frozen *f, int token_index, const char *ptr) {
* Stringify binary data. Output buffer size must be 2 * size_of_input + 1 if (f->tokens == 0 || f->max_tokens == 0) return 0;
* because each byte of input takes 2 bytes in string representation EXPECT(token_index >= 0 && token_index < f->max_tokens, JSON_STRING_INVALID);
* plus 1 byte for the terminating \0 character. f->tokens[token_index].len = ptr - f->tokens[token_index].ptr;
*/ f->tokens[token_index].num_desc = (f->num_tokens - 1) - token_index;
void cs_to_hex(char *to, const unsigned char *p, size_t len) { return 0;
static const char *hex = "0123456789abcdef"; }
for (; len--; p++) { /* identifier = letter { letter | digit | '_' } */
*to++ = hex[p[0] >> 4]; static int parse_identifier(struct frozen *f) {
*to++ = hex[p[0] & 0x0f]; 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], ...) { static int get_utf8_char_len(unsigned char ch) {
unsigned char hash[16]; if ((ch & 0x80) == 0) return 1;
const unsigned char *p; switch (ch & 0xf0) {
va_list ap; case 0xf0: return 4;
MD5_CTX ctx; 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); /* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */
while ((p = va_arg(ap, const unsigned char *) ) != NULL) { static int parse_number(struct frozen *f) {
size_t len = va_arg(ap, size_t); int ch = cur(f);
MD5_Update(&ctx, p, len); 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); /* array = '[' [ value { ',' value } ] ']' */
cs_to_hex(buf, hash, sizeof(hash)); 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 */ static int expect(struct frozen *f, const char *s, int len, enum json_type t) {
#ifdef NS_MODULE_LINES int i, n = left(f);
#line 1 "src/../../common/base64.c"
/**/
#endif
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*/
#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" */ return 0;
#include <string.h> }
/* 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) switch (ch) {
#define NUM_LETTERS (NUM_UPPERCASES * 2) case '"': TRY(parse_string(f)); break;
#define NUM_DIGITS ('9' - '0' + 1) 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;
}
/* return 0;
* Emit a base64 code char. }
*
* Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps /* key = identifier | string */
*/ static int parse_key(struct frozen *f) {
static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) { int ch = cur(f);
if (v < NUM_UPPERCASES) { #if 0
ctx->b64_putc(v + 'A', ctx->user_data); printf("%s 1 [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur);
} else if (v < (NUM_LETTERS)) { #endif
ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data); if (is_alpha(ch)) {
} else if (v < (NUM_LETTERS + NUM_DIGITS)) { TRY(parse_identifier(f));
ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data); } else if (ch == '"') {
TRY(parse_string(f));
} else { } else {
ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/', return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
ctx->user_data);
} }
return 0;
} }
static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) { /* pair = key ':' value */
int a, b, c; static int parse_pair(struct frozen *f) {
TRY(parse_key(f));
a = ctx->chunk[0]; TRY(test_and_skip(f, ':'));
b = ctx->chunk[1]; TRY(parse_value(f));
c = ctx->chunk[2]; return 0;
}
cs_base64_emit_code(ctx, a >> 2); /* object = '{' pair { ',' pair } '}' */
cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4)); static int parse_object(struct frozen *f) {
if (ctx->chunk_size > 1) { int ind;
cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6)); TRY(test_and_skip(f, '{'));
} TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_OBJECT));
if (ctx->chunk_size > 2) { ind = f->num_tokens - 1;
cs_base64_emit_code(ctx, c & 63); 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, static int doit(struct frozen *f) {
void *user_data) { if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID;
ctx->chunk_size = 0; if (f->end == f->cur) return JSON_STRING_INCOMPLETE;
ctx->b64_putc = b64_putc; TRY(parse_object(f));
ctx->user_data = user_data; TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF));
} capture_len(f, f->num_tokens, f->cur);
return 0;
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);
}
}
} }
#define BASE64_ENCODE_BODY \ /* json = object */
static const char *b64 = \ int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \ struct frozen frozen;
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()
#define BASE64_OUT(ch) \ memset(&frozen, 0, sizeof(frozen));
do { \ frozen.end = s + s_len;
dst[j++] = (ch); \ frozen.cur = s;
} while (0) frozen.tokens = arr;
frozen.max_tokens = arr_len;
#define BASE64_FLUSH() \ TRY(doit(&frozen));
do { \
dst[j++] = '\0'; \
} while (0)
void cs_base64_encode(const unsigned char *src, int src_len, char *dst) { return frozen.cur - s;
BASE64_ENCODE_BODY;
} }
#undef BASE64_OUT struct json_token *parse_json2(const char *s, int s_len) {
#undef BASE64_FLUSH struct frozen frozen;
#define BASE64_OUT(ch) \ memset(&frozen, 0, sizeof(frozen));
do { \ frozen.end = s + s_len;
fprintf(f, "%c", (ch)); \ frozen.cur = s;
j++; \ frozen.do_realloc = 1;
} while (0)
#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) { static int path_part_len(const char *p) {
BASE64_ENCODE_BODY; int i = 0;
while (p[i] != '\0' && p[i] != '[' && p[i] != '.') i++;
return i;
} }
#undef BASE64_OUT struct json_token *find_json_token(struct json_token *toks, const char *path) {
#undef BASE64_FLUSH 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 */ int json_emit_long(char *buf, int buf_len, long int value) {
static unsigned char from_b64(unsigned char ch) { char tmp[20];
/* Inverse lookup map */ int n = snprintf(tmp, sizeof(tmp), "%ld", value);
static const unsigned char tab[128] = { strncpy(buf, tmp, buf_len > 0 ? buf_len : 0);
255, 255, 255, 255, return n;
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 cs_base64_decode(const unsigned char *s, int len, char *dst) { int json_emit_double(char *buf, int buf_len, double value) {
unsigned char a, b, c, d; char tmp[20];
int orig_len = len; int n = snprintf(tmp, sizeof(tmp), "%g", value);
while (len >= 4 && (a = from_b64(s[0])) != 255 && strncpy(buf, tmp, buf_len > 0 ? buf_len : 0);
(b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 && return n;
(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 */ int json_emit_quoted_str(char *s, int s_len, const char *str, int len) {
#ifdef NS_MODULE_LINES const char *begin = s, *end = s + s_len, *str_end = str + len;
#line 1 "src/../../common/str_util.c" char ch;
/**/
#endif
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*/
#ifndef EXCLUDE_COMMON #define EMIT(x) do { if (s < end) *s = x; s++; } while (0)
/* Amalgamated: #include "osdep.h" */ EMIT('"');
/* Amalgamated: #include "str_util.h" */ 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) && \ return s - begin;
!(__DARWIN_C_LEVEL >= 200809L) && !defined(RTOS_SDK) || \ }
defined(_WIN32)
size_t strnlen(const char *s, size_t maxlen) { int json_emit_unquoted_str(char *buf, int buf_len, const char *str, int len) {
size_t l = 0; if (buf_len > 0 && len > 0) {
for (; l < maxlen && s[l] != '\0'; l++) { 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) \ int json_emit_va(char *s, int s_len, const char *fmt, va_list ap) {
do { \ const char *end = s + s_len, *str, *orig = s;
if (i < (int) buf_size) buf[i] = ch; \ size_t len;
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(' ');
}
/* Ignore negative and 0 precisions */ while (*fmt != '\0') {
for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) { switch (*fmt) {
C_SNPRINTF_APPEND_CHAR(s[j]); case '[': case ']': case '{': case '}': case ',': case ':':
case ' ': case '\r': case '\n': case '\t':
if (s < end) {
*s = *fmt;
} }
} else if (ch == 'c') { s++;
ch = va_arg(ap, int); /* Always fetch parameter */ break;
C_SNPRINTF_APPEND_CHAR(ch); case 'i':
} else if (ch == 'd' && len_mod == 0) { s += json_emit_long(s, end - s, va_arg(ap, long));
i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags, break;
field_width); case 'f':
} else if (ch == 'd' && len_mod == 'l') { s += json_emit_double(s, end - s, va_arg(ap, double));
i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags, break;
field_width); case 'v':
} else if ((ch == 'x' || ch == 'u') && len_mod == 0) { str = va_arg(ap, char *);
i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned), len = va_arg(ap, size_t);
ch == 'x' ? 16 : 10, flags, field_width); s += json_emit_quoted_str(s, end - s, str, len);
} else if ((ch == 'x' || ch == 'u') && len_mod == 'l') { break;
i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long), case 'V':
ch == 'x' ? 16 : 10, flags, field_width); str = va_arg(ap, char *);
} else if (ch == 'p') { len = va_arg(ap, size_t);
unsigned long num = (unsigned long) va_arg(ap, void *); s += json_emit_unquoted_str(s, end - s, str, len);
C_SNPRINTF_APPEND_CHAR('0'); break;
C_SNPRINTF_APPEND_CHAR('x'); case 's':
i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0); str = va_arg(ap, char *);
} else { s += json_emit_quoted_str(s, end - s, str, strlen(str));
#ifndef NO_LIBC break;
/* case 'S':
* TODO(lsm): abort is not nice in a library, remove it str = va_arg(ap, char *);
* Also, ESP8266 SDK doesn't have it s += json_emit_unquoted_str(s, end - s, str, strlen(str));
*/ break;
abort(); case 'T':
#endif 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 */ /* Best-effort to 0-terminate generated string */
if (buf_size > 0) { if (s < end) {
buf[i < (int) buf_size ? i : (int) buf_size - 1] = '\0'; *s = '\0';
} }
return i; return s - orig;
} }
#endif
int c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) { int json_emit(char *buf, int buf_len, const char *fmt, ...) {
int result; int len;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
result = c_vsnprintf(buf, buf_size, fmt, ap); len = json_emit_va(buf, buf_len, fmt, ap);
va_end(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)); return len;
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 #ifdef NS_MODULE_LINES
#line 1 "src/../../common/dirent.c" #line 1 "src/../../common/md5.c"
/**/ /**/
#endif #endif
/* /*
* Copyright (c) 2015 Cesanta Software Limited * This code implements the MD5 message-digest algorithm.
* All rights reserved * 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 * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* for systems which do not natively support it (e.g. Windows). * 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 ctx->bits[0] = 0;
#define MG_FREE free ctx->bits[1] = 0;
#endif }
#ifndef MG_MALLOC static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
#define MG_MALLOC malloc register uint32_t a, b, c, d;
#endif
#ifdef _WIN32 a = buf[0];
DIR *opendir(const char *name) { b = buf[1];
DIR *dir = NULL; c = buf[2];
wchar_t wpath[MAX_PATH]; d = buf[3];
DWORD attrs;
if (name == NULL) { MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
SetLastError(ERROR_BAD_ARGUMENTS); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
} else if ((dir = (DIR *) MG_MALLOC(sizeof(*dir))) == NULL) { MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
SetLastError(ERROR_NOT_ENOUGH_MEMORY); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
} else { MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
to_wchar(name, wpath, ARRAY_SIZE(wpath)); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
attrs = GetFileAttributesW(wpath); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
if (attrs != 0xFFFFFFFF && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
(void) wcscat(wpath, L"\\*"); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
dir->handle = FindFirstFileW(wpath, &dir->info); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
dir->result.d_name[0] = '\0'; MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
} else { MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MG_FREE(dir); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
dir = NULL; 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) { MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
int result = 0; 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) { MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
if (dir->handle != INVALID_HANDLE_VALUE) MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
result = FindClose(dir->handle) ? 0 : -1; MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MG_FREE(dir); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
} else { MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
result = -1; MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
SetLastError(ERROR_BAD_ARGUMENTS); 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) { void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, size_t len) {
struct dirent *result = 0; uint32_t t;
if (dir) { t = ctx->bits[0];
if (dir->handle != INVALID_HANDLE_VALUE) { if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) ctx->bits[1]++;
result = &dir->result; ctx->bits[1] += (uint32_t) len >> 29;
(void) WideCharToMultiByte(CP_UTF8, 0, dir->info.cFileName, -1,
result->d_name, sizeof(result->d_name), NULL,
NULL);
if (!FindNextFileW(dir->handle, &dir->info)) { t = (t >> 3) & 0x3f;
(void) FindClose(dir->handle);
dir->handle = INVALID_HANDLE_VALUE;
}
} else { if (t) {
SetLastError(ERROR_FILE_NOT_FOUND); unsigned char *p = (unsigned char *) ctx->in + t;
t = 64 - t;
if (len < t) {
memcpy(p, buf, len);
return;
} }
} else { memcpy(p, buf, t);
SetLastError(ERROR_BAD_ARGUMENTS); byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
buf += t;
len -= t;
} }
return result; while (len >= 64) {
} memcpy(ctx->in, buf, 64);
#endif byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (uint32_t *) ctx->in);
#endif /* EXCLUDE_COMMON */ buf += 64;
#ifdef NS_MODULE_LINES len -= 64;
#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>.
*/
#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005+ */ memcpy(ctx->in, buf, len);
}
#include <stdio.h> void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) {
#include <stdlib.h> unsigned count;
#include <string.h> unsigned char *p;
#include <stdarg.h> uint32_t *a;
/* Amalgamated: #include "frozen.h" */
#ifdef _WIN32 count = (ctx->bits[0] >> 3) & 0x3F;
#define snprintf _snprintf
#endif
#ifndef FROZEN_REALLOC p = ctx->in + count;
#define FROZEN_REALLOC realloc *p++ = 0x80;
#endif count = 64 - 1 - count;
if (count < 8) {
#ifndef FROZEN_FREE memset(p, 0, count);
#define FROZEN_FREE free byteReverse(ctx->in, 16);
#endif MD5Transform(ctx->buf, (uint32_t *) ctx->in);
memset(ctx->in, 0, 56);
} else {
memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
struct frozen { a = (uint32_t *) ctx->in;
const char *end; a[14] = ctx->bits[0];
const char *cur; a[15] = ctx->bits[1];
struct json_token *tokens;
int max_tokens;
int num_tokens;
int do_realloc;
};
static int parse_object(struct frozen *f); MD5Transform(ctx->buf, (uint32_t *) ctx->in);
static int parse_value(struct frozen *f); 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) * Stringify binary data. Output buffer size must be 2 * size_of_input + 1
#define END_OF_STRING (-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) { for (; len--; p++) {
return f->end - f->cur; *to++ = hex[p[0] >> 4];
*to++ = hex[p[0] & 0x0f];
}
*to = '\0';
} }
static int is_space(int ch) { char *cs_md5(char buf[33], ...) {
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; unsigned char hash[16];
} const unsigned char *p;
va_list ap;
MD5_CTX ctx;
static void skip_whitespaces(struct frozen *f) { MD5_Init(&ctx);
while (f->cur < f->end && is_space(*f->cur)) f->cur++;
}
static int cur(struct frozen *f) { va_start(ap, buf);
skip_whitespaces(f); while ((p = va_arg(ap, const unsigned char *) ) != NULL) {
return f->cur >= f->end ? END_OF_STRING : * (unsigned char *) f->cur; 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) { MD5_Final(hash, &ctx);
int ch = cur(f); cs_to_hex(buf, hash, sizeof(hash));
if (ch == expected) { f->cur++; return 0; }
return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID;
}
static int is_alpha(int ch) { return buf;
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
} }
static int is_digit(int ch) { #endif /* EXCLUDE_COMMON */
return ch >= '0' && ch <= '9'; #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) { #ifndef EXCLUDE_COMMON
return is_digit(ch) || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
#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) { void mbuf_free(struct mbuf *mbuf) {
switch (*s) { if (mbuf->buf != NULL) {
case 'u': MBUF_FREE(mbuf->buf);
return len < 6 ? JSON_STRING_INCOMPLETE : mbuf_init(mbuf, 0);
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;
} }
} }
static int capture_ptr(struct frozen *f, const char *ptr, enum json_type type) { void mbuf_resize(struct mbuf *a, size_t new_size) {
if (f->do_realloc && f->num_tokens >= f->max_tokens) { if (new_size > a->size || (new_size < a->size && new_size >= a->len)) {
int new_size = f->max_tokens == 0 ? 100 : f->max_tokens * 2; char *buf = (char *) MBUF_REALLOC(a->buf, new_size);
void *p = FROZEN_REALLOC(f->tokens, new_size * sizeof(f->tokens[0])); /*
if (p == NULL) return JSON_TOKEN_ARRAY_TOO_SMALL; * In case realloc fails, there's not much we can do, except keep things as
f->max_tokens = new_size; * they are. Note that NULL is a valid return value from realloc when
f->tokens = (struct json_token *) p; * 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) { void mbuf_trim(struct mbuf *mbuf) {
if (f->tokens == 0 || f->max_tokens == 0) return 0; mbuf_resize(mbuf, mbuf->len);
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;
} }
/* identifier = letter { letter | digit | '_' } */ size_t mbuf_insert(struct mbuf *a, size_t off, const void *buf, size_t len) {
static int parse_identifier(struct frozen *f) { char *p = NULL;
EXPECT(is_alpha(cur(f)), JSON_STRING_INVALID);
TRY(capture_ptr(f, f->cur, JSON_TYPE_STRING)); assert(a != NULL);
while (f->cur < f->end && assert(a->len <= a->size);
(*f->cur == '_' || is_alpha(*f->cur) || is_digit(*f->cur))) { assert(off <= a->len);
f->cur++;
/* 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) { size_t mbuf_append(struct mbuf *a, const void *buf, size_t len) {
if ((ch & 0x80) == 0) return 1; return mbuf_insert(a, a->len, buf, len);
switch (ch & 0xf0) {
case 0xf0: return 4;
case 0xe0: return 3;
default: return 2;
}
} }
/* string = '"' { quoted_printable_chars } '"' */ void mbuf_remove(struct mbuf *mb, size_t n) {
static int parse_string(struct frozen *f) { if (n > 0 && n <= mb->len) {
int n, ch = 0, len = 0; memmove(mb->buf, mb->buf + n, mb->len - n);
TRY(test_and_skip(f, '"')); mb->len -= n;
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;
} }
/* number = [ '-' ] digit+ [ '.' digit+ ] [ ['e'|'E'] ['+'|'-'] digit+ ] */ #endif /* EXCLUDE_COMMON */
static int parse_number(struct frozen *f) { #ifdef NS_MODULE_LINES
int ch = cur(f); #line 1 "src/../../common/sha1.c"
TRY(capture_ptr(f, f->cur, JSON_TYPE_NUMBER)); /**/
if (ch == '-') f->cur++; #endif
EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); /* Copyright(c) By Steve Reid <steve@edmweb.com> */
EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); /* 100% Public Domain */
while (f->cur < f->end && is_digit(f->cur[0])) f->cur++;
if (f->cur < f->end && f->cur[0] == '.') { #if !defined(DISABLE_SHA1) && !defined(EXCLUDE_COMMON)
f->cur++;
EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); /* Amalgamated: #include "sha1.h" */
EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID);
while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; #define SHA1HANDSOFF
} #if defined(__sun)
if (f->cur < f->end && (f->cur[0] == 'e' || f->cur[0] == 'E')) { /* Amalgamated: #include "solarisfixes.h" */
f->cur++; #endif
EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE);
if ((f->cur[0] == '+' || f->cur[0] == '-')) f->cur++; union char64long16 {
EXPECT(f->cur < f->end, JSON_STRING_INCOMPLETE); unsigned char c[64];
EXPECT(is_digit(f->cur[0]), JSON_STRING_INVALID); uint32_t l[16];
while (f->cur < f->end && is_digit(f->cur[0])) f->cur++; };
}
capture_len(f, f->num_tokens - 1, f->cur); #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
return 0;
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 } ] ']' */ /* Avoid redefine warning (ARM /usr/include/sys/ucontext.h define R0~R4) */
static int parse_array(struct frozen *f) { #undef blk
int ind; #undef R0
TRY(test_and_skip(f, '[')); #undef R1
TRY(capture_ptr(f, f->cur - 1, JSON_TYPE_ARRAY)); #undef R2
ind = f->num_tokens - 1; #undef R3
while (cur(f) != ']') { #undef R4
TRY(parse_value(f));
if (cur(f) == ',') f->cur++; #define blk(i) \
} (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ \
TRY(test_and_skip(f, ']')); block->l[(i + 2) & 15] ^ block->l[i & 15], \
capture_len(f, ind, f->cur); 1))
return 0; #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) { void cs_sha1_init(cs_sha1_ctx *context) {
int i = 0; context->state[0] = 0x67452301;
while (i < len && s[i] == str[i]) i++; context->state[1] = 0xEFCDAB89;
return i == len ? 1 : 0; 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) { void cs_sha1_update(cs_sha1_ctx *context, const unsigned char *data, uint32_t len) {
int i, n = left(f); uint32_t i, j;
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));
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 */ void cs_sha1_final(unsigned char digest[20], cs_sha1_ctx *context) {
static int parse_value(struct frozen *f) { unsigned i;
int ch = cur(f); unsigned char finalcount[8], c;
switch (ch) { for (i = 0; i < 8; i++) {
case '"': TRY(parse_string(f)); break; finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >>
case '{': TRY(parse_object(f)); break; ((3 - (i & 3)) * 8)) &
case '[': TRY(parse_array(f)); break; 255);
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;
} }
c = 0200;
return 0; 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 */ void cs_hmac_sha1(const unsigned char *key, size_t keylen,
static int parse_key(struct frozen *f) { const unsigned char *data, size_t datalen,
int ch = cur(f); unsigned char out[20]) {
#if 0 cs_sha1_ctx ctx;
printf("%s 1 [%.*s]\n", __func__, (int) (f->end - f->cur), f->cur); unsigned char buf1[64], buf2[64], tmp_key[20], i;
#endif
if (is_alpha(ch)) { if (keylen > sizeof(buf1)) {
TRY(parse_identifier(f)); cs_sha1_init(&ctx);
} else if (ch == '"') { cs_sha1_update(&ctx, key, keylen);
TRY(parse_string(f)); cs_sha1_final(tmp_key, &ctx);
} else { key = tmp_key;
return ch == END_OF_STRING ? JSON_STRING_INCOMPLETE : JSON_STRING_INVALID; keylen = sizeof(tmp_key);
} }
return 0;
}
/* pair = key ':' value */ memset(buf1, 0, sizeof(buf1));
static int parse_pair(struct frozen *f) { memset(buf2, 0, sizeof(buf2));
TRY(parse_key(f)); memcpy(buf1, key, keylen);
TRY(test_and_skip(f, ':')); memcpy(buf2, key, keylen);
TRY(parse_value(f));
return 0;
}
/* object = '{' pair { ',' pair } '}' */ for (i = 0; i < sizeof(buf1); i++) {
static int parse_object(struct frozen *f) { buf1[i] ^= 0x36;
int ind; buf2[i] ^= 0x5c;
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;
}
static int doit(struct frozen *f) { cs_sha1_init(&ctx);
if (f->cur == 0 || f->end < f->cur) return JSON_STRING_INVALID; cs_sha1_update(&ctx, buf1, sizeof(buf1));
if (f->end == f->cur) return JSON_STRING_INCOMPLETE; cs_sha1_update(&ctx, data, datalen);
TRY(parse_object(f)); cs_sha1_final(out, &ctx);
TRY(capture_ptr(f, f->cur, JSON_TYPE_EOF));
capture_len(f, f->num_tokens, f->cur); cs_sha1_init(&ctx);
return 0; cs_sha1_update(&ctx, buf2, sizeof(buf2));
cs_sha1_update(&ctx, out, 20);
cs_sha1_final(out, &ctx);
} }
/* json = object */ #endif /* EXCLUDE_COMMON */
int parse_json(const char *s, int s_len, struct json_token *arr, int arr_len) { #ifdef NS_MODULE_LINES
struct frozen frozen; #line 1 "src/../../common/str_util.c"
/**/
#endif
/*
* Copyright (c) 2015 Cesanta Software Limited
* All rights reserved
*/
memset(&frozen, 0, sizeof(frozen)); #ifndef EXCLUDE_COMMON
frozen.end = s + s_len;
frozen.cur = s;
frozen.tokens = arr;
frozen.max_tokens = arr_len;
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) { #define C_SNPRINTF_APPEND_CHAR(ch) \
struct frozen frozen; do { \
if (i < (int) buf_size) buf[i] = ch; \
i++; \
} while (0)
memset(&frozen, 0, sizeof(frozen)); #define C_SNPRINTF_FLAG_ZERO 1
frozen.end = s + s_len;
frozen.cur = s;
frozen.do_realloc = 1;
if (doit(&frozen) < 0) { #ifdef C_DISABLE_BUILTIN_SNPRINTF
FROZEN_FREE((void *) frozen.tokens); int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
frozen.tokens = NULL; return vsnprintf(buf, buf_size, fmt, ap);
}
return frozen.tokens;
} }
#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) { if (num < 0) {
int i = 0; neg++;
while (p[i] != '\0' && p[i] != '[' && p[i] != '.') i++; num = -num;
return i; }
}
struct json_token *find_json_token(struct json_token *toks, const char *path) { /* Print into temporary buffer - in reverse order */
while (path != 0 && path[0] != '\0') { do {
int i, ind2 = 0, ind = -1, skip = 2, n = path_part_len(path); int rem = num % base;
if (path[0] == '[') { if (rem < 10) {
if (toks->type != JSON_TYPE_ARRAY || !is_digit(path[1])) return 0; tmp[k++] = '0' + rem;
for (ind = 0, n = 1; path[n] != ']' && path[n] != '\0'; n++) { } else {
if (!is_digit(path[n])) return 0; tmp[k++] = 'a' + (rem - 10);
ind *= 10; }
ind += path[n] - '0'; num /= base;
} } while (num > 0);
if (path[n++] != ']') return 0;
skip = 1; /* In objects, we skip 2 elems while iterating, in arrays 1. */ /* Zero padding */
} else if (toks->type != JSON_TYPE_OBJECT) return 0; if (flags && C_SNPRINTF_FLAG_ZERO) {
toks++; while (k < field_width && k < (int) sizeof(tmp) - 1) {
for (i = 0; i < toks[-1].num_desc; i += skip, ind2++) { tmp[k++] = '0';
/* 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;
}
int json_emit_long(char *buf, int buf_len, long int value) { /* And sign */
char tmp[20]; if (neg) {
int n = snprintf(tmp, sizeof(tmp), "%ld", value); tmp[k++] = '-';
strncpy(buf, tmp, buf_len > 0 ? buf_len : 0); }
return n;
}
int json_emit_double(char *buf, int buf_len, double value) { /* Now output */
char tmp[20]; while (--k >= 0) {
int n = snprintf(tmp, sizeof(tmp), "%g", value); C_SNPRINTF_APPEND_CHAR(tmp[k]);
strncpy(buf, tmp, buf_len > 0 ? buf_len : 0); }
return n;
return i;
} }
int json_emit_quoted_str(char *s, int s_len, const char *str, int len) { int c_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list ap) {
const char *begin = s, *end = s + s_len, *str_end = str + len; int ch, i = 0, len_mod, flags, precision, field_width;
char ch;
#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('"'); /* Flags. only zero-pad flag is supported. */
while (str < str_end) { if (*fmt == '0') {
ch = *str++; flags |= C_SNPRINTF_FLAG_ZERO;
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';
}
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) { /* Precision */
if (buf_len > 0 && len > 0) { if (*fmt == '.') {
int n = len < buf_len ? len : buf_len; fmt++;
memcpy(buf, str, n); if (*fmt == '*') {
if (n < buf_len) { precision = va_arg(ap, int);
buf[n] = '\0'; fmt++;
} } else {
} while (*fmt >= '0' && *fmt <= '9') {
return len; precision *= 10;
} precision += *fmt++ - '0';
}
}
}
int json_emit_va(char *s, int s_len, const char *fmt, va_list ap) { /* Length modifier */
const char *end = s + s_len, *str, *orig = s; switch (*fmt) {
size_t len; 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') { ch = *fmt++;
switch (*fmt) { if (ch == 's') {
case '[': case ']': case '{': case '}': case ',': case ':': const char *s = va_arg(ap, const char *); /* Always fetch parameter */
case ' ': case '\r': case '\n': case '\t': int j;
if (s < end) { int pad = field_width - (precision >= 0 ? strnlen(s, precision) : 0);
*s = *fmt; for (j = 0; j < pad; j++) {
C_SNPRINTF_APPEND_CHAR(' ');
} }
s++;
break; /* Ignore negative and 0 precisions */
case 'i': for (j = 0; (precision <= 0 || j < precision) && s[j] != '\0'; j++) {
s += json_emit_long(s, end - s, va_arg(ap, long)); C_SNPRINTF_APPEND_CHAR(s[j]);
break; }
case 'f': } else if (ch == 'c') {
s += json_emit_double(s, end - s, va_arg(ap, double)); ch = va_arg(ap, int); /* Always fetch parameter */
break; C_SNPRINTF_APPEND_CHAR(ch);
case 'v': } else if (ch == 'd' && len_mod == 0) {
str = va_arg(ap, char *); i += c_itoa(buf + i, buf_size - i, va_arg(ap, int), 10, flags,
len = va_arg(ap, size_t); field_width);
s += json_emit_quoted_str(s, end - s, str, len); } else if (ch == 'd' && len_mod == 'l') {
break; i += c_itoa(buf + i, buf_size - i, va_arg(ap, long), 10, flags,
case 'V': field_width);
str = va_arg(ap, char *); } else if ((ch == 'x' || ch == 'u') && len_mod == 0) {
len = va_arg(ap, size_t); i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned),
s += json_emit_unquoted_str(s, end - s, str, len); ch == 'x' ? 16 : 10, flags, field_width);
break; } else if ((ch == 'x' || ch == 'u') && len_mod == 'l') {
case 's': i += c_itoa(buf + i, buf_size - i, va_arg(ap, unsigned long),
str = va_arg(ap, char *); ch == 'x' ? 16 : 10, flags, field_width);
s += json_emit_quoted_str(s, end - s, str, strlen(str)); } else if (ch == 'p') {
break; unsigned long num = (unsigned long) va_arg(ap, void *);
case 'S': C_SNPRINTF_APPEND_CHAR('0');
str = va_arg(ap, char *); C_SNPRINTF_APPEND_CHAR('x');
s += json_emit_unquoted_str(s, end - s, str, strlen(str)); i += c_itoa(buf + i, buf_size - i, num, 16, flags, 0);
break; } else {
case 'T': #ifndef NO_LIBC
s += json_emit_unquoted_str(s, end - s, "true", 4); /*
break; * TODO(lsm): abort is not nice in a library, remove it
case 'F': * Also, ESP8266 SDK doesn't have it
s += json_emit_unquoted_str(s, end - s, "false", 5); */
break; abort();
case 'N': #endif
s += json_emit_unquoted_str(s, end - s, "null", 4); }
break;
default:
return 0;
} }
fmt++;
} }
/* Best-effort to 0-terminate generated string */ /* Zero-terminate the result */
if (s < end) { if (buf_size > 0) {
*s = '\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 c_snprintf(char *buf, size_t buf_size, const char *fmt, ...) {
int len; int result;
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
len = json_emit_va(buf, buf_len, fmt, ap); result = c_vsnprintf(buf, buf_size, fmt, ap);
va_end(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 #ifdef NS_MODULE_LINES
#line 1 "src/net.c" #line 1 "src/net.c"
/**/ /**/
......
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
#ifdef MG_LOCALS #ifdef MG_LOCALS
#include <mg_locals.h> #include <mg_locals.h>
#endif #endif
#if defined(MG_ENABLE_DEBUG) && !defined(CS_ENABLE_DEBUG)
#define CS_ENABLE_DEBUG
#endif
/* /*
* Copyright (c) 2015 Cesanta Software Limited * Copyright (c) 2015 Cesanta Software Limited
* All rights reserved * All rights reserved
...@@ -260,25 +264,31 @@ int64_t strtoll(const char *str, char **endptr, int base); ...@@ -260,25 +264,31 @@ int64_t strtoll(const char *str, char **endptr, int base);
#endif #endif
#endif /* !_WIN32 */ #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 { \ do { \
printf("%-20s ", __func__); \ fprintf(stderr, "%-20s ", __func__); \
printf x; \ cs_dbg_printf x; \
putchar('\n'); \
fflush(stdout); \
} while (0) } while (0)
#ifdef MG_ENABLE_DEBUG
#define DBG __DBG #define DBG __DBG
#else #else
#define DBG(x) #define DBG(x)
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#endif #endif
#endif /* OSDEP_HEADER_INCLUDED */ #endif /* _CS_DBG_H_ */
/* /*
* Copyright (c) 2015 Cesanta Software Limited * Copyright (c) 2015 Cesanta Software Limited
* All rights reserved * All rights reserved
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment