| /*============================================================================ |
| CMake - Cross Platform Makefile Generator |
| Copyright 2000-2009 Kitware, Inc., Insight Software Consortium |
| |
| Distributed under the OSI-approved BSD License (the "License"); |
| see accompanying file Copyright.txt for details. |
| |
| This software is distributed WITHOUT ANY WARRANTY; without even the |
| implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the License for more information. |
| ============================================================================*/ |
| #include "cmHexFileConverter.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #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<unsigned int>(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] = static_cast<char>(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 = cmsys::SystemTools::Fopen(inFileName, "rb"); |
| if (inFile == 0) |
| { |
| return Binary; |
| } |
| |
| if(!fgets(buf, 1024, inFile)) |
| { |
| buf[0] = 0; |
| } |
| 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 = cmsys::SystemTools::Fopen(inFileName, "rb"); |
| FILE* outFile = cmsys::SystemTools::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; |
| } |
| |