| 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 ; | 
|     } | 
|   | 
| } |