/*========================================================================= Program: CMake - Cross-Platform Makefile Generator Module: $RCSfile: cmHexFileConverter.cxx,v $ Language: C++ Date: $Date: 2007-07-20 12:36:16 $ Version: $Revision: 1.5 $ Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "cmHexFileConverter.h" #include #include #define INTEL_HEX_MIN_LINE_LENGTH (1+8 +2) #define INTEL_HEX_MAX_LINE_LENGTH (1+8+(256*2)+2) #define MOTOROLA_SREC_MIN_LINE_LENGTH (2+2+4 +2) #define MOTOROLA_SREC_MAX_LINE_LENGTH (2+2+8+(256*2)+2) // might go to SystemTools ? static bool cm_IsHexChar(char c) { return (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'))); } static unsigned int ChompStrlen(const char* line) { if (line == 0) { return 0; } unsigned int length = static_cast(strlen(line)); if ((line[length-1] == '\n') || (line[length-1] == '\r')) { length--; } if ((line[length-1] == '\n') || (line[length-1] == '\r')) { length--; } return length; } static bool OutputBin(FILE* file, const char * buf, unsigned int startIndex, unsigned int stopIndex) { bool success = true; char hexNumber[3]; hexNumber[2] = '\0'; char outBuf[256]; unsigned int outBufCount = 0; for (unsigned int i = startIndex; i < stopIndex; i += 2) { hexNumber[0] = buf[i]; hexNumber[1] = buf[i+1]; unsigned int convertedByte = 0; if (sscanf(hexNumber, "%x", &convertedByte) != 1) { success = false; break; } outBuf[outBufCount] = convertedByte & 0xff; outBufCount++; } if (success) { success = (fwrite(outBuf, 1, outBufCount, file)==outBufCount); } return success; } // see http://www.die.net/doc/linux/man/man5/srec.5.html static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile) { unsigned int slen = ChompStrlen(buf); if ((slen < MOTOROLA_SREC_MIN_LINE_LENGTH) || (slen > MOTOROLA_SREC_MAX_LINE_LENGTH)) { return false; } // line length must be even if (slen % 2 == 1) { return false; } if (buf[0] != 'S') { return false; } unsigned int dataStart = 0; // ignore extra address records if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') || (buf[1] == '9')) { return true; } else if (buf[1] == '1') { dataStart = 8; } else if (buf[1] == '2') { dataStart = 10; } else if (buf[1] == '3') { dataStart = 12; } else // unknown record type { return false; } // ignore the last two bytes (checksum) return OutputBin(outFile, buf, dataStart, slen - 2); } // see http://en.wikipedia.org/wiki/Intel_hex static bool ConvertIntelHexLine(const char* buf, FILE* outFile) { unsigned int slen = ChompStrlen(buf); if ((slen < INTEL_HEX_MIN_LINE_LENGTH) || (slen > INTEL_HEX_MAX_LINE_LENGTH)) { return false; } // line length must be odd if (slen % 2 == 0) { return false; } if ((buf[0] != ':') || (buf[7] != '0')) { return false; } unsigned int dataStart = 0; if ((buf[8] == '0') || (buf[8] == '1')) { dataStart = 9; } // ignore extra address records else if ((buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4') || (buf[8] == '5')) { return true; } else // unknown record type { return false; } // ignore the last two bytes (checksum) return OutputBin(outFile, buf, dataStart, slen - 2); } cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType( const char* inFileName) { char buf[1024]; FILE* inFile = fopen(inFileName, "rb"); if (inFile == 0) { return Binary; } fgets(buf, 1024, inFile); fclose(inFile); FileType type = Binary; unsigned int minLineLength = 0; unsigned int maxLineLength = 0; if (buf[0] == ':') // might be an intel hex file { type = IntelHex; minLineLength = INTEL_HEX_MIN_LINE_LENGTH; maxLineLength = INTEL_HEX_MAX_LINE_LENGTH; } else if (buf[0] == 'S') // might be a motorola srec file { type = MotorolaSrec; minLineLength = MOTOROLA_SREC_MIN_LINE_LENGTH; maxLineLength = MOTOROLA_SREC_MAX_LINE_LENGTH; } else { return Binary; } unsigned int slen = ChompStrlen(buf); if ((slen < minLineLength) || (slen > maxLineLength)) { return Binary; } for (unsigned int i = 1; i < slen; i++) { if (!cm_IsHexChar(buf[i])) { return Binary; } } return type; } bool cmHexFileConverter::TryConvert(const char* inFileName, const char* outFileName) { FileType type = DetermineFileType(inFileName); if (type == Binary) { return false; } // try to open the file FILE* inFile = fopen(inFileName, "rb"); FILE* outFile = fopen(outFileName, "wb"); if ((inFile == 0) || (outFile == 0)) { if (inFile != 0) { fclose(inFile); } if (outFile != 0) { fclose(outFile); } return false; } // convert them line by line bool success = false; char buf[1024]; while (fgets(buf, 1024, inFile) != 0) { if (type == MotorolaSrec) { success = ConvertMotorolaSrecLine(buf, outFile); } else if (type == IntelHex) { success = ConvertIntelHexLine(buf, outFile); } if (success == false) { break; } } // close them again fclose(inFile); fclose(outFile); return success; }