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);
#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"
/**/
......
......@@ -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
......
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