Mercurial > public > ostc_companion
view HexFile.cpp @ 1:0b3630a29ad8
Initial version based on previous repository.
Project was ported to QT6 and in now cmake based.
| author | Ideenmodellierer <tiefenrauscher@web.de> |
|---|---|
| date | Thu, 27 Nov 2025 18:40:28 +0100 |
| parents | |
| 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(); }
