| 420 | // --- Load --- |
| 421 | |
| 422 | bool SdCardFont::load(const char* path) { |
| 423 | freeAll(); |
| 424 | if (strlen(path) >= sizeof(filePath_)) { |
| 425 | LOG_ERR("SDCF", "Path too long (%zu bytes, max %zu)", strlen(path), sizeof(filePath_) - 1); |
| 426 | return false; |
| 427 | } |
| 428 | strncpy(filePath_, path, sizeof(filePath_) - 1); |
| 429 | filePath_[sizeof(filePath_) - 1] = '\0'; |
| 430 | |
| 431 | HalFile file; |
| 432 | if (!Storage.openFileForRead("SDCF", path, file)) { |
| 433 | LOG_ERR("SDCF", "Failed to open .cpfont: %s", path); |
| 434 | return false; |
| 435 | } |
| 436 | |
| 437 | // Read and validate global header |
| 438 | uint8_t headerBuf[HEADER_SIZE]; |
| 439 | if (file.read(headerBuf, HEADER_SIZE) != HEADER_SIZE) { |
| 440 | LOG_ERR("SDCF", "Failed to read header"); |
| 441 | return false; |
| 442 | } |
| 443 | |
| 444 | if (memcmp(headerBuf, CPFONT_MAGIC, 8) != 0) { |
| 445 | LOG_ERR("SDCF", "Invalid magic bytes"); |
| 446 | return false; |
| 447 | } |
| 448 | |
| 449 | uint16_t fileVersion = readU16(headerBuf + 8); |
| 450 | if (fileVersion != CPFONT_VERSION) { |
| 451 | LOG_ERR("SDCF", "Unsupported version: %u (expected %u)", fileVersion, CPFONT_VERSION); |
| 452 | return false; |
| 453 | } |
| 454 | |
| 455 | // Begin content hash: accumulate global header |
| 456 | uint32_t hash = fnv1a(headerBuf, HEADER_SIZE); |
| 457 | |
| 458 | bool is2Bit = (readU16(headerBuf + 10) & 1) != 0; |
| 459 | |
| 460 | uint8_t styleCount = headerBuf[12]; |
| 461 | if (styleCount == 0 || styleCount > MAX_STYLES) { |
| 462 | LOG_ERR("SDCF", "Invalid style count: %u", styleCount); |
| 463 | return false; |
| 464 | } |
| 465 | |
| 466 | // Read style TOC |
| 467 | for (uint8_t i = 0; i < styleCount; i++) { |
| 468 | uint8_t tocBuf[STYLE_TOC_ENTRY_SIZE]; |
| 469 | if (file.read(tocBuf, STYLE_TOC_ENTRY_SIZE) != STYLE_TOC_ENTRY_SIZE) { |
| 470 | LOG_ERR("SDCF", "Failed to read style TOC entry %u", i); |
| 471 | freeAll(); |
| 472 | return false; |
| 473 | } |
| 474 | |
| 475 | // Accumulate TOC entry into content hash |
| 476 | hash = fnv1a(tocBuf, STYLE_TOC_ENTRY_SIZE, hash); |
| 477 | |
| 478 | uint8_t styleId = tocBuf[0]; |
| 479 | if (styleId >= MAX_STYLES) { |
no test coverage detected