cmHexFileConverter.cxx 5.9 KB

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