Skip to content

Commit aea46f6

Browse files
Update jellyfish.c
1 parent 435d429 commit aea46f6

File tree

1 file changed

+57
-137
lines changed

1 file changed

+57
-137
lines changed

code/logic/jellyfish.c

Lines changed: 57 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -169,197 +169,117 @@ void fossil_jellyfish_dump(const fossil_jellyfish_chain *chain) {
169169
}
170170
}
171171

172-
static void skip_whitespace(const char **ptr) {
173-
while (isspace(**ptr)) (*ptr)++;
174-
}
175-
176-
static bool match_key(const char **ptr, const char *key) {
177-
skip_whitespace(ptr);
178-
size_t len = strlen(key);
179-
if (strncmp(*ptr, key, len) == 0) {
180-
*ptr += len;
181-
return true;
182-
}
183-
return false;
184-
}
185-
186-
static bool parse_string(const char **ptr, char *out, size_t maxlen) {
187-
skip_whitespace(ptr);
188-
if (**ptr != '"') return false;
189-
(*ptr)++;
190-
size_t i = 0;
191-
while (**ptr && **ptr != '"' && i < maxlen - 1) {
192-
if (**ptr == '\\') (*ptr)++; // Skip escape char
193-
out[i++] = *(*ptr)++;
194-
}
195-
if (**ptr != '"') return false;
196-
(*ptr)++;
197-
out[i] = '\0';
198-
return true;
199-
}
200-
201-
static bool parse_hash(const char **ptr, uint8_t *hash_out) {
202-
char hexstr[FOSSIL_JELLYFISH_HASH_SIZE * 2 + 1] = {0};
203-
if (!parse_string(ptr, hexstr, sizeof(hexstr))) return false;
204-
205-
if (strlen(hexstr) != FOSSIL_JELLYFISH_HASH_SIZE * 2) return false;
206-
207-
for (size_t i = 0; i < FOSSIL_JELLYFISH_HASH_SIZE; ++i) {
208-
char byte[3] = { hexstr[i * 2], hexstr[i * 2 + 1], 0 };
209-
hash_out[i] = (uint8_t)strtoul(byte, NULL, 16);
210-
}
211-
return true;
212-
}
213-
214-
static bool parse_number(const char **ptr, double *out_d, uint64_t *out_u64, int *out_i, uint32_t *out_u32) {
215-
skip_whitespace(ptr);
216-
char buffer[64];
217-
size_t i = 0;
218-
while ((isdigit(**ptr) || **ptr == '.' || **ptr == '-') && i < sizeof(buffer) - 1)
219-
buffer[i++] = *(*ptr)++;
220-
buffer[i] = '\0';
221-
222-
if (out_d) *out_d = atof(buffer);
223-
if (out_u64) *out_u64 = strtoull(buffer, NULL, 10);
224-
if (out_i) *out_i = atoi(buffer);
225-
if (out_u32) *out_u32 = (uint32_t)strtoul(buffer, NULL, 10);
226-
227-
return i > 0;
228-
}
229-
230172
int fossil_jellyfish_load(fossil_jellyfish_chain *chain, const char *filepath) {
231173
FILE *fp = fopen(filepath, "rb");
232174
if (!fp) return 0;
233175

234176
fseek(fp, 0, SEEK_END);
235-
long fsize = ftell(fp);
177+
long length = ftell(fp);
236178
fseek(fp, 0, SEEK_SET);
237179

238-
char *data = malloc(fsize + 1);
239-
if (!data) {
180+
if (length <= 0 || (size_t)length > 1024 * 1024) {
240181
fclose(fp);
241182
return 0;
242183
}
243184

244-
fread(data, 1, fsize, fp);
245-
data[fsize] = '\0';
246-
fclose(fp);
247-
248-
const char *ptr = data;
249-
skip_whitespace(&ptr);
185+
char *buffer = malloc(length + 1);
186+
if (!buffer) {
187+
fclose(fp);
188+
return 0;
189+
}
250190

251-
if (!match_key(&ptr, "{\"signature\":")) { free(data); return 0; }
191+
if (fread(buffer, 1, length, fp) != (size_t)length) {
192+
free(buffer);
193+
fclose(fp);
194+
return 0;
195+
}
196+
buffer[length] = '\0';
197+
fclose(fp);
252198

253-
char sig[8];
254-
if (!parse_string(&ptr, sig, sizeof(sig)) || strcmp(sig, "JFS1") != 0) {
255-
free(data);
199+
const char *ptr = buffer;
200+
if (!match_key_value(&ptr, "signature", "JFS1")) {
201+
free(buffer);
256202
return 0;
257203
}
258204

259-
if (!match_key(&ptr, ",\"blocks\":[")) { free(data); return 0; }
205+
if (!skip_key(&ptr, "blocks") || !skip_symbol(&ptr, '[')) {
206+
free(buffer);
207+
return 0;
208+
}
260209

261210
size_t count = 0;
262-
bool ok = true;
263-
264-
while (*ptr && *ptr != ']') {
265-
if (count >= FOSSIL_JELLYFISH_MAX_MEM) break;
266-
211+
while (*ptr && *ptr != ']' && count < FOSSIL_JELLYFISH_MAX_MEM) {
267212
fossil_jellyfish_block *b = &chain->memory[count];
268213
memset(b, 0, sizeof(*b));
269214

270-
if (!match_key(&ptr, "{")) { ok = false; break; }
271-
272-
if (!match_key(&ptr, "\"input\":")) { ok = false; break; }
273-
if (!parse_string(&ptr, b->input, sizeof(b->input))) { ok = false; break; }
274-
275-
if (!match_key(&ptr, ",\"output\":")) { ok = false; break; }
276-
if (!parse_string(&ptr, b->output, sizeof(b->output))) { ok = false; break; }
277-
278-
if (!match_key(&ptr, ",\"hash\":")) { ok = false; break; }
279-
if (!parse_hash(&ptr, b->hash)) { ok = false; break; }
215+
if (!skip_symbol(&ptr, '{')) break;
216+
if (!parse_string_field(&ptr, "input", b->input, sizeof(b->input))) break;
217+
if (!parse_string_field(&ptr, "output", b->output, sizeof(b->output))) break;
218+
if (!parse_number_field(&ptr, "timestamp", NULL, &b->timestamp, NULL, NULL)) break;
280219

281-
if (!match_key(&ptr, ",\"timestamp\":")) { ok = false; break; }
282-
if (!parse_number(&ptr, NULL, &b->timestamp, NULL, NULL)) { ok = false; break; }
220+
double temp_conf = 0;
221+
if (!parse_number_field(&ptr, "confidence", &temp_conf, NULL, NULL, NULL)) break;
222+
b->confidence = (float)temp_conf;
283223

284-
if (!match_key(&ptr, ",\"valid\":")) { ok = false; break; }
285-
if (!parse_number(&ptr, NULL, NULL, &b->valid, NULL)) { ok = false; break; }
224+
if (!parse_number_field(&ptr, "usage_count", NULL, NULL, NULL, &b->usage_count)) break;
225+
b->valid = 1;
286226

287-
if (!match_key(&ptr, ",\"confidence\":")) { ok = false; break; }
288-
if (!parse_number(&ptr, &b->confidence, NULL, NULL, NULL)) { ok = false; break; }
227+
if (!skip_symbol(&ptr, '}')) break;
289228

290-
if (!match_key(&ptr, ",\"usage_count\":")) { ok = false; break; }
291-
if (!parse_number(&ptr, NULL, NULL, NULL, &b->usage_count)) { ok = false; break; }
292-
293-
if (!match_key(&ptr, "}")) { ok = false; break; }
294-
295-
count++;
296-
skip_whitespace(&ptr);
297-
if (*ptr == ',') ptr++;
229+
skip_comma(&ptr);
230+
++count;
298231
}
299232

300-
free(data);
301-
chain->count = ok ? count : 0;
302-
return ok ? 1 : 0;
303-
}
304-
305-
static void hex_encode(const uint8_t *hash, size_t len, char *out, size_t out_size) {
306-
const char *hex = "0123456789abcdef";
307-
if (out_size < len * 2 + 1) return;
308-
for (size_t i = 0; i < len; ++i) {
309-
out[i * 2] = hex[(hash[i] >> 4) & 0xF];
310-
out[i * 2 + 1] = hex[hash[i] & 0xF];
233+
if (!skip_symbol(&ptr, ']') || !skip_symbol(&ptr, '}')) {
234+
free(buffer);
235+
return 0;
311236
}
312-
out[len * 2] = '\0';
237+
238+
chain->count = count;
239+
free(buffer);
240+
return 1;
313241
}
314242

315243
int fossil_jellyfish_save(const fossil_jellyfish_chain *chain, const char *filepath) {
316244
FILE *fp = fopen(filepath, "wb");
317245
if (!fp) return 0;
318246

319-
fprintf(fp, "{\n \"signature\": \"JFS1\",\n \"blocks\": [\n");
247+
fprintf(fp, "{\n");
248+
fprintf(fp, " \"signature\": \"JFS1\",\n");
249+
fprintf(fp, " \"blocks\": [\n");
320250

321251
for (size_t i = 0; i < chain->count; ++i) {
322252
const fossil_jellyfish_block *b = &chain->memory[i];
323253

324-
// Escape input/output strings (basic)
325-
char input_escaped[FOSSIL_JELLYFISH_INPUT_SIZE * 2] = {0};
326-
char output_escaped[FOSSIL_JELLYFISH_OUTPUT_SIZE * 2] = {0};
254+
char input_escaped[2 * FOSSIL_JELLYFISH_INPUT_SIZE] = {0};
255+
char output_escaped[2 * FOSSIL_JELLYFISH_OUTPUT_SIZE] = {0};
327256

328-
char *dst = input_escaped;
329-
// Escape input
330257
char *dst = input_escaped;
331258
for (const char *src = b->input; *src && (size_t)(dst - input_escaped) < sizeof(input_escaped) - 2; ++src) {
332259
if (*src == '"' || *src == '\\') *dst++ = '\\';
333260
*dst++ = *src;
334261
}
335262
*dst = '\0';
336-
337-
// Escape output
263+
338264
dst = output_escaped;
339265
for (const char *src = b->output; *src && (size_t)(dst - output_escaped) < sizeof(output_escaped) - 2; ++src) {
340266
if (*src == '"' || *src == '\\') *dst++ = '\\';
341267
*dst++ = *src;
342268
}
343269
*dst = '\0';
344270

345-
char hash_hex[FOSSIL_JELLYFISH_HASH_SIZE * 2 + 1];
346-
hex_encode(b->hash, FOSSIL_JELLYFISH_HASH_SIZE, hash_hex, sizeof(hash_hex));
347-
348-
fprintf(fp,
349-
" {\n"
350-
" \"input\": \"%s\",\n"
351-
" \"output\": \"%s\",\n"
352-
" \"hash\": \"%s\",\n"
353-
" \"timestamp\": %" PRIu64 ",\n"
354-
" \"valid\": %d,\n"
355-
" \"confidence\": %.6f,\n"
356-
" \"usage_count\": %u\n"
357-
" }%s\n",
358-
input_escaped, output_escaped, hash_hex, b->timestamp, b->valid, b->confidence, b->usage_count,
359-
(i < chain->count - 1) ? "," : "");
271+
fprintf(fp, " {\n");
272+
fprintf(fp, " \"input\": \"%s\",\n", input_escaped);
273+
fprintf(fp, " \"output\": \"%s\",\n", output_escaped);
274+
fprintf(fp, " \"timestamp\": %" PRIu64 ",\n", b->timestamp);
275+
fprintf(fp, " \"confidence\": %.6f,\n", b->confidence);
276+
fprintf(fp, " \"usage_count\": %" PRIu32 "\n", b->usage_count);
277+
fprintf(fp, " }%s\n", (i < chain->count - 1) ? "," : "");
360278
}
361279

362-
fprintf(fp, " ]\n}\n");
280+
fprintf(fp, " ]\n");
281+
fprintf(fp, "}\n");
282+
363283
fclose(fp);
364284
return 1;
365285
}

0 commit comments

Comments
 (0)