#!/bin/bash # 用法: ./extract_firmware.sh [output_dir] # 从合并的 bin 文件中提取 head file (firmware), tail file (IUM), 以及生成 metadata.json # # 文件布局: # 0x04000: firmware (head file) # 0x1dc00: IUM (tail file, 256 bytes) # 0x1dd00: metadata (blocks: uint16, last_block_size: uint8) INPUT="$1" OUTPUT_DIR="${2:-.}" if [ -z "$INPUT" ]; then echo "用法: $0 [output_dir]" echo "示例: $0 40_ufcs2.bin /tmp/output" echo " $0 40_ufcs2.bin # 输出到当前目录" echo "" echo "输出文件:" echo " firmware.bin - firmware 部分" echo " ium.bin - IUM 部分 (256 bytes)" echo " metadata.json - 元数据" exit 1 fi if [ ! -f "$INPUT" ]; then echo "错误: 文件不存在: $INPUT" exit 1 fi # 创建输出目录(如果不存在) mkdir -p "$OUTPUT_DIR" # 常量定义 FIRMWARE_OFFSET=$((0x4000)) # 16384 IUM_OFFSET=$((0x1dc00)) # 121856 METADATA_OFFSET=$((0x1dd00)) # 122112 IUM_SIZE=256 # 获取文件大小 if stat --version >/dev/null 2>&1; then FILE_SIZE=$(stat -c%s "$INPUT") # Linux else FILE_SIZE=$(stat -f%z "$INPUT") # macOS fi echo "输入文件: $INPUT" echo "文件大小: $FILE_SIZE bytes (0x$(printf '%x' $FILE_SIZE))" echo "" # 读取 metadata (位于 0x1dd00) # 结构: uint16_t blocks (little-endian), uint8_t last_block_size echo "读取 metadata (offset 0x1dd00)..." METADATA=$(dd if="$INPUT" bs=1 skip=$METADATA_OFFSET count=3 2>/dev/null | xxd -p) if [ ${#METADATA} -lt 6 ]; then echo "错误: 无法读取 metadata" exit 1 fi # 解析 little-endian uint16 (blocks) 和 uint8 (last_block_size) BLOCKS_LOW=$((16#${METADATA:0:2})) BLOCKS_HIGH=$((16#${METADATA:2:2})) BLOCKS=$(( BLOCKS_LOW + BLOCKS_HIGH * 256 )) LAST_BLOCK_SIZE=$((16#${METADATA:4:2})) echo " blocks: $BLOCKS (0x$(printf '%04x' $BLOCKS))" echo " last_block_size: $LAST_BLOCK_SIZE (0x$(printf '%02x' $LAST_BLOCK_SIZE))" # 计算 firmware 大小 FIRMWARE_SIZE=$(( BLOCKS * 256 + LAST_BLOCK_SIZE )) echo " 计算出 firmware 大小: $FIRMWARE_SIZE bytes" echo "" # 提取 head file (firmware: 从 0x4000 开始) HEAD_FILE="$OUTPUT_DIR/firmware.bin" echo "提取 head file (firmware)..." dd if="$INPUT" of="$HEAD_FILE" bs=1 skip=$FIRMWARE_OFFSET count=$FIRMWARE_SIZE status=none if [ $? -eq 0 ]; then ACTUAL_HEAD_SIZE=$(stat -f%z "$HEAD_FILE" 2>/dev/null || stat -c%s "$HEAD_FILE" 2>/dev/null) echo " ✓ 已保存: $HEAD_FILE ($ACTUAL_HEAD_SIZE bytes)" else echo " ✗ 提取失败" exit 1 fi # 提取 tail file (IUM: 从 0x1dc00 开始, 256 bytes) TAIL_FILE="$OUTPUT_DIR/ium.bin" echo "提取 tail file (IUM)..." dd if="$INPUT" of="$TAIL_FILE" bs=1 skip=$IUM_OFFSET count=$IUM_SIZE status=none if [ $? -eq 0 ]; then ACTUAL_TAIL_SIZE=$(stat -f%z "$TAIL_FILE" 2>/dev/null || stat -c%s "$TAIL_FILE" 2>/dev/null) echo " ✓ 已保存: $TAIL_FILE ($ACTUAL_TAIL_SIZE bytes)" else echo " ✗ 提取失败" exit 1 fi # 生成 metadata.json METADATA_FILE="$OUTPUT_DIR/metadata.json" echo "生成 metadata.json..." cat > "$METADATA_FILE" << EOF {"blocks": "0x$(printf '%04x' $BLOCKS)", "lastBlockSize": "0x$(printf '%02x' $LAST_BLOCK_SIZE)"} EOF echo " ✓ 已保存: $METADATA_FILE" echo "" # 显示结果 echo "=========================================" echo "提取完成!" echo "" echo "输出文件:" echo " Head (firmware): $HEAD_FILE ($ACTUAL_HEAD_SIZE bytes)" echo " Tail (IUM): $TAIL_FILE ($ACTUAL_TAIL_SIZE bytes)" echo " Metadata: $METADATA_FILE" echo "" echo "Metadata 内容:" cat "$METADATA_FILE" echo ""