srecfile.cpp
459 lines
| 12.6 KiB
| text/x-c
|
CppLexer
/ srec / srecfile.cpp
Jeandet Alexis
|
r0 | /*------------------------------------------------------------------------------ | ||
-- This file is a part of the SocExplorer Software | ||||
-- Copyright (C) 2014, Plasma Physics Laboratory - CNRS | ||||
-- | ||||
-- This program is free software; you can redistribute it and/or modify | ||||
-- it under the terms of the GNU General Public License as published by | ||||
-- the Free Software Foundation; either version 2 of the License, or | ||||
-- (at your option) any later version. | ||||
-- | ||||
-- This program is distributed in the hope that it will be useful, | ||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
-- GNU General Public License for more details. | ||||
-- | ||||
-- You should have received a copy of the GNU General Public License | ||||
-- along with this program; if not, write to the Free Software | ||||
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
-------------------------------------------------------------------------------*/ | ||||
/*-- Author : Alexis Jeandet | ||||
-- Mail : alexis.jeandet@member.fsf.org | ||||
----------------------------------------------------------------------------*/ | ||||
#include "srecfile.h" | ||||
#include <QTextStream> | ||||
#include "binaryfile.h" | ||||
srecFile::srecFile() | ||||
{ | ||||
p_mergingRecords = true; | ||||
r14 | litleendian = false; | |||
Jeandet Alexis
|
r0 | } | ||
srecFile::srecFile(const QString &File) | ||||
{ | ||||
p_mergingRecords = true; | ||||
openFile(File); | ||||
r14 | litleendian = false; | |||
Jeandet Alexis
|
r0 | } | ||
srecFile::srecFile(const QStringList &Files) | ||||
{ | ||||
p_mergingRecords = true; | ||||
openFiles(Files); | ||||
r14 | litleendian = false; | |||
Jeandet Alexis
|
r0 | } | ||
srecFile::~srecFile() | ||||
{ | ||||
} | ||||
bool srecFile::openFile(const QString &File) | ||||
{ | ||||
return openFiles(QStringList()<<File); | ||||
} | ||||
bool srecFile::openFiles(const QStringList &Files) | ||||
{ | ||||
for(int i=0;i<Files.count();i++) | ||||
{ | ||||
this->p_isSrec=true; | ||||
this->p_isSrec &= isSREC(Files.at(i)); | ||||
this->p_files.append(new QFile(Files.at(i))); | ||||
this->p_files.at(i)->open(QIODevice::ReadOnly); | ||||
parseFile(this->p_files.at(i)); | ||||
} | ||||
return true; | ||||
} | ||||
bool srecFile::isopened() | ||||
{ | ||||
bool opened = true; | ||||
for(int i=0;i<this->p_files.count();i++) | ||||
{ | ||||
opened &= p_files.at(i)->isOpen(); | ||||
} | ||||
return opened; | ||||
} | ||||
int srecFile::closeFile() | ||||
{ | ||||
for(int i=0;i<p_files.count();i++) | ||||
{ | ||||
delete p_files.at(i); | ||||
delete p_fragments.at(i); | ||||
} | ||||
p_fragments.clear(); | ||||
p_files.clear(); | ||||
p_fileName.clear(); | ||||
return 0; | ||||
} | ||||
QList<codeFragment *> srecFile::getFragments() | ||||
{ | ||||
return p_fragments; | ||||
} | ||||
bool srecFile::toSrec(QList<codeFragment *> fragments, const QString &File) | ||||
{ | ||||
QString line; | ||||
QFile file(File); | ||||
file.open(QIODevice::WriteOnly); | ||||
if(file.isOpen()) | ||||
{ | ||||
QTextStream stream( &file ); | ||||
//First build header | ||||
stream << buildRecord(0,0,File.toStdString().c_str(),File.count()); | ||||
for(int i=0;i<fragments.count();i++) | ||||
{ | ||||
codeFragment *fragment = fragments.at(i); | ||||
for(int j=0;j<((int)(fragment->size)/16);j++) | ||||
{ | ||||
stream << buildRecord(3,fragment->address+(j*16),fragment->data+(j*16),16); | ||||
} | ||||
int rem = fragment->size % 16; | ||||
if(rem) | ||||
{ | ||||
stream << buildRecord(3,fragment->address+fragment->size-rem,fragment->data+fragment->size-rem,rem); | ||||
} | ||||
stream << buildRecord(7,fragment->address,NULL,0); | ||||
} | ||||
file.close(); | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||
bool srecFile::toSrec(const QString &File) | ||||
{ | ||||
return toSrec(p_fragments,File); | ||||
} | ||||
bool srecFile::toBinary(const QString &File) | ||||
{ | ||||
return binaryFile::toBinary(p_fragments,File); | ||||
} | ||||
int srecFile::lineCount() | ||||
{ | ||||
return p_lineCount; | ||||
} | ||||
int srecFile::getFragmentsCount() | ||||
{ | ||||
return p_fragments.count(); | ||||
} | ||||
int srecFile::getFragmentAddress(int index) | ||||
{ | ||||
if((index < p_fragments.count()) && (index>=0)) | ||||
{ | ||||
return p_fragments.at(index)->address; | ||||
} | ||||
return 0; | ||||
} | ||||
int srecFile::getFragmentSize(int index) | ||||
{ | ||||
if((index < p_fragments.count()) && (index>=0)) | ||||
{ | ||||
return p_fragments.at(index)->size; | ||||
} | ||||
return 0; | ||||
} | ||||
codeFragment *srecFile::getFragment(int index) | ||||
{ | ||||
if((index < p_fragments.count()) && (index>=0)) | ||||
{ | ||||
return p_fragments.at(index); | ||||
} | ||||
return NULL; | ||||
} | ||||
QString srecFile::getFragmentHeader(int index) | ||||
{ | ||||
if((index < p_fragments.count()) && (index>=0)) | ||||
{ | ||||
return p_fragments.at(index)->header; | ||||
} | ||||
return ""; | ||||
} | ||||
bool srecFile::getFragmentData(int index, char **buffer) | ||||
{ | ||||
if((index < p_fragments.count()) && (index>=0)) | ||||
{ | ||||
*buffer = (char *)this->p_fragments.at(index)->data; | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||
bool srecFile::mergingRecords() | ||||
{ | ||||
return p_mergingRecords; | ||||
} | ||||
void srecFile::setMergingRecords(bool enabled) | ||||
{ | ||||
p_mergingRecords = enabled; | ||||
} | ||||
bool srecFile::isSREC() | ||||
{ | ||||
return p_isSrec & isopened(); | ||||
} | ||||
bool srecFile::isSREC(const QString &File) | ||||
{ | ||||
QFile file(File); | ||||
file.open(QIODevice::ReadOnly); | ||||
if(file.isOpen()) | ||||
{ | ||||
file.seek(0); | ||||
QString line=file.readLine(); | ||||
file.close(); | ||||
return ((line.at(0)=='S')&&(line.at(1)=='0')); | ||||
} | ||||
return false; | ||||
} | ||||
void srecFile::parseFile(QFile *file) | ||||
{ | ||||
if(file->isOpen()) | ||||
{ | ||||
this->p_lineCount = 0; | ||||
file->seek(0); | ||||
codeFragment* fragment=NULL; | ||||
bool newFragment=true; | ||||
char* data; | ||||
quint64 size=0; | ||||
quint64 address=-1; | ||||
QString header; | ||||
while (!file->atEnd()) | ||||
{ | ||||
QString line = file->readLine(); | ||||
p_lineCount++; | ||||
int rectype = parseLine(line,&address,&data,&size); | ||||
if(rectype==0) | ||||
{ | ||||
header.clear(); | ||||
header.append(data); | ||||
fragment = new codeFragment(data,size,address); | ||||
fragment->header = header; | ||||
p_fragments.append(fragment); | ||||
} | ||||
else | ||||
{ | ||||
if((rectype>=1) && (rectype<=3)) | ||||
{ | ||||
if(p_mergingRecords) | ||||
{ | ||||
//Could I merge it with an other fragment? | ||||
bool merged = false; | ||||
for(int i=0;i<p_fragments.count();i++) | ||||
{ | ||||
codeFragment* frag = p_fragments.at(i); | ||||
if(((frag->address+frag->size)==address) && (merged==false) && (size!=0)) | ||||
{ | ||||
merged = mergeFragment(frag,data,size); | ||||
} | ||||
} | ||||
if(!merged) | ||||
{ | ||||
fragment = new codeFragment(data,size,address); | ||||
fragment->header = header; | ||||
p_fragments.append(fragment); | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
if(newFragment) | ||||
{ | ||||
fragment = new codeFragment(data,size,address); | ||||
fragment->header = header; | ||||
p_fragments.append(fragment); | ||||
newFragment = false; | ||||
} | ||||
else | ||||
{ | ||||
codeFragment* frag = p_fragments.last(); | ||||
mergeFragment(frag,data,size); | ||||
} | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
if((rectype>=7) && (rectype<=9)) | ||||
{ | ||||
newFragment = true; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
int srecFile::parseLine(const QString &record, quint64 *address, char **data, quint64 *size) | ||||
{ | ||||
#define newData (*data) | ||||
#define newAddress (*address) | ||||
#define newSize (*size) | ||||
int recType = -1; | ||||
if((record.count()>4) && checkSum(record)) | ||||
{ | ||||
if(record.at(0)=='S') | ||||
{ | ||||
recType = record.at(1).toLatin1() & 0x0F; | ||||
//Header type | ||||
if(recType==0) | ||||
{ | ||||
newAddress = record.mid(4,4).toInt(0,16); | ||||
newSize = record.mid(2,2).toInt(0,16) - 3; | ||||
if(newSize>0) | ||||
{ | ||||
newData=(char*)malloc(newSize+1); | ||||
for(int i=0;i<(int)newSize;i++) | ||||
{ | ||||
newData[i] = ((char)record.mid((2*i)+8,2).toInt(0,16)); | ||||
} | ||||
newData[newSize] = '\0'; // force string end for header | ||||
} | ||||
} | ||||
//2 address byte record type | ||||
if((recType==1) || (recType==5) || (recType==9)) | ||||
{ | ||||
newAddress = record.mid(4,4).toInt(0,16); | ||||
newSize = record.mid(2,2).toInt(0,16) - 3; | ||||
if(newSize>0) | ||||
{ | ||||
newData=(char*)malloc(newSize); | ||||
for(int i=0;i<(int)newSize;i++) | ||||
{ | ||||
newData[i] = ((char)record.mid((2*i)+8,2).toInt(0,16)); | ||||
} | ||||
} | ||||
} | ||||
//3 address byte record type | ||||
if((recType==2) || (recType==6) || (recType==8)) | ||||
{ | ||||
newAddress = record.mid(4,6).toInt(0,16); | ||||
newSize = record.mid(2,2).toInt(0,16) - 4; | ||||
if(newSize>0) | ||||
{ | ||||
newData=(char*)malloc(newSize); | ||||
for(int i=0;i<(int)newSize;i++) | ||||
{ | ||||
newData[i] = ((char)record.mid((2*i)+10,2).toInt(0,16)); | ||||
} | ||||
} | ||||
} | ||||
//4 address byte record type | ||||
if((recType==3) || (recType==7)) | ||||
{ | ||||
newAddress = record.mid(4,8).toInt(0,16); | ||||
newSize = record.mid(2,2).toInt(0,16) - 5; | ||||
if(newSize>0) | ||||
{ | ||||
newData=(char*)malloc(newSize); | ||||
for(int i=0;i<(int)newSize;i++) | ||||
{ | ||||
newData[i] = ((char)record.mid((2*i)+12,2).toInt(0,16)); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return recType; | ||||
} | ||||
char srecFile::lineCheckSum(const QString &line) | ||||
{ | ||||
char sum=0; | ||||
QString localLine = line; | ||||
bool ok; | ||||
if(localLine.at(0)=='S') // then should skip the first two digits | ||||
{ | ||||
localLine.remove(0,2); | ||||
} | ||||
for(int i=0;i<localLine.count();i+=2) | ||||
{ | ||||
sum+=(char)(localLine.mid(i,2).toInt(&ok,16)); | ||||
} | ||||
return ~sum; | ||||
} | ||||
bool srecFile::checkSum(const QString &line) | ||||
{ | ||||
QString scp=line; | ||||
scp.remove('\n'); | ||||
scp.remove('\r'); | ||||
char ck2 = (char)scp.mid(scp.count()-2,2).toInt(0,16); | ||||
char ck=lineCheckSum(scp.remove(scp.count()-2,2)); | ||||
if(ck==ck2) | ||||
{ | ||||
return true; | ||||
} | ||||
return false; | ||||
// return (ck2==ck); | ||||
} | ||||
QString srecFile::buildRecord(int recType, int address,const char *data, int size) | ||||
{ | ||||
QString record; | ||||
if((recType>=0) && (recType<=9)) | ||||
{ | ||||
record.append("S"); | ||||
record.append(QString::number(recType)); | ||||
//2 address byte record type | ||||
if((recType==0) || (recType==1) || (recType==5) || (recType==9)) | ||||
{ | ||||
record.append(QString("%1").arg(3+size,2,16).replace(' ','0')); | ||||
record.append(QString("%1").arg(address,4,16).replace(' ','0')); | ||||
} | ||||
//3 address byte record type | ||||
if((recType==2) || (recType==6) || (recType==8)) | ||||
{ | ||||
record.append(QString("%1").arg(4+size,2,16).replace(' ','0')); | ||||
record.append(QString("%1").arg(address,6,16).replace(' ','0')); | ||||
} | ||||
//4 address byte record type | ||||
if((recType==3) || (recType==7)) | ||||
{ | ||||
record.append(QString("%1").arg(5+size,2,16).replace(' ','0')); | ||||
record.append(QString("%1").arg(address,8,16).replace(' ','0')); | ||||
} | ||||
for(int i=0; i<size;i++) | ||||
{ | ||||
record.append(QString("%1").arg((uchar)data[i],2,16).replace(' ','0')); | ||||
} | ||||
record.append(QString("%1").arg((uchar)srecFile::lineCheckSum(record),2,16).replace(' ','0')); | ||||
record.append('\n'); | ||||
} | ||||
return record.toUpper(); | ||||
} | ||||
bool srecFile::mergeFragment(codeFragment *fragment, char *data, int size) | ||||
{ | ||||
char* mergedData=(char*)malloc(size+fragment->size); | ||||
if(mergedData!=NULL) | ||||
{ | ||||
memcpy(mergedData,fragment->data,fragment->size); | ||||
memcpy(mergedData+fragment->size,data,size); | ||||
free(fragment->data); | ||||
free(data); | ||||
fragment->data = mergedData; | ||||
fragment->size = fragment->size+size; | ||||
return true; | ||||
} | ||||
return false; | ||||
} | ||||