00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "HexFile.h"
00025 #include <istream>
00026 #include <ostream>
00027 #include <fstream>
00028 #include <iostream>
00029 #include <iomanip>
00030 #include <cassert>
00031 #include <algorithm>
00032 #include <valarray>
00033
00034 namespace Aseba
00035 {
00036 std::string HexFile::EarlyEOF::toString() const
00037 {
00038 return FormatableString("Early end of file after %0 lines").arg(line);
00039 }
00040
00041 std::string HexFile::InvalidRecord::toString() const
00042 {
00043 return FormatableString("Invalid record at line %0").arg(line);
00044 }
00045
00046 std::string HexFile::WrongCheckSum::toString() const
00047 {
00048 return FormatableString("Wrong checksum (%0 instead of %1) at line %2").arg(computedCheckSum, 0, 16).arg(recordCheckSum, 0, 16).arg(line);
00049 }
00050
00051 std::string HexFile::UnknownRecordType::toString() const
00052 {
00053 return FormatableString("Unknown record type (%1) at line %0").arg(line).arg(recordType, 0, 16);
00054 }
00055
00056 std::string HexFile::FileOpeningError::toString() const
00057 {
00058 return FormatableString("Can't open file %0").arg(fileName);
00059 }
00060
00061 unsigned HexFile::getUint4(std::istream &stream)
00062 {
00063 int c = stream.get();
00064 if (c <= '9')
00065 return c - '0';
00066 else if (c <= 'F')
00067 return c - 'A' + 10;
00068 else
00069 return c - 'a' + 10;
00070 }
00071
00072 unsigned HexFile::getUint8(std::istream &stream)
00073 {
00074 return (getUint4(stream) << 4) | getUint4(stream);
00075 }
00076
00077 unsigned HexFile::getUint16(std::istream &stream)
00078 {
00079 return (getUint8(stream) << 8) | getUint8(stream);
00080 }
00081
00082 void HexFile::read(const std::string &fileName)
00083 {
00084 std::ifstream ifs(fileName.c_str());
00085
00086 if (ifs.bad())
00087 throw FileOpeningError(fileName);
00088
00089 int lineCounter = 0;
00090 uint32 baseAddress = 0;
00091
00092 while (ifs.good())
00093 {
00094
00095 char c;
00096 ifs >> c;
00097 if (c != ':')
00098 throw InvalidRecord(lineCounter);
00099
00100 uint8 computedCheckSum = 0;
00101
00102
00103 uint8 dataLength = getUint8(ifs);
00104 computedCheckSum += dataLength;
00105
00106
00107 uint16 lowAddress = getUint16(ifs);
00108 computedCheckSum += lowAddress;
00109 computedCheckSum += lowAddress >> 8;
00110
00111
00112 uint8 recordType = getUint8(ifs);
00113 computedCheckSum += recordType;
00114
00115 switch (recordType)
00116 {
00117 case 0:
00118
00119 {
00120
00121 std::vector<uint8> recordData;
00122 for (int i = 0; i != dataLength; i++)
00123 {
00124 uint8 d = getUint8(ifs);
00125 computedCheckSum += d;
00126 recordData.push_back(d);
00127
00128 }
00129
00130
00131 uint8 checkSum = getUint8(ifs);
00132 computedCheckSum = 1 + ~computedCheckSum;
00133 if (checkSum != computedCheckSum)
00134 throw WrongCheckSum(lineCounter, checkSum, computedCheckSum);
00135
00136
00137 uint32 address = lowAddress;
00138 address += baseAddress;
00139
00140
00141
00142 bool found = false;
00143 for (ChunkMap::iterator it = data.begin(); it != data.end(); ++it)
00144 {
00145 size_t chunkSize = it->second.size();
00146 if (address == it->first + chunkSize)
00147 {
00148
00149 std::copy(recordData.begin(), recordData.end(), std::back_inserter(it->second));
00150 found = true;
00151
00152 break;
00153 }
00154 else if (address + recordData.size() == it->first)
00155 {
00156
00157 it->second.resize(chunkSize + recordData.size());
00158
00159 std::copy_backward(it->second.begin(), it->second.begin() + chunkSize, it->second.end());
00160
00161 std::copy(recordData.begin(), recordData.end(), it->second.begin());
00162 found = true;
00163
00164 break;
00165 }
00166 }
00167 if (!found)
00168 data[address] = recordData;
00169 }
00170 break;
00171
00172 case 1:
00173
00174 for (ChunkMap::iterator it = data.begin(); it != data.end(); ++it)
00175 {
00176
00177 }
00178 return;
00179 break;
00180
00181 case 2:
00182
00183 {
00184 if (dataLength != 2)
00185 throw InvalidRecord(lineCounter);
00186
00187
00188 uint16 highAddress = getUint16(ifs);
00189 computedCheckSum += highAddress;
00190 computedCheckSum += highAddress >> 8;
00191 baseAddress = highAddress;
00192 baseAddress <<= 4;
00193
00194
00195
00196 uint8 checkSum = getUint8(ifs);
00197 computedCheckSum = 1 + ~computedCheckSum;
00198 if (checkSum != computedCheckSum)
00199 throw WrongCheckSum(lineCounter, checkSum, computedCheckSum);
00200 }
00201 break;
00202
00203 case 4:
00204
00205 {
00206 if (dataLength != 2)
00207 throw InvalidRecord(lineCounter);
00208
00209
00210 uint16 highAddress = getUint16(ifs);
00211 computedCheckSum += highAddress;
00212 computedCheckSum += highAddress >> 8;
00213 baseAddress = highAddress;
00214 baseAddress <<= 16;
00215
00216
00217
00218 uint8 checkSum = getUint8(ifs);
00219 computedCheckSum = 1 + ~computedCheckSum;
00220 if (checkSum != computedCheckSum)
00221 throw WrongCheckSum(lineCounter, checkSum, computedCheckSum);
00222 }
00223 break;
00224
00225 default:
00226 throw UnknownRecordType(lineCounter, recordType);
00227 break;
00228 }
00229
00230 lineCounter++;
00231 }
00232
00233 throw EarlyEOF(lineCounter);
00234 }
00235
00236 void HexFile::writeExtendedLinearAddressRecord(std::ofstream &stream, unsigned addr16) const
00237 {
00238 assert(addr16 <= 65535);
00239
00240 uint8 checkSum = 0;
00241
00242 stream << ":02000002";
00243 checkSum += 0x02;
00244 checkSum += 0x00;
00245 checkSum += 0x00;
00246 checkSum += 0x02;
00247
00248 stream << std::setw(2);
00249 stream << (addr16 & 0xFF);
00250 checkSum += (addr16 & 0xFF);
00251
00252 stream << std::setw(2);
00253 stream << (addr16 >> 8);
00254 checkSum += (addr16 >> 8);
00255
00256 checkSum = (~checkSum) + 1;
00257 stream << std::setw(2);
00258 stream << (unsigned)checkSum;
00259
00260 stream << "\n";
00261 }
00262
00263 void HexFile::writeData(std::ofstream &stream, unsigned addr16, unsigned count8, uint8 *data) const
00264 {
00265 assert(addr16 <= 65535);
00266 assert(count8 <= 255);
00267
00268 uint8 checkSum = 0;
00269
00270 stream << ":";
00271
00272 stream << std::setw(2);
00273 stream << count8;
00274 checkSum += count8;
00275
00276 stream << std::setw(2);
00277 stream << (addr16 & 0xFF);
00278 checkSum += (addr16 & 0xFF);
00279
00280 stream << std::setw(2);
00281 stream << (addr16 >> 8);
00282 checkSum += (addr16 >> 8);
00283
00284 stream << "00";
00285 checkSum += 0x00;
00286
00287 for (unsigned i = 0; i < count8; i++)
00288 {
00289 stream << std::setw(2);
00290 stream << (unsigned)data[i];
00291 checkSum += data[i];
00292 }
00293
00294 checkSum = (~checkSum) + 1;
00295 stream << std::setw(2);
00296 stream << (unsigned)checkSum;
00297
00298 stream << "\n";
00299 }
00300
00301 void HexFile::write(const std::string &fileName) const
00302 {
00303 std::ofstream ofs(fileName.c_str());
00304
00305 if (ofs.bad())
00306 throw FileOpeningError(fileName);
00307
00308
00309 ofs.flags(std::ios::hex);
00310 ofs.fill('0');
00311
00312
00313 for (ChunkMap::const_iterator it = data.begin(); it != data.end(); it++)
00314 {
00315
00316 unsigned address = it->first;
00317 unsigned amount = it->second.size();
00318 unsigned highAddress = address >> 16;
00319
00320 writeExtendedLinearAddressRecord(ofs, highAddress);
00321 for (unsigned count = 0; count < amount;)
00322 {
00323
00324 unsigned newHighAddress = (address + count) >> 16;
00325 if (newHighAddress != highAddress)
00326 writeExtendedLinearAddressRecord(ofs, newHighAddress);
00327 highAddress = newHighAddress;
00328
00329
00330 unsigned rowCount = std::min(amount - count, (unsigned)32);
00331 unsigned lowAddress = address & 0xFFFF;
00332 std::valarray<uint8> buffer(rowCount);
00333 std::copy(it->second.begin() + count, it->second.begin() + count + rowCount, &buffer[0]);
00334 writeData(ofs, lowAddress, rowCount , &buffer[0]);
00335
00336
00337 count += rowCount;
00338 }
00339 }
00340
00341
00342 ofs << ":00000001FF";
00343 }
00344 }
00345