Mercurial > public > ostc_companion
view HexFile.cpp @ 12:ac837fe1d590
Switch implementation for reqex class and added RFCOMM as label for Bluetooth based connection by Linux
| author | Ideenmodellierer |
|---|---|
| date | Mon, 12 Jan 2026 13:58:41 +0000 |
| parents | 21ce6187d32e |
| children |
line wrap: on
line source
///////////////////////////////////////////////////////////////////////////// /// \file HexFile.cpp /// \brief Read .hex file in "Intel HEX" format. /// \author JD Gascuel. /// /// \copyright (c) 2012-2016, JD Gascuel. All rights reserved. /// $Id$ ////////////////////////////////////////////////////////////////////////////// // // BSD 2-Clause License: // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////// #include "HexFile.h" #include "Utils/Log.h" #include "Utils/ProgressEvent.h" #include <QCoreApplication> #include <QTextStream> #include <QtDebug> ////////////////////////////////////////////////////////////////////////////// // Crypto++ objects needed: typedef unsigned char byte; #include "AES/rijndael.h" /////////////////////////////////////////////////////////////////////////////// HexFile::HexFile() : _memSize(0) , #ifdef FROG_MASTER _baseAddress(0) , #endif _buffer(0) {} HexFile::~HexFile() { delete[] _buffer; _buffer = 0; } /////////////////////////////////////////////////////////////////////////////// bool HexFile::allocate(size_t memSize, unsigned char fill) { delete[] _buffer; _buffer = new unsigned char[_memSize = memSize]; Q_CHECK_PTR(_buffer); memset(_buffer, fill, memSize); return true; } bool HexFile::sqwiz(size_t newMemSize) { if (newMemSize >= _memSize) { LOG_THROW("Squiz failed"); } _memSize = newMemSize; return true; } /////////////////////////////////////////////////////////////////////////////// static size_t bytes = 0; void HexFile::readLine() { QByteArray line = _file.readLine(); if (line[0] != ':') LOG_THROW("Bad HEX format"); unsigned char checksum = 0; bool ok = true; for (int i = 1; ok && i < line.length(); i += 2) { if (line[i] == '\r' || line[i] == '\n') break; checksum += line.mid(i, 2).toInt(&ok, 16); } if (!ok) LOG_THROW("Bad HEX header"); if (checksum != 0) LOG_THROW("Bad HEX checksum"); int len = line.mid(1, 2).toInt(0, 16); int addr = line.mid(3, 2).toInt(0, 16) << 8 | line.mid(5, 2).toInt(0, 16); int type = line.mid(7, 2).toInt(0, 16); switch (type) { case 00: //---- Data record ---------------------------------------------- if (_baseAddress == 0x300000) // Skip configuration bits. return; if (_baseAddress == 0xF00000) // Skip internal prom reset. return; for (int i = 0; i < len; i++, ++addr) { size_t a = _baseAddress + addr; if (a >= _memSize) LOG_THROW("BAD HEX address"); if (_buffer[a] != 0xFF) LOG_THROW("Double write"); _buffer[a] = line.mid(9 + i * 2, 2).toInt(&ok, 16); if (!ok) LOG_THROW("Bad HEX byte"); bytes++; } break; case 01: //---- END OF FILE record --------------------------------------- _file.seek(-1); // Force to end of file. break; case 02: //---- Segment address record ----------------------------------- if (len != 2 || addr != 0) LOG_THROW("Bad HEX Segment Address record"); _baseAddress = line.mid(9, 4).toInt(0, 16) << 4; break; case 04: //---- Extended Linear Address Record --------------------------- if (len != 2 || addr != 0) LOG_THROW("Bad HEX Extended Linear Address Record"); _baseAddress = line.mid(9, 2).toInt(0, 16) << 20 | line.mid(11, 2).toInt(0, 16) << 16; break; default: LOG_THROW("Bad HEX subtype"); } } /////////////////////////////////////////////////////////////////////////////// void HexFile::load(const QString &fileName) { Q_ASSERT(_buffer); _file.setFileName(fileName); if (!_file.open(QIODevice::ReadOnly)) LOG_THROW("Can't open HEX file"); bytes = 0; while (!_file.atEnd()) { PROGRESS(_file.pos(), _file.size()); readLine(); } PROGRESS_RESET(); _file.close(); LOG_TRACE(int(bytes / 1024.0f) << "KB loaded (" << int(bytes * 100.0f / _memSize) << "% of firmware area)."); } /////////////////////////////////////////////////////////////////////////////// const unsigned char *HexFile::data() const { Q_ASSERT(_buffer); return _buffer; } /////////////////////////////////////////////////////////////////////////////// unsigned int HexFile::checksum() const { Q_ASSERT(_buffer); unsigned short low = 0; unsigned short high = 0; for (size_t i = 0; i < _memSize; ++i) { low += _buffer[i]; high += low; } return (((unsigned int) high) << 16) + low; } /////////////////////////////////////////////////////////////////////////////// #ifndef FROG_MASTER void HexFile::saveEncrypted(const QString &, byte[16]) { LOG_THROW("No encryption"); } #else void HexFile::saveEncrypted(const QString &fileName, byte secretKey[16]) { _file.setFileName(fileName); if (!_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) LOG_THROW("Can't save to encrypted file"); QTextStream out(&_file); out.setIntegerBase(16); out.setPadChar('0'); //---- Generates 128 bits of random initialization vector ---------------- Rijndael::CFB<128>::IV iv = {0}; Rijndael::ECB<128> PRNG; PRNG.setupEncrypt(secretKey); for (int i = 0; i < sizeof iv; ++i) iv[i] = PRNG.get_random() % 256; size_t bytes = 0; // encrypted fake address for (int i0 = 0; i0 < sizeof iv; i0 += 0x10) { out << qSetFieldWidth(1) << ":" << qSetFieldWidth(6) << bytes << qSetFieldWidth(2); for (int i = 0; i < 0x10; i++) out << iv[i0 + i]; out << qSetFieldWidth(1) << "\n"; bytes += 0x10; } //---- Create stream encryptor ------------------------------------------- Rijndael::CFB<128> enc(secretKey, iv); //---- Process data ------------------------------------------------------ PROGRESS(0, _memSize); byte encrypted[32]; for (size_t addr = 0; addr < _memSize; addr += 0x10) { PROGRESS(addr, _memSize); enc.encrypt(_buffer + addr, encrypted); out << qSetFieldWidth(1) << ":" << qSetFieldWidth(6) << bytes << qSetFieldWidth(2); for (int i = 0; i < 16; i++) out << encrypted[i]; out << qSetFieldWidth(1) << "\n"; bytes += 16; } //---- Process data ------------------------------------------------------ unsigned int sum = checksum(); // 33.29.BD.1D out << qSetFieldWidth(1) << ":" << qSetFieldWidth(6) << bytes << qSetFieldWidth(2) << ((sum) & 0xff) << ((sum >> 8) & 0xff) << ((sum >> 16) & 0xff) << ((sum >> 24) & 0xff) << qSetFieldWidth(1) << "\n"; qDebug().nospace() << int(bytes / 1024.0f) << "KB saved into " << fileName.section('/', -1); PROGRESS_RESET(); } #endif /////////////////////////////////////////////////////////////////////////////// void HexFile::loadEncrypted(const QString &fileName, unsigned char secretKey[16]) { Q_ASSERT(_buffer); _file.setFileName(fileName); if (!_file.open(QIODevice::ReadOnly)) LOG_THROW("Cannot open HEX file " << fileName); //---- Read 128 bits of initialization vector ---------------------------- Rijndael::CFB<128>::IV iv = {0}; unsigned int bytes = 0; bool ok = true; for (size_t i0 = 0; i0 < sizeof iv; i0 += 0x10) { QByteArray line = _file.readLine(); if (line[0] != ':') LOG_THROW("Bad HEX line"); unsigned int readAddr = line.mid(1, 6).toInt(&ok, 16); if (!ok || readAddr != bytes) LOG_THROW("Bad HEX address"); for (int i = 0; i < 0x10; i++) iv[i0 + i] = line.mid(2 * i + 7, 2).toInt(&ok, 16); if (!ok) LOG_THROW("Bad HEX file format"); bytes += 0x10; } //---- Create stream decryptor ------------------------------------------- Rijndael::CFB<128> dec(secretKey, iv); //---- Process data ------------------------------------------------------ PROGRESS(0, (int) _memSize); Rijndael::Block encrypted; for (size_t addr = 0; addr < _memSize; addr += 0x10) { PROGRESS((int) addr, (int) _memSize); QByteArray line = _file.readLine(); if (line[0] != ':') LOG_THROW("Bad HEX line"); unsigned int readAddr = line.mid(1, 6).toInt(&ok, 16); if (!ok || readAddr != bytes) LOG_THROW("Bad HEX address"); for (int i = 0; i < 0x10; i++) encrypted[i] = line.mid(2 * i + 7, 2).toInt(&ok, 16); if (!ok) LOG_THROW("Bad HEX file format"); bytes += 0x10; dec.decrypt(encrypted, *(Rijndael::Block *) (_buffer + addr)); } QByteArray line = _file.readLine(); if (bytes != (unsigned int) line.mid(1, 6).toInt(&ok, 16) || !ok) LOG_THROW("Bad HEX address"); unsigned int sum = line.mid(7, 2).toInt(&ok, 16) + (line.mid(9, 2).toInt(&ok, 16) << 8) + (line.mid(11, 2).toInt(&ok, 16) << 16) + (line.mid(13, 2).toInt(&ok, 16) << 24); if (sum != checksum()) LOG_THROW("Bad HEX checksum"); PROGRESS_RESET(); }
