Skip to content

Commit a3a3334

Browse files
Update jellyfish.c
1 parent 8ab072b commit a3a3334

File tree

1 file changed

+92
-93
lines changed

1 file changed

+92
-93
lines changed

code/logic/jellyfish.c

Lines changed: 92 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,12 @@ void fossil_jellyfish_dump(const fossil_jellyfish_chain *chain) {
168168
}
169169
}
170170

171+
static void skip_whitespace(const char **ptr) {
172+
while (isspace(**ptr)) (*ptr)++;
173+
}
174+
171175
static bool match_key(const char **ptr, const char *key) {
172-
while (**ptr && (**ptr == ' ' || **ptr == '\n' || **ptr == '\r' || **ptr == '\t')) (*ptr)++;
176+
skip_whitespace(ptr);
173177
size_t len = strlen(key);
174178
if (strncmp(*ptr, key, len) == 0) {
175179
*ptr += len;
@@ -178,43 +182,48 @@ static bool match_key(const char **ptr, const char *key) {
178182
return false;
179183
}
180184

181-
static void skip_whitespace(const char **ptr) {
182-
while (**ptr && (**ptr == ' ' || **ptr == '\n' || **ptr == '\r' || **ptr == '\t')) (*ptr)++;
183-
}
184-
185185
static bool parse_string(const char **ptr, char *out, size_t maxlen) {
186186
skip_whitespace(ptr);
187-
if (**ptr != '\"') return false;
187+
if (**ptr != '"') return false;
188188
(*ptr)++;
189189
size_t i = 0;
190-
while (**ptr && **ptr != '\"' && i < maxlen - 1) {
190+
while (**ptr && **ptr != '"' && i < maxlen - 1) {
191+
if (**ptr == '\\') (*ptr)++; // Skip escape char
191192
out[i++] = *(*ptr)++;
192193
}
193-
if (**ptr != '\"') return false;
194+
if (**ptr != '"') return false;
194195
(*ptr)++;
195196
out[i] = '\0';
196197
return true;
197198
}
198199

199-
static bool parse_number(const char **ptr, double *out_double, long *out_long) {
200+
static bool parse_hash(const char **ptr, uint8_t *hash_out) {
201+
char hexstr[FOSSIL_JELLYFISH_HASH_SIZE * 2 + 1] = {0};
202+
if (!parse_string(ptr, hexstr, sizeof(hexstr))) return false;
203+
204+
if (strlen(hexstr) != FOSSIL_JELLYFISH_HASH_SIZE * 2) return false;
205+
206+
for (size_t i = 0; i < FOSSIL_JELLYFISH_HASH_SIZE; ++i) {
207+
char byte[3] = { hexstr[i * 2], hexstr[i * 2 + 1], 0 };
208+
hash_out[i] = (uint8_t)strtoul(byte, NULL, 16);
209+
}
210+
return true;
211+
}
212+
213+
static bool parse_number(const char **ptr, double *out_d, uint64_t *out_u64, int *out_i, uint32_t *out_u32) {
200214
skip_whitespace(ptr);
201215
char buffer[64];
202216
size_t i = 0;
203-
while ((**ptr >= '0' && **ptr <= '9') || **ptr == '.' || **ptr == '-') {
204-
if (i < sizeof(buffer) - 1)
205-
buffer[i++] = *(*ptr)++;
206-
else
207-
return false;
208-
}
217+
while ((isdigit(**ptr) || **ptr == '.' || **ptr == '-') && i < sizeof(buffer) - 1)
218+
buffer[i++] = *(*ptr)++;
209219
buffer[i] = '\0';
210220

211-
if (strchr(buffer, '.')) {
212-
if (out_double) *out_double = atof(buffer);
213-
} else {
214-
if (out_long) *out_long = atol(buffer);
215-
}
221+
if (out_d) *out_d = atof(buffer);
222+
if (out_u64) *out_u64 = strtoull(buffer, NULL, 10);
223+
if (out_i) *out_i = atoi(buffer);
224+
if (out_u32) *out_u32 = (uint32_t)strtoul(buffer, NULL, 10);
216225

217-
return true;
226+
return i > 0;
218227
}
219228

220229
int fossil_jellyfish_load(fossil_jellyfish_chain *chain, const char *filepath) {
@@ -232,131 +241,121 @@ int fossil_jellyfish_load(fossil_jellyfish_chain *chain, const char *filepath) {
232241
}
233242

234243
fread(data, 1, fsize, fp);
235-
fclose(fp);
236244
data[fsize] = '\0';
245+
fclose(fp);
237246

238247
const char *ptr = data;
239248
skip_whitespace(&ptr);
240249

241-
// Look for signature
242-
if (!match_key(&ptr, "{\"signature\":")) {
243-
free(data);
244-
return 0;
245-
}
250+
if (!match_key(&ptr, "{\"signature\":")) { free(data); return 0; }
246251

247252
char sig[8];
248253
if (!parse_string(&ptr, sig, sizeof(sig)) || strcmp(sig, "JFS1") != 0) {
249254
free(data);
250255
return 0;
251256
}
252257

253-
if (!match_key(&ptr, ",\"blocks\":[")) {
254-
free(data);
255-
return 0;
256-
}
258+
if (!match_key(&ptr, ",\"blocks\":[")) { free(data); return 0; }
257259

258260
size_t count = 0;
261+
bool ok = true;
262+
259263
while (*ptr && *ptr != ']') {
260264
if (count >= FOSSIL_JELLYFISH_MAX_MEM) break;
261265

262-
if (!match_key(&ptr, "{")) {
263-
free(data);
264-
return 0;
265-
}
266+
fossil_jellyfish_block *b = &chain->memory[count];
267+
memset(b, 0, sizeof(*b));
266268

267-
fossil_jellyfish_block *block = &chain->memory[count];
268-
memset(block, 0, sizeof(*block));
269+
if (!match_key(&ptr, "{")) { ok = false; break; }
269270

270-
if (!match_key(&ptr, "\"input\":")) {
271-
free(data);
272-
return 0;
273-
}
274-
if (!parse_string(&ptr, block->input, sizeof(block->input))) {
275-
free(data);
276-
return 0;
277-
}
271+
if (!match_key(&ptr, "\"input\":")) { ok = false; break; }
272+
if (!parse_string(&ptr, b->input, sizeof(b->input))) { ok = false; break; }
278273

279-
if (!match_key(&ptr, ",\"output\":")) {
280-
free(data);
281-
return 0;
282-
}
283-
if (!parse_string(&ptr, block->output, sizeof(block->output))) {
284-
free(data);
285-
return 0;
286-
}
274+
if (!match_key(&ptr, ",\"output\":")) { ok = false; break; }
275+
if (!parse_string(&ptr, b->output, sizeof(b->output))) { ok = false; break; }
287276

288-
if (!match_key(&ptr, ",\"timestamp\":")) {
289-
free(data);
290-
return 0;
291-
}
292-
if (!parse_number(&ptr, NULL, &block->timestamp)) {
293-
free(data);
294-
return 0;
295-
}
277+
if (!match_key(&ptr, ",\"hash\":")) { ok = false; break; }
278+
if (!parse_hash(&ptr, b->hash)) { ok = false; break; }
296279

297-
if (!match_key(&ptr, ",\"confidence\":")) {
298-
free(data);
299-
return 0;
300-
}
301-
if (!parse_number(&ptr, &block->confidence, NULL)) {
302-
free(data);
303-
return 0;
304-
}
280+
if (!match_key(&ptr, ",\"timestamp\":")) { ok = false; break; }
281+
if (!parse_number(&ptr, NULL, &b->timestamp, NULL, NULL)) { ok = false; break; }
305282

306-
if (!match_key(&ptr, "}")) {
307-
free(data);
308-
return 0;
309-
}
283+
if (!match_key(&ptr, ",\"valid\":")) { ok = false; break; }
284+
if (!parse_number(&ptr, NULL, NULL, &b->valid, NULL)) { ok = false; break; }
310285

311-
count++;
286+
if (!match_key(&ptr, ",\"confidence\":")) { ok = false; break; }
287+
if (!parse_number(&ptr, &b->confidence, NULL, NULL, NULL)) { ok = false; break; }
288+
289+
if (!match_key(&ptr, ",\"usage_count\":")) { ok = false; break; }
290+
if (!parse_number(&ptr, NULL, NULL, NULL, &b->usage_count)) { ok = false; break; }
291+
292+
if (!match_key(&ptr, "}")) { ok = false; break; }
312293

294+
count++;
313295
skip_whitespace(&ptr);
314296
if (*ptr == ',') ptr++;
315297
}
316298

317-
chain->count = count;
318299
free(data);
319-
return 1;
300+
chain->count = ok ? count : 0;
301+
return ok ? 1 : 0;
302+
}
303+
304+
static void hex_encode(const uint8_t *hash, size_t len, char *out, size_t out_size) {
305+
const char *hex = "0123456789abcdef";
306+
if (out_size < len * 2 + 1) return;
307+
for (size_t i = 0; i < len; ++i) {
308+
out[i * 2] = hex[(hash[i] >> 4) & 0xF];
309+
out[i * 2 + 1] = hex[hash[i] & 0xF];
310+
}
311+
out[len * 2] = '\0';
320312
}
321313

322314
int fossil_jellyfish_save(const fossil_jellyfish_chain *chain, const char *filepath) {
323315
FILE *fp = fopen(filepath, "wb");
324316
if (!fp) return 0;
325317

326-
fprintf(fp, "{\n");
327-
fprintf(fp, " \"signature\": \"JFS1\",\n");
328-
fprintf(fp, " \"blocks\": [\n");
318+
fprintf(fp, "{\n \"signature\": \"JFS1\",\n \"blocks\": [\n");
329319

330320
for (size_t i = 0; i < chain->count; ++i) {
331-
const fossil_jellyfish_block *block = &chain->memory[i];
321+
const fossil_jellyfish_block *b = &chain->memory[i];
322+
323+
// Escape input/output strings (basic)
324+
char input_escaped[FOSSIL_JELLYFISH_INPUT_SIZE * 2] = {0};
325+
char output_escaped[FOSSIL_JELLYFISH_OUTPUT_SIZE * 2] = {0};
332326

333-
// Escape JSON strings (only for quote and backslash for simplicity)
334-
char input_escaped[512] = {0}, output_escaped[512] = {0};
335327
char *dst = input_escaped;
336-
for (const char *src = block->input; *src && (dst - input_escaped) < sizeof(input_escaped) - 2; ++src) {
328+
for (const char *src = b->input; *src && (dst - input_escaped) < sizeof(input_escaped) - 2; ++src) {
337329
if (*src == '"' || *src == '\\') *dst++ = '\\';
338330
*dst++ = *src;
339331
}
340332
*dst = '\0';
341333

342334
dst = output_escaped;
343-
for (const char *src = block->output; *src && (dst - output_escaped) < sizeof(output_escaped) - 2; ++src) {
335+
for (const char *src = b->output; *src && (dst - output_escaped) < sizeof(output_escaped) - 2; ++src) {
344336
if (*src == '"' || *src == '\\') *dst++ = '\\';
345337
*dst++ = *src;
346338
}
347339
*dst = '\0';
348340

349-
fprintf(fp, " {\n");
350-
fprintf(fp, " \"input\": \"%s\",\n", input_escaped);
351-
fprintf(fp, " \"output\": \"%s\",\n", output_escaped);
352-
fprintf(fp, " \"timestamp\": %llu,\n", block->timestamp);
353-
fprintf(fp, " \"confidence\": %.6f\n", block->confidence);
354-
fprintf(fp, " }%s\n", (i < chain->count - 1) ? "," : "");
355-
}
341+
char hash_hex[FOSSIL_JELLYFISH_HASH_SIZE * 2 + 1];
342+
hex_encode(b->hash, FOSSIL_JELLYFISH_HASH_SIZE, hash_hex, sizeof(hash_hex));
356343

357-
fprintf(fp, " ]\n");
358-
fprintf(fp, "}\n");
344+
fprintf(fp,
345+
" {\n"
346+
" \"input\": \"%s\",\n"
347+
" \"output\": \"%s\",\n"
348+
" \"hash\": \"%s\",\n"
349+
" \"timestamp\": %" PRIu64 ",\n"
350+
" \"valid\": %d,\n"
351+
" \"confidence\": %.6f,\n"
352+
" \"usage_count\": %u\n"
353+
" }%s\n",
354+
input_escaped, output_escaped, hash_hex, b->timestamp, b->valid, b->confidence, b->usage_count,
355+
(i < chain->count - 1) ? "," : "");
356+
}
359357

358+
fprintf(fp, " ]\n}\n");
360359
fclose(fp);
361360
return 1;
362361
}

0 commit comments

Comments
 (0)