/*
- * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2023-2024 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
#include "internal/json_enc.h"
#include "internal/nelem.h"
+#include "internal/numbers.h"
#include <string.h>
#include <math.h>
* wbuf
* ====
*/
-static int wbuf_flush(struct json_write_buf *wbuf);
+static int wbuf_flush(struct json_write_buf *wbuf, int full);
static int wbuf_init(struct json_write_buf *wbuf, BIO *bio, size_t alloc)
{
static ossl_inline int wbuf_write_char(struct json_write_buf *wbuf, char c)
{
if (wbuf_avail(wbuf) == 0) {
- if (!wbuf_flush(wbuf))
+ if (!wbuf_flush(wbuf, /*full=*/0))
return 0;
}
}
/* Flush write buffer, returning 0 on I/O failure. */
-static int wbuf_flush(struct json_write_buf *wbuf)
+static int wbuf_flush(struct json_write_buf *wbuf, int full)
{
size_t written = 0, total_written = 0;
}
wbuf->cur = 0;
+
+ if (full)
+ (void)BIO_flush(wbuf->bio); /* best effort */
+
return 1;
}
int ossl_json_flush(OSSL_JSON_ENC *json)
{
- return wbuf_flush(&json->wbuf);
+ return wbuf_flush(&json->wbuf, /*full=*/1);
}
int ossl_json_set0_sink(OSSL_JSON_ENC *json, BIO *bio)
if (!json_pre_item(json))
return;
- if (isnan(value) || isinf(value)) {
- json_raise_error(json);
- return;
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+ {
+ int checks = isnan(value);
+# if !defined(OPENSSL_SYS_VMS)
+ checks |= isinf(value);
+# endif
+
+ if (checks) {
+ json_raise_error(json);
+ return;
+ }
}
+#endif
BIO_snprintf(buf, sizeof(buf), "%1.17g", value);
json_write_str(json, buf);
int nul_term)
{
char c, *o, obuf[7];
+ unsigned char *u_str;
int i;
size_t j;
json_write_char(json, '"');
- for (j = 0; (nul_term && *str != '\0')
- || (!nul_term && j < str_len); ++str, ++j) {
+ for (j = nul_term ? strlen(str) : str_len; j > 0; str++, j--) {
c = *str;
+ u_str = (unsigned char*)str;
switch (c) {
case '\n': o = "\\n"; break;
case '\r': o = "\\r"; break;
case '"': o = "\\\""; break;
case '\\': o = "\\\\"; break;
default:
- if ((unsigned char)c >= 0x80) {
- json_raise_error(json);
- return;
+ /* valid UTF-8 sequences according to RFC-3629 */
+ if (u_str[0] >= 0xc2 && u_str[0] <= 0xdf && j >= 2
+ && u_str[1] >= 0x80 && u_str[1] <= 0xbf) {
+ memcpy(obuf, str, 2);
+ obuf[2] = '\0';
+ str++, j--;
+ o = obuf;
+ break;
+ }
+ if (u_str[0] >= 0xe0 && u_str[0] <= 0xef && j >= 3
+ && u_str[1] >= 0x80 && u_str[1] <= 0xbf
+ && u_str[2] >= 0x80 && u_str[2] <= 0xbf
+ && !(u_str[0] == 0xe0 && u_str[1] <= 0x9f)
+ && !(u_str[0] == 0xed && u_str[1] >= 0xa0)) {
+ memcpy(obuf, str, 3);
+ obuf[3] = '\0';
+ str += 2;
+ j -= 2;
+ o = obuf;
+ break;
+ }
+ if (u_str[0] >= 0xf0 && u_str[0] <= 0xf4 && j >= 4
+ && u_str[1] >= 0x80 && u_str[1] <= 0xbf
+ && u_str[2] >= 0x80 && u_str[2] <= 0xbf
+ && u_str[3] >= 0x80 && u_str[3] <= 0xbf
+ && !(u_str[0] == 0xf0 && u_str[1] <= 0x8f)
+ && !(u_str[0] == 0xf4 && u_str[1] >= 0x90)) {
+ memcpy(obuf, str, 4);
+ obuf[4] = '\0';
+ str += 3;
+ j -= 3;
+ o = obuf;
+ break;
}
- if ((unsigned char)c < 0x20 || (unsigned char)c >= 0x7f) {
+ if (u_str[0] < 0x20 || u_str[0] >= 0x7f) {
obuf[0] = '\\';
obuf[1] = 'u';
for (i = 0; i < 4; ++i)
- obuf[2 + i] = hex_digit((c >> ((3 - i) * 4)) & 0x0F);
+ obuf[2 + i] = hex_digit((u_str[0] >> ((3 - i) * 4)) & 0x0F);
obuf[6] = '\0';
o = obuf;
} else {