* 从 HBC 文件末尾的自定义 Meta 块读取元数据 * 格式: [原始HBC][MAGIC_START][LENGTH][JSON_DATA][MAGIC_END]
(buffer)
| 25 | * 格式: [原始HBC][MAGIC_START][LENGTH][JSON_DATA][MAGIC_END] |
| 26 | */ |
| 27 | function readMetadataFromHBCFooter(buffer) { |
| 28 | const MAGIC = Buffer.from('RNUPDATE', 'utf8'); // 8 bytes |
| 29 | const MAGIC_SIZE = 8; |
| 30 | const LENGTH_SIZE = 4; |
| 31 | |
| 32 | console.log(`\n[DEBUG] Reading metadata from HBC footer...`); |
| 33 | console.log(`[DEBUG] File size: ${buffer.length} bytes`); |
| 34 | console.log(`[DEBUG] Last 100 bytes (hex): ${buffer.slice(-100).toString('hex')}`); |
| 35 | console.log(`[DEBUG] Last 50 bytes (utf8): ${buffer.slice(-50).toString('utf8', 0, 50).replace(/[^\x20-\x7E]/g, '.')}`); |
| 36 | |
| 37 | // 检查文件是否足够大以包含 meta 块 |
| 38 | // 最小大小: MAGIC_START(8) + LENGTH(4) + JSON(至少2字节"{}") + MAGIC_END(8) = 22 bytes |
| 39 | if (buffer.length < 22) { |
| 40 | console.log(`[DEBUG] File too small: ${buffer.length} < 22`); |
| 41 | return null; |
| 42 | } |
| 43 | |
| 44 | // 从文件末尾向前查找最后一个 MAGIC_END |
| 45 | const lastMagicIndex = buffer.lastIndexOf(MAGIC); |
| 46 | |
| 47 | console.log(`[DEBUG] MAGIC string: "${MAGIC.toString('utf8')}"`); |
| 48 | console.log(`[DEBUG] Last MAGIC index: ${lastMagicIndex}`); |
| 49 | |
| 50 | if (lastMagicIndex === -1) { |
| 51 | console.log(`[DEBUG] MAGIC not found in file`); |
| 52 | return null; |
| 53 | } |
| 54 | |
| 55 | // MAGIC_END 应该在文件末尾 |
| 56 | console.log(`[DEBUG] Expected MAGIC_END at: ${buffer.length - MAGIC_SIZE}`); |
| 57 | console.log(`[DEBUG] Found MAGIC_END at: ${lastMagicIndex}`); |
| 58 | |
| 59 | if (lastMagicIndex + MAGIC_SIZE !== buffer.length) { |
| 60 | console.warn(`⚠️ Found MAGIC but not at file end (expected ${buffer.length - MAGIC_SIZE}, found ${lastMagicIndex})`); |
| 61 | return null; |
| 62 | } |
| 63 | |
| 64 | // 计算 MAGIC_START 的位置 |
| 65 | // 从 MAGIC_END 向前:MAGIC_END(8) + JSON(?) + LENGTH(4) + MAGIC_START(8) |
| 66 | const magicEndStart = lastMagicIndex; |
| 67 | |
| 68 | // 读取长度字段(在 MAGIC_END 之前的 4 字节) |
| 69 | const lengthStart = magicEndStart - LENGTH_SIZE; |
| 70 | if (lengthStart < MAGIC_SIZE) { |
| 71 | console.log(`[DEBUG] lengthStart too small: ${lengthStart} < ${MAGIC_SIZE}`); |
| 72 | return null; // 文件太小 |
| 73 | } |
| 74 | |
| 75 | const jsonLength = buffer.readUInt32LE(lengthStart); |
| 76 | console.log(`[DEBUG] JSON length from buffer: ${jsonLength}`); |
| 77 | |
| 78 | // 验证长度是否合理(JSON 数据应该小于 10KB) |
| 79 | if (jsonLength > 10240 || jsonLength < 2) { |
| 80 | console.warn(`⚠️ Invalid JSON length: ${jsonLength}`); |
| 81 | return null; |
| 82 | } |
| 83 | |
| 84 | // 计算 JSON 数据的起始位置 |
no test coverage detected