packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmHexFileConverter.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmHexFileConverter.h"
13
14 #include <stdio.h>
15 #include <string.h>
16
17 #define INTEL_HEX_MIN_LINE_LENGTH     (1+8        +2)
18 #define INTEL_HEX_MAX_LINE_LENGTH     (1+8+(256*2)+2)
19 #define MOTOROLA_SREC_MIN_LINE_LENGTH (2+2+4        +2)
20 #define MOTOROLA_SREC_MAX_LINE_LENGTH (2+2+8+(256*2)+2)
21
22 // might go to SystemTools ?
23 static bool cm_IsHexChar(char c)
24 {
25   return (((c >= '0') && (c <= '9'))
26          || ((c >= 'a') && (c <= 'f'))
27          || ((c >= 'A') && (c <= 'F')));
28 }
29
30 static unsigned int ChompStrlen(const char* line)
31 {
32   if (line == 0)
33     {
34     return 0;
35     }
36   unsigned int  length = static_cast<unsigned int>(strlen(line));
37   if ((line[length-1] == '\n') || (line[length-1] == '\r'))
38     {
39     length--;
40     }
41   if ((line[length-1] == '\n') || (line[length-1] == '\r'))
42     {
43     length--;
44     }
45   return length;
46 }
47
48 static bool OutputBin(FILE* file, const char * buf,
49                       unsigned int startIndex, unsigned int stopIndex)
50 {
51   bool success = true;
52   char hexNumber[3];
53   hexNumber[2] = '\0';
54   char outBuf[256];
55   unsigned int outBufCount = 0;
56   for (unsigned int i = startIndex; i < stopIndex; i += 2)
57     {
58     hexNumber[0] = buf[i];
59     hexNumber[1] = buf[i+1];
60     unsigned int convertedByte = 0;
61     if (sscanf(hexNumber, "%x", &convertedByte) != 1)
62       {
63       success = false;
64       break;
65       }
66     outBuf[outBufCount] = static_cast<char>(convertedByte & 0xff);
67     outBufCount++;
68     }
69   if (success)
70     {
71     success = (fwrite(outBuf, 1, outBufCount, file)==outBufCount);
72     }
73   return success;
74 }
75
76 // see http://www.die.net/doc/linux/man/man5/srec.5.html
77 static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile)
78 {
79   unsigned int slen = ChompStrlen(buf);
80   if ((slen < MOTOROLA_SREC_MIN_LINE_LENGTH)
81        || (slen > MOTOROLA_SREC_MAX_LINE_LENGTH))
82     {
83     return false;
84     }
85
86   // line length must be even
87   if (slen % 2 == 1)
88     {
89     return false;
90     }
91
92   if (buf[0] != 'S')
93     {
94     return false;
95     }
96
97   unsigned int dataStart = 0;
98   // ignore extra address records
99   if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') || (buf[1] == '9'))
100     {
101     return true;
102     }
103   else if (buf[1] == '1')
104     {
105     dataStart = 8;
106     }
107   else if (buf[1] == '2')
108     {
109     dataStart = 10;
110     }
111   else if (buf[1] == '3')
112     {
113     dataStart = 12;
114     }
115   else // unknown record type
116     {
117     return false;
118     }
119
120   // ignore the last two bytes  (checksum)
121   return OutputBin(outFile, buf, dataStart, slen - 2);
122 }
123
124 // see http://en.wikipedia.org/wiki/Intel_hex
125 static bool ConvertIntelHexLine(const char* buf, FILE* outFile)
126 {
127   unsigned int slen = ChompStrlen(buf);
128   if ((slen < INTEL_HEX_MIN_LINE_LENGTH)
129        || (slen > INTEL_HEX_MAX_LINE_LENGTH))
130     {
131     return false;
132     }
133
134   // line length must be odd
135   if (slen % 2 == 0)
136     {
137     return false;
138     }
139
140   if ((buf[0] != ':') || (buf[7] != '0'))
141     {
142     return false;
143     }
144
145   unsigned int dataStart = 0;
146   if ((buf[8] == '0') || (buf[8] == '1'))
147     {
148     dataStart = 9;
149     }
150   // ignore extra address records
151   else if ((buf[8] == '2') || (buf[8] == '3') || (buf[8] == '4')
152             || (buf[8] == '5'))
153     {
154     return true;
155     }
156   else  // unknown record type
157     {
158     return false;
159     }
160
161 // ignore the last two bytes  (checksum)
162   return OutputBin(outFile, buf, dataStart, slen - 2);
163 }
164
165 cmHexFileConverter::FileType cmHexFileConverter::DetermineFileType(
166                                                         const char* inFileName)
167 {
168   char buf[1024];
169   FILE* inFile = fopen(inFileName, "rb");
170   if (inFile == 0)
171     {
172     return Binary;
173     }
174
175   if(!fgets(buf, 1024, inFile))
176     {
177     buf[0] = 0;
178     }
179   fclose(inFile);
180   FileType type = Binary;
181   unsigned int minLineLength = 0;
182   unsigned int maxLineLength = 0;
183   if (buf[0] == ':') // might be an intel hex file
184     {
185     type = IntelHex;
186     minLineLength = INTEL_HEX_MIN_LINE_LENGTH;
187     maxLineLength = INTEL_HEX_MAX_LINE_LENGTH;
188     }
189   else if (buf[0] == 'S') // might be a motorola srec file
190     {
191     type = MotorolaSrec;
192     minLineLength = MOTOROLA_SREC_MIN_LINE_LENGTH;
193     maxLineLength = MOTOROLA_SREC_MAX_LINE_LENGTH;
194     }
195   else
196     {
197     return Binary;
198     }
199
200   unsigned int slen = ChompStrlen(buf);
201   if ((slen < minLineLength) || (slen > maxLineLength))
202     {
203     return Binary;
204     }
205
206   for (unsigned int i = 1; i < slen; i++)
207     {
208     if (!cm_IsHexChar(buf[i]))
209       {
210       return Binary;
211       }
212     }
213   return type;
214 }
215
216 bool cmHexFileConverter::TryConvert(const char* inFileName,
217                                     const char* outFileName)
218 {
219   FileType type = DetermineFileType(inFileName);
220   if (type == Binary)
221     {
222     return false;
223     }
224
225   // try to open the file
226   FILE* inFile = fopen(inFileName, "rb");
227   FILE* outFile = fopen(outFileName, "wb");
228   if ((inFile == 0) || (outFile == 0))
229     {
230     if (inFile != 0)
231       {
232       fclose(inFile);
233       }
234     if (outFile != 0)
235       {
236       fclose(outFile);
237       }
238     return false;
239     }
240
241   // convert them line by line
242   bool success = false;
243   char buf[1024];
244   while (fgets(buf, 1024, inFile) != 0)
245     {
246     if (type == MotorolaSrec)
247       {
248       success = ConvertMotorolaSrecLine(buf, outFile);
249       }
250     else if (type == IntelHex)
251       {
252       success = ConvertIntelHexLine(buf, outFile);
253       }
254     if (success == false)
255       {
256       break;
257       }
258     }
259
260   // close them again
261   fclose(inFile);
262   fclose(outFile);
263   return success;
264 }
265