package com.dy.common.softUpgrade.parse; 
 | 
  
 | 
import cn.hutool.core.util.HexUtil; 
 | 
import com.dy.common.util.ByteUtil; 
 | 
import com.dy.common.util.CRC16; 
 | 
  
 | 
import java.io.*; 
 | 
import java.util.ArrayList; 
 | 
import java.util.List; 
 | 
import java.util.stream.Stream; 
 | 
  
 | 
/** 
 | 
 * @Author: liurunyu 
 | 
 * @Date: 2024/11/2 8:51 
 | 
 * @Description 
 | 
 */ 
 | 
public class HexFileParse { 
 | 
  
 | 
    private static final int hexFileMinLine = 4 ; 
 | 
    private static final int lineHeadEndIndex = 9 ; 
 | 
    private static final int lineValidCharCount = 43 ;//每行有效字符(冒号与十六进制)个数,例如“:1096C000DC96010010020020203E00000441000052”,但倒数第3行不受限制 
 | 
    private static final int bytesSplitUnit512 = 512 ; 
 | 
  
 | 
    public static void main(String[] args) throws Exception{ 
 | 
        boolean fromBytes = false ; 
 | 
        HexFileParse obj = new HexFileParse() ; 
 | 
        if(!fromBytes){ 
 | 
            String filePath = "D:\\hexFile\\YuanMu_20250116_01.hex"; 
 | 
            //File file = new File(filePath) ; 
 | 
            HexFileVo vo =  obj.doParse(filePath) ; 
 | 
            System.out.println(vo.toString()); 
 | 
        }else{ 
 | 
            String filePath = "D:\\hexFile\\YuanMu_20250116_01.hex"; 
 | 
            File file = new File(filePath) ; 
 | 
            byte[] fileContent = new byte[(int)file.length()] ; 
 | 
            FileInputStream fileInputStream = new FileInputStream(file) ; 
 | 
            fileInputStream.read(fileContent) ; 
 | 
            HexFileVo vo =  obj.doParse(fileContent) ; 
 | 
            System.out.println(vo.toString()); 
 | 
        } 
 | 
    } 
 | 
    /** 
 | 
     * 解析Hex文件 
 | 
     * @param path 
 | 
     * @return 
 | 
     * @throws Exception 
 | 
     */ 
 | 
    public HexFileVo doParse(String path) throws Exception { 
 | 
        File file = new File(path) ; 
 | 
        return this.doParse(file) ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 解析Hex文件 
 | 
     * @param file 
 | 
     * @return 
 | 
     * @throws Exception 
 | 
     */ 
 | 
    public HexFileVo doParse(File file) throws Exception{ 
 | 
        if(file == null){ 
 | 
            throw new Exception("Hex文件对象为null") ; 
 | 
        } 
 | 
        if(!file.exists()){ 
 | 
            throw new Exception("Hex文件不存在") ; 
 | 
        } 
 | 
        Stream<String> linesStream = new BufferedReader(new FileReader(file)).lines() ; 
 | 
        List<String> lineList =  linesStream.toList() ; 
 | 
        HexFileVo vo = new HexFileVo() ; 
 | 
        this.checkAndCalculate(vo, lineList); 
 | 
        this.parse(vo, lineList); 
 | 
        this.splitBytesByUnit512(vo); 
 | 
        this.calculateCrc(vo); 
 | 
        return vo ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 解析Hex文件 
 | 
     * @param fileContent 
 | 
     * @return 
 | 
     * @throws Exception 
 | 
     */ 
 | 
    public HexFileVo doParse(byte[] fileContent) throws Exception{ 
 | 
        if(fileContent == null || fileContent.length == 0){ 
 | 
            throw new Exception("Hex文件对象为null") ; 
 | 
        } 
 | 
        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(fileContent); 
 | 
        Stream<String> linesStream = new BufferedReader(new InputStreamReader(byteInputStream)).lines() ; 
 | 
        List<String> lineList =  linesStream.toList() ; 
 | 
        HexFileVo vo = new HexFileVo() ; 
 | 
        this.checkAndCalculate(vo, lineList); 
 | 
        this.parse(vo, lineList); 
 | 
        this.splitBytesByUnit512(vo); 
 | 
        this.calculateCrc(vo); 
 | 
        return vo ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 合法性检查,并计算数据包数 
 | 
     * @param vo 
 | 
     * @param lineList 
 | 
     * @throws Exception 
 | 
     */ 
 | 
    private void checkAndCalculate(HexFileVo vo, List<String> lineList) throws Exception{ 
 | 
        if(lineList == null){ 
 | 
            throw new Exception("Hex文件内容为空") ; 
 | 
        } 
 | 
        vo.totalLines = lineList.size() ; 
 | 
        if(vo.totalLines <= 0){ 
 | 
            throw new Exception("Hex文件内容为空") ; 
 | 
        } 
 | 
        if(vo.totalLines < hexFileMinLine){ 
 | 
            throw new Exception("Hex文件内容行数" + vo.totalLines + "不正确(最小行数" + hexFileMinLine +")") ; 
 | 
        } 
 | 
        vo.calculateBytes = ((((vo.totalLines - 4) * 32) / 1024) 
 | 
                + ((((vo.totalLines - 4) * 32) % 1024) > 0?1 : 0)) 
 | 
                * 512 ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 解析Hex文件内容,组合成一个大数据包 
 | 
     * @param vo 
 | 
     * @param lineList 
 | 
     * @throws Exception 
 | 
     */ 
 | 
    private void parse(HexFileVo vo, List<String> lineList) throws Exception{ 
 | 
        int counter = 0 ; 
 | 
        for(String line : lineList){ 
 | 
            if(counter == 0){ 
 | 
                // 文件头 
 | 
            }else if(counter == vo.totalLines - 2){ 
 | 
                // 文件尾倒数第2行 
 | 
            }else if(counter == vo.totalLines - 1){ 
 | 
                // 文件尾倒数第1行 
 | 
            }else{ 
 | 
                // 文件内容 
 | 
                if(line == null){ 
 | 
                    vo.errors.add("第" + counter + "行内容为空") ; 
 | 
                }else{ 
 | 
                    line = line.trim() ; 
 | 
                    if(line.length() == 0){ 
 | 
                        vo.errors.add("第" + counter + "行内容为空") ; 
 | 
                    }else{ 
 | 
                        if(!line.startsWith(":")){ 
 | 
                            vo.errors.add("第" + counter + "行内容不是以:开头") ; 
 | 
                        }else{ 
 | 
                            if(counter != vo.totalLines - 3 && line.length() != lineValidCharCount){ 
 | 
                                //无效数据,舍弃本行数据 
 | 
                            }else{ 
 | 
                                line = line.substring(lineHeadEndIndex, line.length() - 2) ; 
 | 
                                if(vo.bytes.length == 0){ 
 | 
                                    vo.bytes = HexUtil.decodeHex(line) ; 
 | 
                                }else{ 
 | 
                                    byte[] bytes = HexUtil.decodeHex(line) ; 
 | 
                                    vo.bytes = ByteUtil.bytesMerge(vo.bytes, bytes) ; 
 | 
                                } 
 | 
                            } 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
            counter ++ ; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 以512为单位分割数据包 
 | 
     * @param bytes 
 | 
     */ 
 | 
    public List<byte[]> splitBytesByUnit512(byte[] bytes){ 
 | 
        List<byte[]> listByte512 = new ArrayList<>(); 
 | 
        if(bytes != null && bytes.length > 0){ 
 | 
            int index = 0 ; 
 | 
            while (true){ 
 | 
                if(index < bytes.length){ 
 | 
                    byte[] bs = ByteUtil.bytesSplit(bytes, index, bytesSplitUnit512) ; 
 | 
                    listByte512.add(bs) ; 
 | 
                }else{ 
 | 
                    break ; 
 | 
                } 
 | 
                index += bytesSplitUnit512; 
 | 
            } 
 | 
        } 
 | 
        return listByte512 ; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 以512为单位分割数据包 
 | 
     * @param vo 
 | 
     */ 
 | 
    private void splitBytesByUnit512(HexFileVo vo){ 
 | 
        if(vo.bytes != null && vo.bytes.length > 0){ 
 | 
            vo.realBytes += vo.bytes.length ; 
 | 
            int index = 0 ; 
 | 
            while (true){ 
 | 
                if(index < vo.bytes.length){ 
 | 
                    byte[] bytes = ByteUtil.bytesSplit(vo.bytes, index, bytesSplitUnit512) ; 
 | 
                    vo.listByte512.add(bytes) ; 
 | 
                    vo.totalBytes512 += bytes.length ; 
 | 
                }else{ 
 | 
                    break ; 
 | 
                } 
 | 
                index += bytesSplitUnit512; 
 | 
            } 
 | 
        } 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 计算CRC16 
 | 
     * @param vo 
 | 
     */ 
 | 
    private void calculateCrc(HexFileVo vo){ 
 | 
        int crc = 0xffff ; 
 | 
        if(vo.listByte512 != null && vo.listByte512.size() > 0){ 
 | 
            CRC16 crc16 = new CRC16() ; 
 | 
            for(byte[] bs : vo.listByte512){ 
 | 
                crc =  crc16.CRC16_table(bs.length, bs, crc) ; 
 | 
            } 
 | 
        } 
 | 
        vo.bytesCrc16 = crc ; 
 | 
    } 
 | 
  
 | 
} 
 |