199 lines
4.9 KiB
C
199 lines
4.9 KiB
C
#include "proto.h"
|
||
#include <string.h>
|
||
|
||
const char *proto_locate(const char *json, const char *key)
|
||
{
|
||
char pat[24];
|
||
int klen = (int)strlen(key);
|
||
const char *p = json;
|
||
|
||
if (klen <= 0 || klen + 3 > (int)sizeof(pat)) return 0;
|
||
pat[0] = '"';
|
||
memcpy(pat + 1, key, klen);
|
||
pat[klen + 1] = '"';
|
||
pat[klen + 2] = '\0';
|
||
|
||
while ((p = strstr(p, pat)) != 0) {
|
||
const char *q = p + klen + 2;
|
||
while (*q == ' ' || *q == '\t') q++;
|
||
if (*q == ':') {
|
||
q++;
|
||
while (*q == ' ' || *q == '\t') q++;
|
||
return q;
|
||
}
|
||
/* 命中的是字符串值里的子串而非键名,继续向后找 */
|
||
p += 2;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 提取 key 的值区域到 buf(带花括号深度跟踪,嵌套对象整体取出)。
|
||
* 成功返回 1,失败返回 0。 */
|
||
static int proto_value_region(const char *json, const char *key, char *buf, int cap)
|
||
{
|
||
const char *p = proto_locate(json, key);
|
||
int i = 0;
|
||
int depth = 0;
|
||
|
||
if (!p) return 0;
|
||
while (p[i] && i < cap - 1) {
|
||
char c = p[i];
|
||
if (c == '{') {
|
||
depth++;
|
||
} else if (c == '}') {
|
||
if (depth == 0) break; /* 不属于本值的右括号 */
|
||
depth--;
|
||
if (depth == 0) { i++; break; } /* 嵌套对象结束 */
|
||
} else if (c == ',' && depth == 0) {
|
||
break; /* 顶层下一个字段 */
|
||
}
|
||
buf[i] = c;
|
||
i++;
|
||
}
|
||
buf[i] = '\0';
|
||
return 1;
|
||
}
|
||
|
||
int proto_get_bool(const char *json, const char *key, int *val)
|
||
{
|
||
char region[96];
|
||
char *q;
|
||
int len;
|
||
|
||
if (!proto_value_region(json, key, region, sizeof(region))) return 0;
|
||
len = (int)strlen(region);
|
||
|
||
/* 在值区域内找最先出现的 true/false 令牌(排除键名里的子串) */
|
||
for (q = region; q < region + len; q++) {
|
||
if (q + 4 <= region + len && strncmp(q, "true", 4) == 0 && (q == region || q[-1] != '"')) {
|
||
*val = 1;
|
||
return 1;
|
||
}
|
||
if (q + 5 <= region + len && strncmp(q, "false", 5) == 0 && (q == region || q[-1] != '"')) {
|
||
*val = 0;
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
/* 兼容 0/1 */
|
||
if (region[0] == '0' || region[0] == '1') {
|
||
*val = region[0] - '0';
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int proto_get_u32(const char *json, const char *key, uint32_t *val)
|
||
{
|
||
const char *p = proto_locate(json, key);
|
||
uint32_t v = 0;
|
||
|
||
if (!p || *p < '0' || *p > '9') return 0;
|
||
while (*p >= '0' && *p <= '9') {
|
||
v = v * 10 + (uint32_t)(*p - '0');
|
||
p++;
|
||
}
|
||
*val = v;
|
||
return 1;
|
||
}
|
||
|
||
int proto_get_hex16(const char *json, const char *key, uint16_t *val)
|
||
{
|
||
const char *p = proto_locate(json, key);
|
||
uint16_t v = 0;
|
||
int n = 0;
|
||
|
||
if (!p) return 0;
|
||
if (*p == '"') p++;
|
||
while (n < 4) {
|
||
char c = *p;
|
||
uint8_t d;
|
||
if (c >= '0' && c <= '9') d = (uint8_t)(c - '0');
|
||
else if (c >= 'a' && c <= 'f') d = (uint8_t)(c - 'a' + 10);
|
||
else if (c >= 'A' && c <= 'F') d = (uint8_t)(c - 'A' + 10);
|
||
else break;
|
||
v = (uint16_t)((v << 4) | d);
|
||
p++;
|
||
n++;
|
||
}
|
||
if (n == 0) return 0;
|
||
*val = v;
|
||
return 1;
|
||
}
|
||
|
||
int proto_get_str(const char *json, const char *key, char *out, int cap)
|
||
{
|
||
const char *p = proto_locate(json, key);
|
||
int i = 0;
|
||
|
||
if (!p || *p != '"' || cap <= 0) return 0;
|
||
p++;
|
||
while (p[i] && p[i] != '"' && i < cap - 1) {
|
||
out[i] = p[i];
|
||
i++;
|
||
}
|
||
out[i] = '\0';
|
||
return (i > 0) ? 1 : 0;
|
||
}
|
||
|
||
int proto_get_id(const char *json, char *out, int cap)
|
||
{
|
||
const char *p = proto_locate(json, "id");
|
||
int i = 0;
|
||
|
||
if (!p || cap <= 0) return 0;
|
||
if (*p == '"') {
|
||
p++;
|
||
while (i < cap - 1 &&
|
||
((p[i] >= '0' && p[i] <= '9') ||
|
||
(p[i] >= 'a' && p[i] <= 'z') ||
|
||
(p[i] >= 'A' && p[i] <= 'Z'))) {
|
||
out[i] = p[i];
|
||
i++;
|
||
}
|
||
} else {
|
||
while (i < cap - 1 && p[i] >= '0' && p[i] <= '9') {
|
||
out[i] = p[i];
|
||
i++;
|
||
}
|
||
}
|
||
out[i] = '\0';
|
||
return (i > 0) ? 1 : 0;
|
||
}
|
||
|
||
int proto_get_kg100(const char *json, const char *key, uint16_t *val)
|
||
{
|
||
char region[64];
|
||
const char *p;
|
||
const char *vp;
|
||
uint16_t v = 0;
|
||
|
||
if (!proto_value_region(json, key, region, sizeof(region))) return 0;
|
||
|
||
/* 嵌套对象时取 "value" 字段,否则直接用区域本身 */
|
||
vp = proto_locate(region, "value");
|
||
p = vp ? vp : region;
|
||
|
||
/* 跳过空白、引号、冒号 */
|
||
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == '"' || *p == ':') p++;
|
||
if (*p < '0' || *p > '9') return 0;
|
||
|
||
while (*p >= '0' && *p <= '9') {
|
||
v = (uint16_t)(v * 10 + (*p - '0'));
|
||
p++;
|
||
}
|
||
if (*p == '.') {
|
||
p++;
|
||
if (*p >= '0' && *p <= '9') {
|
||
v = (uint16_t)(v * 10 + (*p - '0'));
|
||
} else {
|
||
v = (uint16_t)(v * 10); /* 整数补一位小数 */
|
||
}
|
||
/* 忽略第二位小数 */
|
||
} else {
|
||
v = (uint16_t)(v * 10); /* 整数转 0.1KG */
|
||
}
|
||
*val = v;
|
||
return 1;
|
||
}
|