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