ENH: check in almost building VMS stuff with VMSBuild directory since the bootstrap...
[cmake.git] / Source / cmHexFileConverter.cxx
blobd124238beada03046f99c54920addc15e4f04723
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmHexFileConverter.cxx,v $
5 Language: C++
6 Date: $Date: 2007-07-20 12:36:16 $
7 Version: $Revision: 1.5 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmHexFileConverter.h"
19 #include <stdio.h>
20 #include <string.h>
22 #define INTEL_HEX_MIN_LINE_LENGTH (1+8 +2)
23 #define INTEL_HEX_MAX_LINE_LENGTH (1+8+(256*2)+2)
24 #define MOTOROLA_SREC_MIN_LINE_LENGTH (2+2+4 +2)
25 #define MOTOROLA_SREC_MAX_LINE_LENGTH (2+2+8+(256*2)+2)
27 // might go to SystemTools ?
28 static bool cm_IsHexChar(char c)
30 return (((c >= '0') && (c <= '9'))
31 || ((c >= 'a') && (c <= 'f'))
32 || ((c >= 'A') && (c <= 'F')));
35 static unsigned int ChompStrlen(const char* line)
37 if (line == 0)
39 return 0;
41 unsigned int length = static_cast<unsigned int>(strlen(line));
42 if ((line[length-1] == '\n') || (line[length-1] == '\r'))
44 length--;
46 if ((line[length-1] == '\n') || (line[length-1] == '\r'))
48 length--;
50 return length;
53 static bool OutputBin(FILE* file, const char * buf,
54 unsigned int startIndex, unsigned int stopIndex)
56 bool success = true;
57 char hexNumber[3];
58 hexNumber[2] = '\0';
59 char outBuf[256];
60 unsigned int outBufCount = 0;
61 for (unsigned int i = startIndex; i < stopIndex; i += 2)
63 hexNumber[0] = buf[i];
64 hexNumber[1] = buf[i+1];
65 unsigned int convertedByte = 0;
66 if (sscanf(hexNumber, "%x", &convertedByte) != 1)
68 success = false;
69 break;
71 outBuf[outBufCount] = convertedByte & 0xff;
72 outBufCount++;
74 if (success)
76 success = (fwrite(outBuf, 1, outBufCount, file)==outBufCount);
78 return success;
81 // see http://www.die.net/doc/linux/man/man5/srec.5.html
82 static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile)
84 unsigned int slen = ChompStrlen(buf);
85 if ((slen < MOTOROLA_SREC_MIN_LINE_LENGTH)
86 || (slen > MOTOROLA_SREC_MAX_LINE_LENGTH))
88 return false;
91 // line length must be even
92 if (slen % 2 == 1)
94 return false;
97 if (buf[0] != 'S')
99 return false;
102 unsigned int dataStart = 0;
103 // ignore extra address records
104 if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') || (buf[1] == '9'))
106 return true;
108 else if (buf[1] == '1')
110 dataStart = 8;
112 else if (buf[1] == '2')
114 dataStart = 10;
116 else if (buf[1] == '3')
118 dataStart = 12;
120 else // unknown record type
122 return false;
125 // ignore the last two bytes (checksum)
126 return OutputBin(outFile, buf, dataStart, slen - 2);
129 // see http://en.wikipedia.org/wiki/Intel_hex
130 static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
132 unsigned int slen = ChompStrlen(buf);
133 if ((slen < INTEL_HEX_MIN_LINE_LENGTH)
134 || (slen > INTEL_HEX_MAX_LINE_LENGTH))
136 return false;
139 // line length must be odd
140 if (slen % 2 == 0)
142 return false;
145 if ((buf[0] != ':') || (buf[7] != '0'))
147 return false;
150 unsigned int dataStart = 0;
151 if ((buf[8] == '0') || (buf[8] == '1'))
153 dataStart = 9;
155 // ignore extra address records
156 else if ((buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4')
157 || (buf[8] == '5'))
159 return true;
161 else // unknown record type
163 return false;
166 // ignore the last two bytes (checksum)
167 return OutputBin(outFile, buf, dataStart, slen - 2);
170 cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
171 const char* inFileName)
173 char buf[1024];
174 FILE* inFile = fopen(inFileName, "rb");
175 if (inFile == 0)
177 return Binary;
180 fgets(buf, 1024, inFile);
181 fclose(inFile);
182 FileType type = Binary;
183 unsigned int minLineLength = 0;
184 unsigned int maxLineLength = 0;
185 if (buf[0] == ':') // might be an intel hex file
187 type = IntelHex;
188 minLineLength = INTEL_HEX_MIN_LINE_LENGTH;
189 maxLineLength = INTEL_HEX_MAX_LINE_LENGTH;
191 else if (buf[0] == 'S') // might be a motorola srec file
193 type = MotorolaSrec;
194 minLineLength = MOTOROLA_SREC_MIN_LINE_LENGTH;
195 maxLineLength = MOTOROLA_SREC_MAX_LINE_LENGTH;
197 else
199 return Binary;
202 unsigned int slen = ChompStrlen(buf);
203 if ((slen < minLineLength) || (slen > maxLineLength))
205 return Binary;
208 for (unsigned int i = 1; i < slen; i++)
210 if (!cm_IsHexChar(buf[i]))
212 return Binary;
215 return type;
218 bool cmHexFileConverter::TryConvert(const char* inFileName,
219 const char* outFileName)
221 FileType type = DetermineFileType(inFileName);
222 if (type == Binary)
224 return false;
227 // try to open the file
228 FILE* inFile = fopen(inFileName, "rb");
229 FILE* outFile = fopen(outFileName, "wb");
230 if ((inFile == 0) || (outFile == 0))
232 if (inFile != 0)
234 fclose(inFile);
236 if (outFile != 0)
238 fclose(outFile);
240 return false;
243 // convert them line by line
244 bool success = false;
245 char buf[1024];
246 while (fgets(buf, 1024, inFile) != 0)
248 if (type == MotorolaSrec)
250 success = ConvertMotorolaSrecLine(buf, outFile);
252 else if (type == IntelHex)
254 success = ConvertIntelHexLine(buf, outFile);
256 if (success == false)
258 break;
262 // close them again
263 fclose(inFile);
264 fclose(outFile);
265 return success;