package main import ( "encoding/binary" "encoding/hex" "fmt" "hash/crc32" "io" "io/ioutil" "os" "path/filepath" "github.com/akamensky/argparse" ) func swab16(x uint16) uint16 { return (x&0x00ff)<<8 | (x&0xff00)>>8 } func swab32(x uint32) uint32 { return (x&0x000000ff)<<24 | (x&0x0000ff00)<<8 | (x&0x00ff0000)>>8 | (x&0xff000000)>>24 } func sumArr(arr []uint8) uint32 { sum := uint32(0) for _, val := range arr { sum += uint32(val) } return sum } func calChecknum(_type string, datas []byte) uint32 { if _type == "sum32" { return sumArr(datas) } else if _type == "crc32" { return crc32.ChecksumIEEE(datas) } else { print("unKown type: " + _type) return 0 } } func getFileSize(filename string) (int64, error) { fileinfo, err := os.Stat(filename) if err != nil { return 0, err } size := fileinfo.Size() return size, nil } func ReadBinFile(_name string, _type string, _en string, _block int, _addcheck int, _addpos int) { FileName := filepath.Base(_name) // FileType := filepath.Ext(_name) InputFilePath := _name OutputFilePath := FileName + "." + _type inputFile, err := os.Open(InputFilePath) if err != nil { panic(err) } defer inputFile.Close() // 计算总帧数 // fileInfo, err := inputFile.Stat() // if err != nil { // panic(err) // } // fileSize := fileInfo.Size() // totalFrames := uint16((fileSize + int64(_block) - 1) / int64(_block)) outputFile, err := os.OpenFile(OutputFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { panic(err) } defer outputFile.Close() var Endian binary.ByteOrder switch _en { case "big": Endian = binary.BigEndian case "little": Endian = binary.LittleEndian default: fmt.Println("错误: 未知的大小端类型", _en) return } curFrame := 0 if _block > 0 { buffer := make([]byte, _block) for { n, err := inputFile.Read(buffer) if n > 0 { // 计算分片的校验和 check := calChecknum(_type, buffer[:n]) // 写入分片内容+分片校验和 binary.Write(outputFile, Endian, buffer[:n]) if _addpos == 1 { // 追加偏移量 binary.Write(outputFile, Endian, uint16(0xAAAA)) binary.Write(outputFile, Endian, uint16(curFrame)) } // 追加校验码 binary.Write(outputFile, Endian, check) curFrame ++ } if err != nil { if err == io.EOF { break // 文件读取完毕 } panic(err) } } } else { data, err := ioutil.ReadAll(inputFile) if err != nil { panic(err) } // 写入全部内容 binary.Write(outputFile, Endian, data) } // 读取文件内容到字节切片 inputFile, err = os.Open(InputFilePath) if err != nil { panic(err) } defer inputFile.Close() data, err := ioutil.ReadAll(inputFile) if err != nil { panic(err) } check := calChecknum(_type, data[:]) if _addcheck == 1 { // 追加校验码 binary.Write(outputFile, Endian, check) } // 大小端转换 var networkBytes [4]byte if _en == "big" { binary.BigEndian.PutUint32(networkBytes[:], check) } else { binary.LittleEndian.PutUint32(networkBytes[:], check) } check_hex := hex.EncodeToString(networkBytes[:]) // 打印输出内容 size, err := getFileSize(InputFilePath) fmt.Println(InputFilePath, fmt.Sprintf("%d", size), _type, check_hex) // 关闭文件 err = outputFile.Close() if err != nil { fmt.Println(err) } // 重命名文件 out_name1 := FileName + "." + _type + "[" + check_hex + "]" err = os.Rename(OutputFilePath, out_name1) if err != nil { fmt.Println("重命名文件出错:", err) return } } func main() { parser := argparse.NewParser("goChecknum", "这是一个用于固件校验码工具, 制作升级文件") _name := parser.String("n", "name", &argparse.Options{Required: true, Help: "bin文件名, 譬如 test.bin", Default: "test.bin"}) _type := parser.String("t", "type", &argparse.Options{Required: false, Help: "校验方式: sum32,crc32", Default: "sum32"}) _en := parser.String("e", "en", &argparse.Options{Required: false, Help: "校验码大小端: little,big", Default: "little"}) _section := parser.Int("s", "section", &argparse.Options{Required: false, Help: "分块大小: 0,1024,2048", Default: 0}) _addcheck := parser.Int("c", "addcheck", &argparse.Options{Required: false, Help: "文件结尾追加校验码", Default: 1}) _addpos := parser.Int("p", "addpos", &argparse.Options{Required: false, Help: "文件结尾追加偏移", Default: 1}) err := parser.Parse(os.Args) if err != nil { fmt.Print(parser.Usage(err)) // 帮助 -h or --help return } ReadBinFile(*_name, *_type, *_en, *_section, *_addcheck, *_addpos) }