|
|
@@ -0,0 +1,266 @@
|
|
|
+/*=========================================================================
|
|
|
+
|
|
|
+ Program: CMake - Cross-Platform Makefile Generator
|
|
|
+ Module: $RCSfile$
|
|
|
+ Language: C++
|
|
|
+ Date: $Date$
|
|
|
+ Version: $Revision$
|
|
|
+
|
|
|
+ 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 <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 = 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];
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|