summaryrefslogtreecommitdiffstats
path: root/Source/cmHexFileConverter.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmHexFileConverter.cxx')
-rw-r--r--Source/cmHexFileConverter.cxx224
1 files changed, 224 insertions, 0 deletions
diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx
new file mode 100644
index 0000000..34fd626
--- /dev/null
+++ b/Source/cmHexFileConverter.cxx
@@ -0,0 +1,224 @@
+/*============================================================================
+ 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 == CM_NULLPTR) {
+ 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 == CM_NULLPTR) {
+ 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 == CM_NULLPTR) || (outFile == CM_NULLPTR)) {
+ if (inFile != CM_NULLPTR) {
+ fclose(inFile);
+ }
+ if (outFile != CM_NULLPTR) {
+ fclose(outFile);
+ }
+ return false;
+ }
+
+ // convert them line by line
+ bool success = false;
+ char buf[1024];
+ while (fgets(buf, 1024, inFile) != CM_NULLPTR) {
+ 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;
+}