cmHexFileConverter.cxx 5.3 KB

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