Coverage Report

Created: 2026-06-15 07:03

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