diff options
author | Tobias Klauser <tklauser@distanz.ch> | 2008-10-08 19:22:25 +0200 |
---|---|---|
committer | Tobias Klauser <tklauser@xenon.tklauser.home> | 2008-10-08 19:22:25 +0200 |
commit | 2a441ecbea378da1a2cdea969c48bb7d9e547135 (patch) | |
tree | 63e071a86374ad86615c67f4c75534c4df8b6ab3 /src | |
parent | 226f961c4b7fef115ae2c7950abe0e1973efc6a4 (diff) |
Import new upstream release 0.42
Diffstat (limited to 'src')
37 files changed, 4737 insertions, 0 deletions
diff --git a/src/box.hpp b/src/box.hpp new file mode 100644 index 0000000..3edd733 --- /dev/null +++ b/src/box.hpp @@ -0,0 +1,50 @@ +#ifndef LFHEX_BOX_HPP +#define LFHEX_BOX_HPP +/* $Id: box.hpp,v 1.1 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <QWidget> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QChildEvent> + +template< class _layout > +class box : public QWidget { +public: + box( QWidget* parent ) : QWidget(parent) { + QLayout* l = new _layout(this); + setLayout(l); + } + void addStretch( int s ) + { + dynamic_cast<QBoxLayout*>(layout())->addStretch(s); + } +protected: + void childEvent( QChildEvent *e ) { + if( e->added() && e->child()->isWidgetType() ) { + QWidget* w = dynamic_cast<QWidget*>(e->child()); + layout()->addWidget(w); + } + } +}; + +typedef box<QHBoxLayout> hbox; +typedef box<QVBoxLayout> vbox; + +#endif + diff --git a/src/compareDlg.cpp b/src/compareDlg.cpp new file mode 100644 index 0000000..3c4e104 --- /dev/null +++ b/src/compareDlg.cpp @@ -0,0 +1,305 @@ +/* $Id: compareDlg.cpp,v 1.9 2008-09-11 01:49:00 salem Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <QLabel> +#include <QLineEdit> +#include <QCheckBox> +#include <qlayout.h> +#include <qpushbutton.h> +#include <QToolBar> +#include <QFileDialog> +#include <QMessageBox> +#include <QApplication> +#include <qcombobox.h> +#include <qtabwidget.h> +#include <QBitmap> +#include <QVBoxLayout> +#include <QMenuBar> + +#include "compareDlg.hpp" +#include "offsetConstraint.hpp" +#include "hexGui.hpp" +#include "reader.hpp" +#include "box.hpp" + +// icon images: +#include "img/prev.xbm" +#include "img/next.xbm" +#include "img/last.xbm" +#include "img/first.xbm" +#include "img/exit.xbm" + +//extern QApplication * qApp; + +CompareDlg::CompareDlg(const char *file0, + const char *file1, + QWidget*parent) + : QMainWindow(parent) +{ + tabLayout = new QTabWidget(this); + setCentralWidget(tabLayout); + + QWidget *options = new QWidget(tabLayout); + QVBoxLayout *optionLayout = new QVBoxLayout(options); + + optionLayout->setMargin(3); + optionLayout->setSpacing(2); + + // setup alignment entries: + offsetConstraint = new OffsetConstraint(options); + offsetConstraint->setTitle( "Constrain offset to X*n+Y" ); + optionLayout->addWidget(offsetConstraint); + // setup cursor offsets + diffOffsets = new QCheckBox("Allow different file offsets",options); + optionLayout->addWidget(diffOffsets); + // add a dummy strechable widget for alignment. + optionLayout->addStretch(1); + connect(diffOffsets,SIGNAL(stateChanged(int)), + this,SLOT(setAllowDiffOffsets(int))); + diffOffsets->setChecked(false); + setAllowDiffOffsets(false); + + // setup menu + QMenu* fileMenu = menuBar()->addMenu("File"); + fileMenu->addAction( QBitmap::fromData(QSize(exit_width,exit_height), + exit_bits),"Exit",qApp,SLOT(quit())); + + + // setup toolbar + QToolBar *tools = new QToolBar(this); + + tools->addAction(QBitmap::fromData(QSize(first_width,first_height),first_bits), + "First Difference",this,SLOT(first())); + tools->addAction(QBitmap::fromData(QSize(prev_width,prev_height),prev_bits), + "Previous Difference", this,SLOT(prev())); + tools->addAction(QBitmap::fromData(QSize(next_width,next_height),next_bits), + "Next Difference", this,SLOT(next())); + tools->addAction(QBitmap::fromData(QSize(last_width,last_height),last_bits), + "Last Difference", this,SLOT(last())); + + // setup compare section + QWidget *view = new QWidget(tabLayout); + QVBoxLayout *layout = new QVBoxLayout(view); + + hexGui[0] = new HexGui(view); + hexGui[1] = new HexGui(view); + reader[0] = hexGui[0]->reader(); + reader[1] = hexGui[1]->reader(); + + if( file0 ) + hexGui[0]->open(file0); + if( file1 ) + hexGui[1]->open(file1); + + layout->addWidget(hexGui[0]); + layout->addWidget(hexGui[1]); + hexGui[0]->setWindowFlags(Qt::SubWindow); + hexGui[1]->setWindowFlags(Qt::SubWindow); + + + tabLayout->addTab(view,"&Compare"); + tabLayout->addTab(options,"&Options"); + addToolBar(tools); + // request a size large enough for both hexEditors + resize(500,500); + setWindowTitle("Compare dialog"); +} + +bool CompareDlg::enabled() +{ + if( reader[0]->is_open() && reader[1]->is_open() ) { + // check to see if modified!!! + if( hexGui[0]->isModified() || hexGui[1]->isModified() ) { + QMessageBox::critical(this,PROGRAM_STRING, + "Error, cannot use comparison" + " functions on modified buffers."); + return false; + } + return true; + } + + return false; +} +// public slots +void CompareDlg::setAllowDiffOffsets(int state) +{ + diffOffsets->setChecked(state); +} + +bool CompareDlg::first() +{ + if( !enabled() ) + return false; + + // see Compare::last() for description of concept + off_t offset = offsetConstraint->next(0); + hexGui[0]->gotoOffset(offset); + hexGui[1]->gotoOffset(offset); + if( prev() ) + return true; + hexGui[0]->gotoOffset(0); + hexGui[1]->gotoOffset(0); + return next(); +} + +bool CompareDlg::last() +{ + if( !enabled() ) + return false; + + // look at lastidx 's previous's next range + // prev(x) is garranteed to not contain x, and next(prev(x)) will contain x + off_t min_size_decr = min( reader[0]->size()-1, + reader[1]->size()-1 ); + off_t offset = offsetConstraint->prev( min_size_decr ); + hexGui[0]->gotoOffset(offset); + hexGui[1]->gotoOffset(offset); + if( next() ) + return true; + hexGui[0]->gotoOffset( min_size_decr ); + hexGui[1]->gotoOffset( min_size_decr ); + return prev(); +} + +bool CompareDlg::prev() +{ + if( !enabled() ) + return false;; + // find previous diff + off_t offset[2]; + offset[0] = hexGui[0]->offset(); + offset[1] = (diffOffsets->isChecked()) ? hexGui[1]->offset() : offset[0]; + + if( offsetConstraint->getStride() > 1 ) { + off_t stop[2]; + off_t pos[2]; + for( pos[0] = offset[0] = offsetConstraint->prev(offset[0]), + pos[1] = offset[1] = offsetConstraint->prev(offset[1]); + offset[0] >= 0 && offset[1] >= 0; + pos[0] = offset[0] = offsetConstraint->prev(offset[0]), + pos[1] = offset[1] = offsetConstraint->prev(offset[1])) { + + // calculate stop + stop[0] = offset[0]+offsetConstraint->getStride(); + stop[1] = offset[1]+offsetConstraint->getStride(); + + // ignore lookups on less than a full stride length + // this would only happen if the file size is less than the stride + if( stop[0] > reader[0]->size() || stop[1] > reader[1]->size() ) + return false; + + while( pos[0] < stop[0] ) { + if( (*reader[0])[pos[0]++] != (*reader[1])[pos[1]++] ) { + // we have a difference + hexGui[0]->setSelection(offset[0],stop[0]); + hexGui[1]->setSelection(offset[1],stop[1]); + hexGui[0]->gotoOffset(offset[0]); + hexGui[1]->gotoOffset(offset[1]); + return true; + } + } + } + } else { + // just go one char at a time + + // make sure we are not past the eof of the second buffer + if( offset[1] >= reader[1]->size() ) + return false; + if( offset[0] <= 0 || offset[1] <= 0 ) + return false; + do { + offset[0]--; + offset[1]--; + + if( (*reader[0])[offset[0]] != (*reader[1])[offset[1]] ) { + hexGui[0]->gotoOffset(offset[0]); + hexGui[1]->gotoOffset(offset[1]); + hexGui[0]->setSelection(offset[0],offset[0]+1); + hexGui[1]->setSelection(offset[1],offset[1]+1); + return true; + } + } while( offset[0] > 0 && offset[1] > 0 ); + } + return false; +} + +bool CompareDlg::next() +{ + // find next diff + if( !enabled() ) + return false; + + off_t offset[2]; + offset[0] = hexGui[0]->offset(); + offset[1] = (diffOffsets->isChecked()) ? hexGui[1]->offset() : offset[0]; + + off_t size[2]; + size[0] = reader[0]->size(); + size[1] = reader[1]->size(); + + if( offsetConstraint->getStride() > 1 ) { + off_t stop[2]; + off_t pos[2]; + for( pos[0] = offset[0] = offsetConstraint->next(offset[0]), + pos[1] = offset[1] = offsetConstraint->next(offset[1]); + offset[0] < size[0] && offset[1] < size[1]; + pos[0] = offset[0] = offsetConstraint->next( offset[0] ), + pos[1] = offset[1] = offsetConstraint->next( offset[1] )) { + // compare from offset to offset+stride() + stop[0] = offset[0]+offsetConstraint->getStride(); + stop[1] = offset[1]+offsetConstraint->getStride(); + // if this will go past the bounds of the files, then the difference + // does not matter, ignore it. + if( stop[0] > size[0] || stop[1] > size[1] ) { + return false; + } + + while( pos[0] < stop[0] ) { + if( (*reader[0])[pos[0]++] != (*reader[1])[pos[1]++] ) { + // we have a difference + hexGui[0]->setSelection(offset[0],stop[0]); + hexGui[1]->setSelection(offset[1],stop[1]); + hexGui[0]->gotoOffset(offset[0]); + hexGui[1]->gotoOffset(offset[1]); + return true; // bail out of fn + } + } + } + } else { + // just go one at a time + if( offset[0] >= size[0] || offset[1] >= size[1] ) + return false; + if( offset[0] < 0 || offset[1] < 0 ) + return false; + offset[0]++; + offset[1]++; + while( offset[0] < size[0] && offset[1] < size[1] ) { + // don't compare the one we are on + if( (*reader[0])[offset[0]] != (*reader[1])[offset[1]] ) { + hexGui[0]->gotoOffset(offset[0]); + hexGui[1]->gotoOffset(offset[1]); + hexGui[0]->setSelection(offset[0],offset[0]+1); + hexGui[1]->setSelection(offset[1],offset[1]+1); + return true; + } + offset[0]++; + offset[1]++; + } + } + return false; +} diff --git a/src/compareDlg.hpp b/src/compareDlg.hpp new file mode 100644 index 0000000..1a51671 --- /dev/null +++ b/src/compareDlg.hpp @@ -0,0 +1,56 @@ +#ifndef COMPARE_DLG_HPP +#define COMPARE_DLG_HPP +/* $Id: compareDlg.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <QMainWindow> +#include <list> +#include "local.h" +// forward decl to speed compile times +class QCheckBox; +class QLineEdit; +class OffsetConstraint; +class HexGui; +class Reader; +class QTabWidget; + +class CompareDlg : public QMainWindow { + Q_OBJECT +public: + CompareDlg(const char * file0 = 0, + const char * file1 = 0, + QWidget * parent = 0); + + public slots: + void setAllowDiffOffsets(int state); + bool first(); + bool last(); + bool prev(); + bool next(); +protected: + bool enabled(); + +protected: + QTabWidget * tabLayout; + QCheckBox * diffOffsets; + HexGui * hexGui[2]; + Reader * reader[2]; + OffsetConstraint * offsetConstraint; +}; + +#endif diff --git a/src/conversionDlg.cpp b/src/conversionDlg.cpp new file mode 100644 index 0000000..114ab19 --- /dev/null +++ b/src/conversionDlg.cpp @@ -0,0 +1,363 @@ +/* $Id: conversionDlg.cpp,v 1.7 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <QLabel> +#include <QApplication> +#include <QCheckBox> +#include <QLineEdit> +#include <QPushButton> +#include <QMenuBar> +#include <QToolTip> + +#include <iostream> +#include <float.h> + +#include "conversionDlg.hpp" +#include "local.h" +#include "grid.hpp" +#include "box.hpp" + +ConversionDlg::ConversionDlg ( QWidget*parent ) + : QWidget(parent) +{ + inValueChanged = false; + + + QVBoxLayout *vbox = new QVBoxLayout(this); + grid* g = new grid(3,this); + + g->setContentsMargins(3,3,3,3); + + vbox->addWidget(g); + + new QWidget(g); + new QLabel(" Hex:",g); + leditors[HexLE] = new QLineEdit(g); + + new QWidget(g); + new QLabel(" ASCII:",g); + leditors[AsciiLE] = new QLineEdit(g); + + byteSwapFlag[IntegerBS] = new QCheckBox("b/s",g); + new QLabel(" Int:",g); + leditors[IntegerLE] = new QLineEdit(g); + + byteSwapFlag[FloatBS] = new QCheckBox("b/s",g); + new QLabel(" Float:",g); + leditors[FloatLE] = new QLineEdit(g); + + byteSwapFlag[DoubleBS] = new QCheckBox("b/s",g); + new QLabel(" Double:",g); + leditors[DoubleLE] = new QLineEdit(g); + + // make sure to do an update if any of the byte swap flags toggle + for(int i = MinBS; i < MaxBS; ++i) { + connect(byteSwapFlag[i],SIGNAL(clicked()), + this,SLOT(valueChanged())); + // add tool tip + byteSwapFlag[i]->setToolTip("Byte Swap Data"); + } + + // setup validators + leditors[DoubleLE]->setValidator( new QDoubleValidator(this) ); + QDoubleValidator *vd = new QDoubleValidator(this); + vd->setRange( FLT_MAX, FLT_MAX ); + leditors[FloatLE]->setValidator( vd ); + leditors[IntegerLE]->setValidator( new QIntValidator(this) ); + leditors[HexLE]->setValidator( new HexValidator(this) ); + + // setup editor connections + connect(leditors[DoubleLE],SIGNAL(textChanged(const QString& )), + this,SLOT(doubleChanged(const QString&)) ); + connect(leditors[FloatLE],SIGNAL(textChanged(const QString& )), + this,SLOT(floatChanged(const QString&)) ); + connect(leditors[IntegerLE],SIGNAL(textChanged(const QString&)), + this,SLOT(integerChanged(const QString&)) ); + connect(leditors[HexLE],SIGNAL(textChanged(const QString&)), + this,SLOT(valueChanged(const QString&))); + connect(leditors[AsciiLE],SIGNAL(textChanged(const QString&)), + this,SLOT(asciiChanged(const QString&))); + + for( int i = MinLE; i < MaxLE; ++i ) { + connect(leditors[i],SIGNAL(returnPressed()), + this,SIGNAL(nextPressed())); + } + + hbox * h = new hbox(this); + vbox->addWidget(h); + vbox->addStretch(1); + QPushButton* prev = new QPushButton("<",h); + QPushButton* next = new QPushButton(">",h); + + connect(prev,SIGNAL(clicked()),this,SIGNAL(prevPressed())); + connect(next,SIGNAL(clicked()),this,SIGNAL(nextPressed())); + + setWindowTitle("Conversion Dialog"); +} + +ConversionDlg::~ConversionDlg() +{ + cout << "died" <<endl; +} + +void ConversionDlg::floatChanged(const QString& str) +{ + QChar lastCh = str[str.length()-1]; + if( lastCh == 'e' || lastCh == '-' || lastCh == '.' ) { + return; + } + + bool success; + float value = str.toFloat(&success); + + if( !success && !value ) { + return; + } + + // double to hex: + uchar * ptr = (uchar*) &value; + vector<uchar> bytes; + + if( byteSwapFlag[FloatBS]->isChecked() ) { + for( int i = sizeof(float)-1; i > -1; i--) + bytes.push_back(ptr[i]); + } else { + for( unsigned int i = 0; i < sizeof(float); i++ ) + bytes.push_back(ptr[i]); + } + + QString hex; + Translate::ByteToHex(hex,bytes); + + valueChanged( hex ); +} + +void ConversionDlg::doubleChanged(const QString& str) +{ + QChar lastCh = str[str.length()-1]; + if( lastCh == 'e' || lastCh == '-' || lastCh == '.' ) { + return; + } + + bool success; + double value = str.toDouble(&success); + + if( !success && !value ) { + return; + } + + // double to hex: + uchar * ptr = (uchar*)&value; + vector<uchar> bytes; + + if(byteSwapFlag[DoubleBS]->isChecked() ) { + for(int i = sizeof(double)-1; i > -1; --i) + bytes.push_back(ptr[i]); + } else { + for(unsigned int i = 0; i < sizeof(double); i++ ) + bytes.push_back(ptr[i]); + } + QString hex; + Translate::ByteToHex(hex,bytes); + + valueChanged( hex ); +} + +void ConversionDlg::asciiChanged(const QString &str) +{ + vector<uchar> bytes; + QString hex; + Translate::CharToByte(bytes,str); + Translate::ByteToHex(hex,bytes); + + valueChanged( hex ); +} + +void ConversionDlg::integerChanged( const QString & str ) +{ + bool success; + int value = str.toInt(&success); + + uchar * ptr = (uchar*) &value; + vector<uchar> bytes; + + if( byteSwapFlag[IntegerBS]->isChecked() ) { + for( int i = sizeof(int)-1; i > -1 ;--i ) + bytes.push_back(ptr[i]); + } else { + for( unsigned int i = 0; i < sizeof(int)/sizeof(uchar); i++) + bytes.push_back(ptr[i]); + } + + QString hex; + Translate::ByteToHex(hex,bytes); + + valueChanged( hex ); +} + +// this slot just recalculates conversions +void ConversionDlg::valueChanged() +{ + // make sure the HexLE has focus, so valueChanged(str) updates all fields + leditors[HexLE]->setFocus(); + valueChanged( leditors[HexLE]->text() ); +} +// convert data to hex, then call updateData to set all the other data fields +void ConversionDlg::valueChanged( const QString& str ) +{ + if( str.size()%2 ) { + return; + } + // don't allow this call to nest + if(inValueChanged) + return; + + if( str.isEmpty() ) + return; + + inValueChanged = true; + // remmember cursor offset + int cursor_pos = leditors[HexLE]->cursorPosition(); + // conversion is safe because all chars are less than 'f' + leditors[HexLE]->setText( str ); + leditors[HexLE]->setCursorPosition( cursor_pos ); + + vector<uchar> bytes; + Translate::HexToByte(bytes,str); + if( !leditors[AsciiLE]->hasFocus() ) { + + if(!bytes.size()) { + for(int i = MinLE; i < MaxLE; ++i) + leditors[i]->setText( "" ); + inValueChanged = 0; + return; + } + + // update the ascii entry: + QString ascii; + Translate::ByteToChar(ascii,bytes); + + leditors[AsciiLE]->setText( ascii ); + } + + // scratch conversion vars + QString strvalue; + uchar * ucharPtr; + + if( !leditors[IntegerLE]->hasFocus() ) { + // update the int entry: + // pad right with 0x00 + int intvalue = 0; + ucharPtr = (uchar*) &intvalue; + if( byteSwapFlag[IntegerBS]->isChecked() ) { + for(unsigned int i = 0; (i < sizeof(int)) && (i < bytes.size()); i++) + ucharPtr[sizeof(int)-1-i] = bytes[i]; + } else { + memcpy(&intvalue,&bytes.begin()[0], + min(sizeof(int),bytes.size())); + } + strvalue.setNum(intvalue); + leditors[IntegerLE]->setText( strvalue ); + } + + if( ! leditors[FloatLE]->hasFocus() ) { + // update the float entry: + float fvalue; + ucharPtr = (uchar*)(&fvalue); + if( byteSwapFlag[FloatBS]->isChecked() ) { + for(unsigned int i = 0; i < sizeof(float); ++i) { + if( i < bytes.size() ) { + ucharPtr[sizeof(float)-1-i] = bytes[i]; + } else { + ucharPtr[sizeof(float)-1-i] = 0x00; + } + } + } else { + if(bytes.size() < sizeof(float) ) { + for(unsigned int i= 0; i < sizeof(float); ++i) { + if( i < bytes.size() ) { + *ucharPtr++ = bytes[i]; + } else { + *ucharPtr++ = 0x00; + } + } + } else { + memcpy(&fvalue,&bytes.begin()[0],sizeof(float)); + } + } + strvalue.setNum( fvalue ); + leditors[FloatLE]->setText( strvalue ); + } + + if( ! leditors[DoubleLE]->hasFocus() ) { + // update the double entry: + double dvalue; + ucharPtr = (uchar*)&dvalue; + if( byteSwapFlag[DoubleBS]->isChecked() ) { + for(unsigned int i= 0; i < sizeof(double); ++i) { + if( i < bytes.size() ) { + ucharPtr[sizeof(double)-1-i] = bytes[i]; + } else { + ucharPtr[sizeof(double)-1-i] = 0x00; + } + } + } else { + if(bytes.size() < sizeof(double) ) { + for(unsigned int i= 0; i < sizeof(double); ++i) { + if( i < bytes.size() ) { + *ucharPtr++ = bytes[i]; + } else { + *ucharPtr++ = 0x00; + } + } + } else { + memcpy(&dvalue,&bytes.begin()[0],sizeof(double)); + } + } + strvalue.setNum( dvalue ); + leditors[DoubleLE]->setText( strvalue ); + } + + inValueChanged = false; +} + +QString ConversionDlg::hexValue() const +{ + return leditors[HexLE]->text(); +} + +HexValidator::HexValidator( QWidget * parent ) + : QValidator(parent) +{ +} + +// allow 0xfff syntax +QValidator::State HexValidator::validate ( QString &str, int &pos ) const +{ + str = str.toLower(); + for(int i = 0; i < pos; i++) { + if( ! ((str[i] >= 'a' && str[i] <= 'f') || + (str[i] >= '0' && str[i] <= '9') ) && + ! (i == 1 && str[i] == 'x' ) + ) { + return Invalid; + } + } + return Acceptable; +} + diff --git a/src/conversionDlg.hpp b/src/conversionDlg.hpp new file mode 100644 index 0000000..6c61282 --- /dev/null +++ b/src/conversionDlg.hpp @@ -0,0 +1,78 @@ +/* $Id: conversionDlg.hpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CONVERSION_DLG_HPP_ +#define _CONVERSION_DLG_HPP_ +#include <QWidget> +#include <QWidget> +#include <QValidator> + +#include "translate.hpp" + +class QLineEdit; +class QCheckBox; + +class ConversionDlg : public QWidget { + Q_OBJECT +public: + ConversionDlg(QWidget* parent=0); + ~ConversionDlg(); + + QString hexValue() const; + +signals: + void nextPressed(); + void prevPressed(); + +public slots: + void doubleChanged( const QString& str ); + void floatChanged( const QString& str ); + void integerChanged( const QString& str ); + void valueChanged( const QString& str ); + void valueChanged(); + void asciiChanged( const QString& str ); + +protected: + enum { + MinLE = 0, + HexLE = 0 , + AsciiLE, + DoubleLE, + FloatLE, + IntegerLE, + MaxLE + }; + enum { + MinBS =0, + DoubleBS=0, + FloatBS, + IntegerBS, + MaxBS + }; + QLineEdit * leditors[MaxLE]; + QCheckBox * byteSwapFlag[MaxBS]; + bool inValueChanged; +}; + +class HexValidator : public QValidator { +public: + HexValidator( QWidget* parent ); + State validate( QString & str, int & pos ) const; +}; + +#endif diff --git a/src/cursor.cpp b/src/cursor.cpp new file mode 100755 index 0000000..92f4bef --- /dev/null +++ b/src/cursor.cpp @@ -0,0 +1,158 @@ +/* $Id: cursor.cpp,v 1.3 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "local.h" +#include "cursor.hpp" + +// +// Cursor implimentation +// + +Cursor::Cursor(off_t byteOffset, + off_t charOffset, + off_t low, + off_t high, + off_t charsPerByte) +: _byteOffset(byteOffset), + _charOffset(charOffset), + _low(low), + _high(high), + _charsPerByte(charsPerByte) +{} +// note: range includes low but excludes high: [low,high) (like stl) +// note: [foo,foo) is considered the empty set +bool Cursor::setRange( off_t low, off_t high ) +{ + if ( low > high ) + return false; + _low = low; + _high = high; + return true; +} + +off_t Cursor::decrByByte( off_t n ) +{ + // check for underflow + if (n > _byteOffset) + return OutOfRange; + else + _byteOffset -= n; + return _byteOffset; +} +off_t Cursor::decrByChar( off_t n ) +{ + off_t byteDelta = n/_charsPerByte; + off_t charDelta = n%_charsPerByte; + + if ( charDelta > _charOffset ) { + if( byteDelta == MAX_OFFSET ) { + throw out_of_range("Cursor decriment underflowed.\n"); + } + byteDelta++; + } + // if underflow.. then just return + if( byteDelta && OutOfRange == decrByByte( byteDelta ) ) { + return _charOffset; + } + if ( charDelta > _charOffset ) { + // offset == maxidx - abs(_charOffset - charDelta) + _charOffset = (_charsPerByte) - (charDelta - _charOffset); + } else { + _charOffset -= charDelta; + } + return _charOffset; +} +// note: off_t is always positive +off_t Cursor::incrByChar( off_t n ) +{ + off_t byteDelta = n/_charsPerByte; + off_t charDelta = n%_charsPerByte; + + // carry + if ( charDelta + _charOffset >= _charsPerByte ) { + // Note: this cannot overflow unless chars perbyte == 1 + if ( byteDelta == MAX_OFFSET ) { + throw out_of_range("Cursor increment exceeded maximum offset.\n"); + } + byteDelta++; + } + // if out of range, just leave the char offset where it is + if( byteDelta && OutOfRange == incrByByte( byteDelta ) ) { + return _charOffset; + } + // limit _charOffset to _charsPerByte - 1 + _charOffset = (charDelta + _charOffset)%_charsPerByte; + return _charOffset; +} + +off_t Cursor::incrByByte( off_t byteDelta ) +{ + if ( byteDelta > MAX_OFFSET - _byteOffset ) { + throw out_of_range("Cursor increment exceeded maximum offset.\n"); + } + if ( _byteOffset + byteDelta >= _high ) + return OutOfRange; + return (_byteOffset += byteDelta); +} + +// +// accessor implimentations +// +off_t Cursor::byteOffset() const +{ + return _byteOffset; +} +off_t Cursor::charOffset() const +{ + return _charOffset; +} +#define MIN(a,b) (a < b)?a:b +off_t Cursor::setCharsPerByte( off_t charsPerByte ) +{ + _charsPerByte = charsPerByte; + _charOffset = MIN(_charOffset,charsPerByte-1); + return _charsPerByte; +} +// _byteOffset values are clamped to: +// [_low,_high) +// _charOffset values are clamped to: +// [0,_charsPerByte-1] +void Cursor::setOffset( off_t byteOffset, off_t charOffset ) +{ + assignClamped(_byteOffset,byteOffset,0,_high); + assignClamped(_charOffset,charOffset,0,_charsPerByte); +} +off_t Cursor::charOffsetAbsolute() const +{ + return _byteOffset*_charsPerByte + _charOffset; +} +// +// void Cursor::assignClamped(dst,src, low,high); +// convienience function for assigning dst = src +// clamped to [low,high) +// +void Cursor::assignClamped(off_t& dst, off_t src, off_t low, off_t high) +{ + if( src < low ) { + dst = low; + } else if( src >= high ) { + dst = high-1; + } else { + dst = src; + } +} diff --git a/src/cursor.hpp b/src/cursor.hpp new file mode 100755 index 0000000..6b09a24 --- /dev/null +++ b/src/cursor.hpp @@ -0,0 +1,71 @@ +/* $Id: cursor.hpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _CURSOR_HPP_ +#define _CURSOR_HPP_ + +#include <sys/types.h> +#include <limits.h> +#include <stdexcept> + +#ifdef _LARGEFILE_SOURCE +#define MAX_OFFSET LONG_LONG_MAX +#else +#define MAX_OFFSET LONG_MAX +#endif + +class Cursor { +public: + Cursor( off_t byteOffset = 0, + off_t charOffset = 0, + off_t low = 0, + off_t high = 1, + off_t charsPerByte = 2 ); // defaults to hex + Cursor( const Cursor& c); + + off_t incrByChar( off_t n ); + off_t incrByByte( off_t n ); + off_t decrByChar( off_t n ); + off_t decrByByte( off_t n ); + + off_t byteOffset() const; //returns the current byte offset + off_t charOffset() const; //returns the current char offset. (relative) + off_t charOffsetAbsolute() const; //returns the current absolute offset. + + bool setRange( off_t low, off_t high ); + // setCharsPerByte: + // sideEffect: sets charOffset to min(_charsPerByte-1,_charOffset) + off_t setCharsPerByte( off_t charsPerByte ); + void setOffset( off_t byteOffset, off_t charOffset ); + +protected: + // performs: dst = src; and clamps the value to [low,high) + void assignClamped(off_t& dst,off_t src,off_t low,off_t high); + + enum { + OutOfRange = -1, + }; +protected: + off_t _byteOffset; + off_t _charOffset; + off_t _low; + off_t _high; + off_t _charsPerByte; +}; + +#endif diff --git a/src/delta.cpp b/src/delta.cpp new file mode 100755 index 0000000..de8ed3f --- /dev/null +++ b/src/delta.cpp @@ -0,0 +1,126 @@ +/* $Id: delta.cpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "delta.hpp" + +// +// DeltaMap class implimentation: +// + +DeltaMap::DeltaMap() {} // noop +DeltaMap::~DeltaMap() +{ + // just free all of the Delta's + clear(); +} + +// Free all the Delta's +// Note: this invalidates all pointers to Delta's returned through search() +// do NOT keep returned pointers arround for long. +// +void DeltaMap::clear() +{ + _map.erase(_map.begin(),_map.end()); + + // note: the union of _undo and _redo should contain ALL of the Delta's + // in the map. The intersection of _undo and _redo should be the empty set. + while ( !_undo.empty() ) { + delete _undo.top(); + _undo.pop(); + } + while ( !_redo.empty() ) { + delete _redo.top(); + _redo.pop(); + } +} + +// returns const ptr to the most recent delta on offset off_t +const Delta * DeltaMap::search( off_t offset ) const +{ + delta_map_t::const_iterator itr = _map.find(offset); + if ( itr != _map.end() && (itr->second).size() ) + return itr->second.back(); + else + return 0; +} + +size_t DeltaMap::insert( off_t offset, + const vector<uchar>& oldData, + const vector<uchar>& newData ) +{ + // + // only modify the newData of the top undo iff the offsets match + // and the redo stack is empty. + // + if( _undo.size() && _undo.top()->offset() == offset && _redo.empty() ) { + //just modify the newData of the top delta + _undo.top()->setNewData( newData ); + + // _map[offset] _should_ exist + return _map[offset].size(); + } else { + // create a new delta + Delta * tmp = new Delta(offset, oldData, newData); + _map[offset].push_back( tmp ); + _undo.push( tmp ); + return _map[offset].size(); + } +} + +bool DeltaMap::undo() +{ + if( _undo.empty() ) + return false; + + Delta* d = _undo.top(); + _undo.pop(); + // find the delta in the delta list indexed by d->offset and remove it. + map<off_t,list<Delta*> >::iterator itr = _map.find(d->offset()); + itr->second.remove(d); + // remove the entry iff the list is empty + if( itr->second.empty() ) { + _map.erase(itr); + } + // push the delta back onto the redo stack. + _redo.push( d ); + return true; +} + +bool DeltaMap::redo() +{ + if( _redo.empty() ) + return false; + + // insert the delta back into the modification list + Delta *d = _redo.top(); + _redo.pop(); + _map[d->offset()].push_back( d ); + _undo.push( d ); + return true; +} + +// methods for iterating over all the modifications in the tree +off_t DeltaMap::lower_bound(off_t lb) const +{ + delta_map_t::const_iterator itr = _map.lower_bound(lb); + if( itr == _map.end() ) { + return -1; + } else { + return itr->first; + } +} diff --git a/src/delta.hpp b/src/delta.hpp new file mode 100755 index 0000000..1c7d3e2 --- /dev/null +++ b/src/delta.hpp @@ -0,0 +1,93 @@ +/* $Id: delta.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _DELTA_MAP_ +#define _DELTA_MAP_ + +#include <sys/types.h> +#include <list> +#include <map> +#include <vector> +#include <stack> + +#include <iostream> + +#include "local.h" + +class Delta { +public: + Delta( off_t i, const vector<uchar>& oldData, const vector<uchar>& newData) : + _offset(i), _old(oldData), _new(newData) {} + + void setNewData( const vector<uchar>& ndata ) { _new = ndata; } + + off_t offset() const { return _offset; } + const vector<uchar>& newData() const { return _new;} + const vector<uchar>& oldData() const { return _old;} +protected: + off_t _offset; + vector<uchar> _old; + vector<uchar> _new; +}; + + +// allocation for all delta's is dynamic, but it is all handled +// within the class. +// the user of the class does not need to worry about memory +// allocation/deallocation. +class DeltaMap { +public: + DeltaMap(); + ~DeltaMap(); + +public: + // insert a new delta + size_t insert(off_t offset, + const vector<uchar>& oldData, + const vector<uchar>& newData); + // return the offset of the last inserted Delta. + off_t lastOffset() const; + // set the last delta's newData to data + void setLastData( const vector<uchar>& data); + int numEdits() const { return _undo.size(); } + // find the most recent delta + const Delta* search(off_t offset) const; + + // cleans undo/redo stacks and frees memory for all deltas. + // Makes references to delta's invalid. + void clear(); + + bool undo(); //undo last insert + bool redo(); //redo last insert + + // method for iterating over all of the modifications + // finds the first offset that is is not less than lb + // so lower_bound(0) returns the offset of the first delta + // (off_t) -1 is returned on failure + off_t lower_bound(off_t lb) const; + +protected: + typedef map<off_t,list<Delta*> > delta_map_t; + // notes: + // the back of the delta list is always the most recent/non undone delta. + map<off_t,list<Delta*> > _map; + stack<Delta*> _undo; + stack<Delta*> _redo; +}; + +#endif diff --git a/src/driver.cpp b/src/driver.cpp new file mode 100644 index 0000000..da72bf5 --- /dev/null +++ b/src/driver.cpp @@ -0,0 +1,100 @@ +/* $Id: driver.cpp,v 1.9 2008-09-11 01:49:00 salem Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qapplication.h> +#include <stdexcept> +#include <unistd.h> + +extern "C" { + int optind; +}; +#include "hexGui.hpp" +#include "local.h" +#include "compareDlg.hpp" + +#define STUB(x) extern "C" { void x() {}} +STUB(glXCreateGLXPixmapMESA); +STUB(glXReleaseBuffersMESA); + +// this is used for debugging because I cannot seem to figure out how to see +// the asci representation of a QString while in the debugger. +#include <iostream> +void coutAsciText( const QString& str ) +{ + cout << &str << " -> \"" << C_STR(str) << "\"" << endl; +} + +int main (int argc, char ** argv) +{ + QApplication a(argc,argv); + a.setStyle( "plastique" ); + // parse the command line and see what major mode we should be in + int compare = false; + int c; + // skip argv[0] + optind = 1; + while( EOF != (c = getopt(argc,argv,"c")) ) { + switch (c) { + case 'c': + compare = true; + break; + default: + cerr << "usage: " PROGRAM " [-c [file1 file2]] files..." <<endl; + exit(1); + break; + } + } + if( compare ) { + int nopts = argc - optind; + // check to see if files were passed in + if( nopts >= 2 ) { + (new CompareDlg(argv[optind],argv[optind+1]))->show(); + optind+=2; + } else { + (new CompareDlg())->show(); + } + // treat remaining cmdline options as files to be opened. + while( optind < argc ) { + HexGui *hg = new HexGui(); + hg->open(argv[optind++]); + hg->show(); + } + } else { + // each remaining argument is assumed to be a file + if( optind >= argc ) { + // no files, just open a hexGui + (new HexGui())->show(); + } else { + while( optind < argc ) { + HexGui *hg = new HexGui(); + hg->open(argv[optind++]); + hg->show(); + } + } + } + + a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) ); + int ret=0; + try { + ret = a.exec(); + } catch (const exception& e) { + ret = 1; + cerr << "[error] - unhandled exeption in main:\"" << e.what() << "\"" <<endl; + } + return ret; +} diff --git a/src/expr.h b/src/expr.h new file mode 100644 index 0000000..e90f4f5 --- /dev/null +++ b/src/expr.h @@ -0,0 +1,27 @@ +#ifndef EXPR_H +#define EXPR_H +/* $Id: expr.h,v 1.2 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <string> + +bool expr_eval( const std::string &str, off_t &value ); + +#define YYSTYPE off_t + +#endif diff --git a/src/expr.l b/src/expr.l new file mode 100644 index 0000000..aa6f538 --- /dev/null +++ b/src/expr.l @@ -0,0 +1,154 @@ +%{ +/* $Id: expr.l,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <math.h> + +#include <string> +#include <stdexcept> +#include <iostream> + +using namespace std; + +#include "expr.h" +#include "expr_yacc.h" + +int exprparse(); + +extern off_t expr_value; + +static off_t hex2l( const string &str ); + +#define yylval exprlval + +%} + +%option noyywrap + +hexnum [0-9a-fA-F]+ + +%% + +[1-9][0-9]* { + yylval = atol(yytext); + return NUMBER; + } +{hexnum} | +0x{hexnum} { + string hexnum = yytext; + if( hexnum.substr(0,2) == "0x" ) { + hexnum = hexnum.substr(2); + } + yylval = hex2l(hexnum); + return NUMBER; + } +[-+*()] { return yytext[0]; } +[ \r\n\t] {/*nop*/} +. { return yytext[0]; } + +%% + +static off_t +hex2l( + const string &str + ) +{ + // + off_t ret = 0; + size_t scale = 1; + int i = str.size()-1; + while( i > -1 ) { + switch( str[i] ) { + case '0': + break; + case '1': + ret += 1*scale; + break; + case '2': + ret += 2*scale; + break; + case '3': + ret += 3*scale; + break; + case '4': + ret += 4*scale; + break; + case '5': + ret += 5*scale; + break; + case '6': + ret += 6*scale; + break; + case '7': + ret += 7*scale; + break; + case '8': + ret += 8*scale; + break; + case '9': + ret += 9*scale; + break; + case 'a': + case 'A': + ret += 10*scale; + break; + case 'b': + case 'B': + ret += 11*scale; + break; + case 'c': + case 'C': + ret += 12*scale; + break; + case 'd': + case 'D': + ret += 13*scale; + break; + case 'e': + case 'E': + ret += 14*scale; + break; + case 'f': + case 'F': + ret += 15*scale; + break; + default: + char buf[1024]; + sprintf(buf,"Unknown hex char: \"%s\"[%d]",str.c_str(),i); + throw runtime_error(buf); + } + --i; + scale *= 16; + } + return ret; +} + +bool +expr_eval( + const string &str, + off_t &retval + ) +{ +// exprrestart(NULL); + expr_scan_string(str.c_str()); + expr_value = 0; + bool status = !exprparse(); + retval = expr_value; + return status; +} + + diff --git a/src/expr.y b/src/expr.y new file mode 100644 index 0000000..285ea8d --- /dev/null +++ b/src/expr.y @@ -0,0 +1,61 @@ +%{ +/* $Id: expr.y,v 1.2 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <iostream> + +#include <math.h> + +#include "expr.h" + +using namespace std; + +off_t expr_value; + +int exprlex(); + +static int exprerror( const char * ); + +%} + +%token NUMBER +%left '-' '+' '*' '/' + +%% +target : expr { + expr_value = $1; +} +; + +expr: /* nothing */ +| NUMBER { $$ = $1; } +| expr '+' expr { $$ = $1 + $3; } +| expr '-' expr { $$ = $1 - $3; } +| expr '*' expr { $$ = $1 * $3; } +| '(' expr ')' { $$ = $2; } +; + + +%% + +static int +exprerror( + const char * str + ) +{ + return 0; +} diff --git a/src/grid.cpp b/src/grid.cpp new file mode 100644 index 0000000..3f0dad8 --- /dev/null +++ b/src/grid.cpp @@ -0,0 +1,42 @@ +/* $Id: grid.cpp,v 1.1 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "grid.hpp" +#include <QGridLayout> +#include <QChildEvent> + +grid::grid( int cols, QWidget* parent ) + : QWidget(parent), m_cols(cols), m_row(0), m_col(0) +{ + + setLayout( new QGridLayout(this) ); +} + +void grid::childEvent( QChildEvent* e ) +{ + if( e->added() && e->child()->isWidgetType() ) { + QWidget* w = dynamic_cast<QWidget*>(e->child()); + QGridLayout* l = dynamic_cast<QGridLayout*>(layout()); + l->addWidget(w,m_row,m_col); + ++m_col; + if( m_col >= m_cols ) { + m_col = 0; + ++m_row; + } + } +} diff --git a/src/grid.hpp b/src/grid.hpp new file mode 100644 index 0000000..d7cc89a --- /dev/null +++ b/src/grid.hpp @@ -0,0 +1,35 @@ +#ifndef LFHEX_GRID_HPP +#define LFHEX_GRID_HPP +/* $Id: grid.hpp,v 1.1 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <QWidget> + +class grid : public QWidget { +public: + grid( int cols, QWidget* parent ); + +protected: + void childEvent( QChildEvent *e ); + +protected: + int m_cols; + int m_row; + int m_col; +}; + +#endif diff --git a/src/hexEditor.cpp b/src/hexEditor.cpp new file mode 100755 index 0000000..48cfe8b --- /dev/null +++ b/src/hexEditor.cpp @@ -0,0 +1,1112 @@ +/* $Id: hexEditor.cpp,v 1.14 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <math.h> +#include <assert.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <algorithm> +#include <iostream> + +#include <QApplication> +#include <QMessageBox> +#include <QFileDialog> +#include <QProgressDialog> +#include <QPainter> +#include <QPixmap> +#include <QFocusEvent> +#include <QPaintEvent> +#include <QKeyEvent> +#include <QResizeEvent> +#include <QMouseEvent> + +#include "hexEditor.hpp" +#include "translate.hpp" +#include "local.h" + +extern int errno; + +HexEditor::HexEditor( QWidget * parent ) + : QWidget(parent) +{ + _cols = 5; + _rows = 10; + _charsPerByte = 2; + _base = 16; + _topLeft = 0; + _topMargin = _wordSpacing = 6; + _bytesPerWord = 1; + _lastValidWord = -1; + _selection[SelectionStart] = _selection[SelectionEnd] = -1; + + setFocusPolicy(Qt::StrongFocus); + // the first setBytesPerWord should not come before the first setFont() + QFont font("fixed"); + font.setFixedPitch(1); + setFont( font ); + setBackgroundRole( QPalette::Base ); +} + +HexEditor::~HexEditor() +{ + _reader.close(); +} + +bool HexEditor::isModified() const +{ + return ( _reader.is_open() && _delta.numEdits() ); +} + +bool HexEditor::save( QString filename ) +{ + if( !isModified() ) { + QString errMsg = "Error, file is not open or has not been modified. " + "Aborting save."; + QMessageBox::warning(this,PROGRAM_STRING,errMsg); + return false; + } + + if( filename != "" ) { + // copy open reader file to filename + QString oldFilename = _reader.filename(); + + if( oldFilename == "" ) + return false; + + _reader.close(); + FILE* fin = fopen(C_STR(oldFilename),"r"); + if( !fin ) { + QString errMsg = "Error opening \"" + oldFilename + "\" for reading: " + + strerror(errno); + QMessageBox::warning(this,PROGRAM_STRING,errMsg); + return false; + } + FILE* fout = fopen(C_STR(filename),"w"); + if( !fout ) { + QString errMsg = "Error opening \"" + filename+ "\" for writing: " + + strerror(errno); + QMessageBox::warning(this,PROGRAM_STRING,errMsg); + fclose(fin); + return false; + } + int length; + uchar bytes[4096]; + while( (length = fread(bytes,1,4096,fin)) ) { + fwrite( bytes, 1, length, fout ); + } + fclose(fin); + fclose(fout); + } else { + filename = _reader.filename(); + _reader.close(); + } + + if( filename == "" ) + return false; + + if( !_delta.numEdits() ) + return false; + + if( !writeDeltas(C_STR(filename),_delta) ) { + _reader.open(C_STR(filename)); + return false; + } + _delta.clear(); + _reader.open(C_STR(filename)); + setTopLeft(_topLeft); + return true; +} + +QString HexEditor::filename() const +{ + return _reader.filename(); +} + +bool HexEditor::open( const QString & filename ) +{ + if( closeFile() == QMessageBox::Cancel ) + return false; + + if(!_reader.open(C_STR(filename))) { + QMessageBox::critical( this, "HexEdit", + "Error loading \"" + filename + "\"\n" + + _reader.lastError(), + QMessageBox::Ok,0); + return false; + } + _delta.clear(); // reset modification tree + + // set the new range for the scrollbar + _cursor.setRange(0,_reader.size()); + _cursor.setCharsPerByte(_charsPerByte); + setSelection(SelectionStart,-1); + setSelection(SelectionEnd,-1); + emit rangeChanged(0,_reader.size()/bytesPerLine()); + calculateFontMetrics(); // update labels + setTopLeft(0); // reset the GUI + return true; +} + +int HexEditor::closeFile(bool force) +{ + int retval = QMessageBox::No; + if( _delta.numEdits() ) { + QString message = + "Save changes to \"" + QString(_reader.filename()) + "\"?"; + if( force ) { + retval = QMessageBox::warning( this, + PROGRAM_STRING, + message, + QMessageBox::Yes, + QMessageBox::No ); + } else { + retval = QMessageBox::warning( this, + PROGRAM_STRING, + message, + QMessageBox::Yes, + QMessageBox::No, + QMessageBox::Cancel); + } + } + if( retval == QMessageBox::Yes ) + save(); + return retval; +} + +void HexEditor::setBytesPerWord( int nbytes ) +{ + _bytesPerWord = nbytes; + calculateFontMetrics(); + QResizeEvent *re = new QResizeEvent(QSize(size()),QSize(size())); + resizeEvent(re); + delete re; +} +int HexEditor::fontHeight() const +{ + return _fontHeight; +} +int HexEditor::lineSpacing() const +{ + return _lineSpacing; +} +int HexEditor::fontMaxWidth() const +{ + return _fontMaxWidth; +} +void HexEditor::calculateFontMetrics() +{ + _lineSpacing = fontMetrics().lineSpacing(); + _fontMaxWidth = fontMetrics().maxWidth(); + _wordWidth = _fontMaxWidth*charsPerWord(); + _fontHeight = fontMetrics().height(); + // see how many bytes are needed to show the size of this file + // log base 16 -> log16(x) = log(x)/log(16) + if( _reader.size() ) { + double width = log(static_cast<float>(_reader.size()))/log(16.0)+2; + _offsetLabelBytes = static_cast<int>( width ); + } else { + _offsetLabelBytes = 0; + } + _leftMargin = _topMargin + _fontMaxWidth*(_offsetLabelBytes + 2); + // make sure bboxes are updated with new offset subdivision + QResizeEvent *re = new QResizeEvent(QSize(size()),QSize(size())); + resizeEvent(re); + delete re; +} +void HexEditor::setFont(const QFont& font ) +{ + if( !font.fixedPitch() ) { + cerr << "setFont() failed, font was not fixedPitch()." << endl; + return; + } + QWidget::setFont(font); + calculateFontMetrics(); +} +// set the top left editor to offset in reader +void HexEditor::setTopLeft( off_t offset ) +{ + static bool inTopLeft; + if( inTopLeft ) { + // don't nest + return; + } + inTopLeft = true; + try { + if( offset < 0 ) { + _topLeft = 0; + } else if( offset > _reader.size() ) { + _topLeft = _reader.size(); + } else { + _topLeft = offset; + } + // only let _topLeft be an integer multiple of the line length (round down) + _topLeft = (_topLeft/bytesPerLine()) * bytesPerLine(); + // update the labels + // setOffsetLabels(_topLeft); + + const Delta * delta; + + _reader.seek(_topLeft); + _reader.read(_data,bytesPerPage()); + + // update data from delta map + for( offset = _delta.lower_bound(_topLeft); + (offset != -1) && (offset < _topLeft + bytesPerPage()); + offset = _delta.lower_bound(offset) ) { + delta = _delta.search(offset); + _data[offset++-_topLeft] = delta->newData()[0]; + } + + repaint(); + emit topLeftChanged(_topLeft); + } catch( const exception &e ) { + inTopLeft = false; + throw e; + } + inTopLeft = false; +} + +//void HexEditor::setOffsetLabels( off_t topLeft ) +//{ + // need to impliment manually printing labels +//} + +int HexEditor::topMargin() const +{ + return _topMargin; +} +int HexEditor::leftMargin() const +{ + return _leftMargin; +} +// +// access fn's for offset manip +// +int HexEditor::bytesPerPage() const +{ + return _rows*_cols*bytesPerWord(); +} +int HexEditor::bytesPerWord() const +{ + return _bytesPerWord; +} +int HexEditor::bytesPerLine() const +{ + return bytesPerWord()*wordsPerLine(); +} +int HexEditor::wordsPerLine() const +{ + return _cols; +} +int HexEditor::linesPerPage() const +{ + return _rows; +} +int HexEditor::wordsPerPage() const +{ + return _rows*_cols; +} +int HexEditor::charsPerByte() const +{ + return _charsPerByte; +} +int HexEditor::charsPerWord() const +{ + return _charsPerByte*bytesPerWord(); +} +int HexEditor::charsPerLine() const +{ + return _charsPerByte*(bytesPerLine()); +} +// translate local byte offsets to global byte offsets +off_t HexEditor::globalOffset( off_t local ) const +{ + return local+_topLeft; +} +// translate global byte offsets to viewport byte offsets +off_t HexEditor::localOffset( off_t global ) const +{ + return global-_topLeft; +} + +int HexEditor::offsetToPercent( + off_t offset + ) +{ + // round up + return _reader.size() ? (int)ceil(100.0*offset/_reader.size()) : 0; +} + +// public slots: +bool HexEditor::browseLoadFile() +{ + QString filename = QFileDialog::getOpenFileName(); + if( filename.isNull() ) + return false; + return open(filename); +} + +QRect HexEditor::charBBox( off_t charIdx ) const { + // byteIdx = charIdx/charsPerByte + // wordIdx = byteIdx/bytesPerWord + int wordIdx = (charIdx/charsPerByte())/bytesPerWord(); + int localCharIdx = charIdx % charsPerWord(); + return QRect( _wordBBox[wordIdx].left() + localCharIdx*fontMaxWidth() + + wordSpacing()/2, + _wordBBox[wordIdx].top(), + fontMaxWidth(), + fontHeight() ); +} + +QRect HexEditor::byteBBox( off_t byteIdx ) const { + // wordIdx = byteIdx/bytesPerWord + int wordIdx = byteIdx/bytesPerWord(); + int localByteIdx = byteIdx % bytesPerWord(); + return QRect( _wordBBox[wordIdx].left() + localByteIdx*2*fontMaxWidth() + + wordSpacing()/2, + _wordBBox[wordIdx].top(), + fontMaxWidth()*2, + lineSpacing() ); +} + +void HexEditor::setTopLeftToPercent( int percent ) +{ + setTopLeft( (_reader.size()/100)*percent ); +} + +// +// slot for setting cursor offset. +// +void HexEditor::setOffset( off_t offset ) +{ + off_t oldWordOffset = localWordOffset(); + _cursor.setOffset( offset, 0 ); + // updateWord clamps the wordIdx to [0,_rows*_cols) + updateWord( oldWordOffset ); + emit offsetChanged( _cursor.byteOffset() ); +} + +void HexEditor::nextLine() +{ + setTopLeft(_topLeft+bytesPerLine()); +} +void HexEditor::prevLine() +{ + setTopLeft(_topLeft-bytesPerLine()); +} +void HexEditor::nextPage() +{ + setTopLeft(_topLeft+bytesPerPage()); +} +void HexEditor::prevPage() +{ + setTopLeft(_topLeft-bytesPerPage()); +} + +off_t HexEditor::localByteOffsetAtXY(off_t x, off_t y) +{ + off_t wordIdx; + off_t wordLength = wordSpacing()+wordWidth(); + off_t line = min(y/lineSpacing(),(off_t)linesPerPage()); + + // constrain x to be less than the right side of the last char on a line + x = max( (off_t)0, x - leftMargin()); + x = min(wordsPerLine()*wordLength - 1 ,x); + // constrain y to be > topMargin() and less than bottom of last line + y = max( (off_t)0, y - topMargin()); + line = min(y/lineSpacing(), (off_t)linesPerPage()-1); + wordIdx = line*wordsPerLine() + x/wordLength; + + off_t byteOffsetInWord = (x%wordLength)*bytesPerWord()/wordLength; + // = wordIdx*bytesPerWord + byteOffsetInWord + return min( (off_t) bytesPerPage()-1, + wordIdx*bytesPerWord() + byteOffsetInWord); + +} +// +// event handler implimentation: +// +void HexEditor::setCursorFromXY(int x,int y) +{ + off_t oldWordIdx = localWordOffset(); + + _cursor.setOffset( _topLeft+localByteOffsetAtXY(x,y) ,0 ); + + // update where the cursor used to be, and where it is now + if( oldWordIdx != localWordOffset() ) { + updateWord( oldWordIdx ); + } + updateWord( localWordOffset() ); + emit offsetChanged(_cursor.byteOffset()); +} + +void HexEditor::mousePressEvent( QMouseEvent* e ) +{ + setCursorFromXY(e->x(),e->y()); + + off_t byte_offset = localByteOffset(); + QRect bbox = byteBBox(byte_offset); + if( e->x() > bbox.right() ) { + byte_offset++; + } + setSelection( SelectionStart, globalOffset( byte_offset )); +} + +void HexEditor::mouseMoveEvent( QMouseEvent* e ) +{ + setCursorFromXY(e->x(),e->y()); + + off_t byte_offset = localByteOffset(); + QRect bbox = byteBBox(byte_offset); + if(e->x() > bbox.right() ) { + byte_offset++; + } + + setSelection( SelectionEnd, globalOffset( byte_offset )); +} + +void HexEditor::mouseReleaseEvent( QMouseEvent* e ) +{ + setCursorFromXY(e->x(),e->y()); + + off_t byte_offset = localByteOffset(); + QRect bbox = byteBBox(byte_offset); + if(e->x() > bbox.right() ) { + byte_offset++; + } + + setSelection( SelectionEnd, globalOffset( byte_offset )); +} + +off_t HexEditor::selectionStart() const +{ + if( _selection[SelectionStart] == -1 || _selection[SelectionEnd] == -1 ) + return -1; + return min(_selection[SelectionStart],_selection[SelectionEnd]); +} +// note: end is open. range is: [start,end) + +off_t HexEditor::selectionEnd() const +{ + if( _selection[SelectionStart] == -1 || _selection[SelectionEnd] == -1 ) + return -1; + return max(_selection[SelectionStart],_selection[SelectionEnd]); +} + +void HexEditor::setSelection(SelectionPos_e pos, off_t offset) +{ + if( !_reader.is_open() ) { + return; + } + if( pos == SelectionStart ) { + _selection[SelectionEnd] = -1; + } + _selection[pos] = offset; + + if( _selection[SelectionStart] < 0 ) { + emit selectionChanged(""); + } else { + if( selectionEnd() > -1 && selectionEnd() <= _reader.size() ) { + QString data; + const Delta* delta; + for(off_t i = selectionStart(); + i < selectionEnd(); + ++i) { + if( (delta = _delta.search(i)) ) + data += Translate::ByteToHex(delta->newData()[0]); + else + data += Translate::ByteToHex(_reader[i]); + } + emit selectionChanged( data ); + } else { + emit selectionChanged( "" ); + } + } + + repaint(); +} + +// +// Editor implimentation +// +void HexEditor::keyPressEvent( QKeyEvent *e ) +{ + int key = e->key(); + + switch(_base) { + case -1: + // ascii + // range is taken from qnamespace.h + if( key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde ) { + seeCursor(); + vector<uchar> oldData; + vector<uchar> newData; + vector<uchar> chars; + + oldData.push_back( *(_data.begin()+localByteOffset()) ); + Translate::ByteToChar(chars,oldData); + chars[0] = key; + Translate::CharToByte(newData,chars); + _delta.insert( _cursor.byteOffset(), + oldData, + newData); + _data[_cursor.byteOffset()-_topLeft] = newData[0]; + cursorRight(); + setSelection(SelectionStart,-1); + return; + } + break; + case 16: + if ( key >= 'A' && key <= 'F' ) { + key = tolower(key); + } + if ( (key >= 'a' && key <= 'f') || + (key >= '0' && key <= '9') ) { + // + // make sure we can see where the cursor is + // + seeCursor(); + vector<uchar> oldData; + vector<uchar> newData; + vector<uchar> hex; + + oldData.push_back( *(_data.begin()+localByteOffset()) ); + Translate::ByteToHex(hex,oldData); + hex[_cursor.charOffset()] = key; + Translate::HexToByte(newData,hex); + + _delta.insert( _cursor.byteOffset(), + oldData, + newData ); + _data[_cursor.byteOffset()-_topLeft] = newData[0]; + // move to the next char + cursorRight(); + setSelection(SelectionStart,-1); + return; + } + break; + case 8: + if( key >= '0' && key < '8' ) { + // valid octal key + seeCursor(); + vector<uchar> oldData; + vector<uchar> newData; + vector<uchar> octal; + + oldData.push_back( *(_data.begin()+localByteOffset()) ); + Translate::ByteToOctal(octal,oldData); + octal[_cursor.charOffset()] = key; + Translate::OctalToByte(newData,octal); + + _delta.insert( _cursor.byteOffset(), + oldData, + newData ); + _data[_cursor.byteOffset()-_topLeft] = newData[0]; + cursorRight(); + setSelection(SelectionStart,-1); + return; + } + break; + case 2: + if( key >= '0' && key < '2' ) { + // valid binary key + seeCursor(); + vector<uchar> oldData; + vector<uchar> newData; + vector<uchar> binary; + + oldData.push_back( *(_data.begin()+localByteOffset()) ); + Translate::ByteToBinary(binary,oldData); + binary[_cursor.charOffset()] = key; + Translate::BinaryToByte(newData,binary); + + _delta.insert( _cursor.byteOffset(), + oldData, + newData ); + _data[_cursor.byteOffset()-_topLeft] = newData[0]; + cursorRight(); + setSelection(SelectionStart,-1); + return; + } + break; + } + switch ( e->key() ) { + case Qt::Key_Left: + cursorLeft(); + break; + case Qt::Key_Right: + cursorRight(); + break; + case Qt::Key_Up: + cursorUp(); + break; + case Qt::Key_Down: + cursorDown(); + break; + case Qt::Key_PageUp: + prevPage(); + break; + case Qt::Key_PageDown: + nextPage(); + break; + case Qt::Key_End: + setTopLeft( _reader.size() - bytesPerPage()/2 ); + break; + case Qt::Key_Home: + setTopLeft(0); + break; + default: + e->ignore(); + break; + } +} + +void HexEditor::resizeEvent( QResizeEvent * e ) +{ + int height= lineSpacing(); + int totalWordWidth = wordWidth() + wordSpacing(); + int linewidth = e->size().width(); + + // don't let _rows or _cols drop below 1 + _rows = max(1,(e->size().height() - _topMargin)/height); + _cols = max(1,(e->size().width() - _leftMargin)/totalWordWidth); + + // now update the line && word bbox vectors + _lineBBox.reserve(_rows); + _wordBBox.reserve(_rows*_cols); + int top,left; + for(int r = 0; r < _rows; r++) { + top = r*height + _topMargin; + for(int c = 0; c < _cols; c++) { + left = totalWordWidth*c + _leftMargin; + _wordBBox[r*_cols+c] = QRect(left, //left + top, //top + totalWordWidth, //width + height); //height + } + _lineBBox[r] = QRect(_leftMargin,top,linewidth,height); + } + // calculate offset label bounding box + _labelBBox.setRect(0, // x + 0, // y + _leftMargin, // width + e->size().height()); // height + + // do this to recalculate the amount of displayed data. + setTopLeft(_topLeft); + emit rangeChanged(0,_reader.size()/bytesPerLine()); +} +// +// Reimplimented to be more efficient then repainting the whole screen on +// focus events. +// +void HexEditor::focusInEvent( QFocusEvent* ) +{ + updateWord( localWordOffset() ); +} +void HexEditor::focusOutEvent( QFocusEvent* ) +{ + updateWord( localWordOffset() ); +} +// generate's paint events for wordIdx (global wordIdx) +// is safe to call with any wordIdx +void HexEditor::updateWord( off_t wordIdx ) +{ + if( wordIdx > -1 && wordIdx < _rows*_cols ) + repaint(_wordBBox[wordIdx]); +} + +void HexEditor::paintLabels( QPainter* paintPtr) +{ + // ignore redraw range for first aproximation: + int y = _wordBBox[0].bottom(); + unsigned int i; + off_t offset = _topLeft; + uchar *ucptr; + QString label; + + for(int row = 0; row < _rows;++row) { + label = ""; +#ifdef WORDS_BIGENDIAN + for(i=0, ucptr = (uchar*)&offset; i<sizeof(off_t);++i) { + label += Translate::ByteToHex(*ucptr++); + } +#else + // make sure we write offset labels in big-endian (easier to read) + ucptr = (uchar*)(&offset) + sizeof(off_t)-1; + for(i=0;i<sizeof(off_t);++i) { + label += Translate::ByteToHex(*ucptr--); + } +#endif + label = label.mid(sizeof(off_t)*2-_offsetLabelBytes); + paintPtr->drawText( 5, y, label ); + offset+=bytesPerLine(); + y+=lineSpacing(); + } + // draw dividing line between offset labels and data + int x = leftMargin()-fontMaxWidth(); + paintPtr->drawLine(x,topMargin(), + x,height()-topMargin()); +} +// +// painting optimizations, each time resize is called, it calculates +// the bounding boxes for each word and each line. +// This data can then be retrieved with wordBBox() +// We can then test intersections to see which words need to be redrawn +// +void HexEditor::paintEvent( QPaintEvent* e) +{ +/* QPixmap pixmap(this->width(),this->height()); + pixmap.fill(backgroundRole());*/ + QPainter paint( this );//&pixmap); + + // set up painter;/ + paint.setFont(font()); + const QPalette& p = qApp->palette(); + paint.setBrush(p.background()); + + if( _labelBBox.intersects(e->rect()) ) { + paintLabels(&paint); + } + + QString text; + if( !getDisplayText(text) ) { + cerr << "[error] - internal inconsitency. Please file bug report." + << endl; + return; + } + + // both cursor and selection is drawn underneath the text + drawCursor( paint ); + drawSelection( paint ); + + // Find the stop/start row/col idx's for the repaint + int totalWordWidth = wordWidth()+wordSpacing(); + int row_start = max(0,(e->rect().top()-topMargin())/lineSpacing() ); + int col_start = max(0,(e->rect().left()-leftMargin())/totalWordWidth); + int row_stop = min(_rows-1,e->rect().bottom() / lineSpacing()); + int col_stop = min(_cols-1,e->rect().right() / totalWordWidth); + + // draw text in repaint event + drawTextRegion( paint, text, row_start, row_stop, col_start, col_stop ); +} + +bool HexEditor::getDisplayText( QString& text ) +{ + // get data to draw + switch (_base) { + case 16: + Translate::ByteToHex(text,_data); + break; + case 8: + Translate::ByteToOctal(text,_data); + break; + case 2: + Translate::ByteToBinary(text,_data); + break; + case -1: + Translate::ByteToChar(text,_data); + break; + default: + // error state + return false; + } + return true; +} + +bool HexEditor::wordModified ( off_t wordIdx ) const +{ + off_t lboffset = wordIdx*bytesPerWord()+_topLeft; + off_t nearest_offset = _delta.lower_bound(lboffset); + return ( nearest_offset != -1 && nearest_offset < lboffset+bytesPerWord() ); +} + +// +// accessors for local offsets +// +off_t HexEditor::localByteOffset() const +{ + return _cursor.byteOffset() - _topLeft; +} +off_t HexEditor::localWordOffset() const +{ + return localByteOffset()/bytesPerWord(); +} +// in offset relative to _data[0] +off_t HexEditor::localCharOffset() const +{ + return localByteOffset()*charsPerByte() + _cursor.charOffset(); +} +off_t HexEditor::localLineOffset() const +{ + return localWordOffset()/wordsPerLine(); +} +int HexEditor::wordWidth() const +{ + return _fontMaxWidth*charsPerWord(); +} +int HexEditor::wordSpacing() const +{ + return _wordSpacing; +} +// +// cursor movement members +// +void HexEditor::seeCursor() +{ + // see if it is already visible + if ( _cursor.byteOffset() >= _topLeft && + _cursor.byteOffset() <= _topLeft+bytesPerPage()-1 ) { + updateWord( localWordOffset() ); + return; + } else { + // setTopLeft so cursor is in middle line of screen + setTopLeft( max(_cursor.byteOffset() - bytesPerPage()/2, (off_t)0) ); + } +} + +void HexEditor::cursorLeft() +{ + off_t oldWordIdx = localWordOffset(); + // move the cursor + _cursor.decrByChar(1); + // make sure the user can see the cursor + seeCursor(); + // redraw where the cursor used to be + if( localWordOffset() != oldWordIdx ) + updateWord( oldWordIdx ); + emit offsetChanged( _cursor.byteOffset() ); +} +void HexEditor::cursorRight() +{ + off_t oldWordIdx = localWordOffset(); + _cursor.incrByChar(1); + seeCursor(); + if( localWordOffset() != oldWordIdx ) + updateWord( oldWordIdx ); + emit offsetChanged( _cursor.byteOffset() ); +} +void HexEditor::cursorUp() +{ + off_t oldWordIdx = localWordOffset(); + _cursor.decrByByte( bytesPerLine() ); + seeCursor(); + if( localWordOffset() != oldWordIdx ) + updateWord( oldWordIdx ); + emit offsetChanged( _cursor.byteOffset() ); +} +void HexEditor::cursorDown() +{ + off_t oldWordIdx = localWordOffset(); + _cursor.incrByByte( bytesPerLine() ); + seeCursor(); + if( localWordOffset() != oldWordIdx ) + updateWord( oldWordIdx ); + emit offsetChanged( _cursor.byteOffset() ); +} + +// slots for undo/redo. +// note: it is necessary to reset topLeft to force a reread of the data. +// +void HexEditor::redo() +{ + _delta.redo(); + setTopLeft(_topLeft); + off_t start = selectionStart(); + off_t end = selectionEnd(); + setSelection(SelectionStart,start); + setSelection(SelectionEnd,end); +} + +void HexEditor::undo() +{ + _delta.undo(); + setTopLeft(_topLeft); + off_t start = selectionStart(); + off_t end = selectionEnd(); + setSelection(SelectionStart,start); + setSelection(SelectionEnd,end); +} + +void HexEditor::search( const QString& hexText, bool forwards ) +{ + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + if( !hexText.length() || _reader.filename() == "" ) + return; + + if( -1 != _delta.lower_bound(0) ) { + QMessageBox::information(this,PROGRAM_STRING, + "Cannot search file with unsaved modifications."); + return; + } + + vector<uchar> data; + Translate::HexToByte(data,hexText); +// QProgressDialog progress( "Searching...","Cancel", 0, +// _reader.size(),this ); +// progress.setWindowModality( Qt::WindowModal ); +// progress.setWindowTitle(PROGRAM_STRING); +// progress.setValue(0); + off_t pos; + if( forwards ) { + pos = _reader.findIndex(_cursor.byteOffset(),data,_reader.size()-1); + } else { + pos = _reader.rFindIndex(_cursor.byteOffset(),data,0); + } + if( pos < _reader.size() ) { + showMatch(pos,data.size()); + setOffset( forwards?selectionEnd():selectionStart()-1 ); + seeCursor(); + } else { + QMessageBox::information(this,PROGRAM_STRING, + "Could not find search data 0x" + hexText); + } + QApplication::restoreOverrideCursor(); +} +void HexEditor::setBaseASCII() { + setBase(-1); +} +void HexEditor::setBaseHex() +{ + setBase(16); +} +void HexEditor::setBaseOctal() +{ + setBase(8); +} +void HexEditor::setBaseBinary() +{ + setBase(2); +} +void HexEditor::setBase(int base) +{ + switch(base) { + case -1: + // setup ascii editing mode + _charsPerByte = 1; + break; + case 2: + // setup binary editing mode + _charsPerByte = 8; + break; + case 8: + // setup octal editing mode + _charsPerByte = 3; + break; + case 16: + // setup hex editing mode + _charsPerByte = 2; + break; + default: + // just ignore unsupported bases for now + return; + } + _base = base; + _cursor.setCharsPerByte(_charsPerByte); + // refresh the display + // note: cannot call resize() because it will ignore resize events + // if the size has not changed. + QResizeEvent *re = new QResizeEvent(QSize(size()),QSize(size())); + resizeEvent(re); + delete re; + // make sure we can still see the cursor + // switching from a larger base to a smaller base has the + // possibility of pushing the cursor off the screen + seeCursor(); +} + +off_t HexEditor::offset() const +{ + return _cursor.byteOffset(); +} + +Reader * HexEditor::reader() +{ + return &_reader; +} + +void HexEditor::showMatch( off_t pos, int len ) +{ + setSelection( SelectionStart, pos ); + setSelection( SelectionEnd, pos + len ); +} + +void HexEditor::drawTextRegion( QPainter& paint, const QString& text, + int row_start, int row_stop, + int col_start, int col_stop ) +{ + paint.setPen(qApp->palette().foreground().color()); + for(int r = row_start; r <= row_stop; r++) { + for(int c = col_start; c <= col_stop; c++) { + int widx = r*_cols+c; + if ( wordModified( widx ) ) { + paint.setPen(qApp->palette().link().color()); + paint.drawText( _wordBBox[widx].left() + wordSpacing()/2, + _wordBBox[widx].bottom(), + text.mid(widx*charsPerWord(),charsPerWord()) ); + paint.setPen(qApp->palette().foreground().color()); + } else { + paint.drawText( _wordBBox[widx].left() + wordSpacing()/2, + _wordBBox[widx].bottom(), + text.mid(widx*charsPerWord(),charsPerWord()) ); + } + } + } +} + +void HexEditor::drawSelection( QPainter& paint ) +{ + // draw selection + off_t start = max( (off_t)0, selectionStart() - _topLeft); + if( start < bytesPerPage() ) { + off_t stop = min(selectionEnd() - _topLeft, (off_t)bytesPerPage()); + paint.setPen(Qt::NoPen); + paint.setBrush( qApp->palette().highlight() ); + // foreach line with selection + stop--; + while( start <= stop ) { + // linestop = min(stop,endofline) + off_t linestop = + min(stop, start+bytesPerLine()-1 -(start % bytesPerLine())); + QRect bbox = byteBBox(start); + bbox.setRight( byteBBox(linestop).right() ); + paint.drawRect( bbox ); + start = linestop+1; + } + } +} + +void HexEditor::drawCursor( QPainter& paint ) +{ + QBrush b = qApp->palette().mid(); + if( localWordOffset() > -1 && localWordOffset() < wordsPerPage() ) { + if( hasFocus() ) { + // draw a solid cursor + paint.setPen(Qt::NoPen); + paint.setBrush(b); + } else { + // just draw the outline + paint.setPen(b.color()); + paint.setBrush(Qt::NoBrush); + } + QRect box = charBBox( localCharOffset() ); + paint.drawRect( box ); + } +} diff --git a/src/hexEditor.hpp b/src/hexEditor.hpp new file mode 100755 index 0000000..be96952 --- /dev/null +++ b/src/hexEditor.hpp @@ -0,0 +1,242 @@ +/* $Id: hexEditor.hpp,v 1.7 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _HEX_EDITOR_ +#define _HEX_EDITOR_ + +#include <QMouseEvent> +#include <QFocusEvent> +#include <QResizeEvent> +#include <QKeyEvent> +#include <QPaintEvent> +#include <QWidget> + +// STL headers +#include <vector> + +// System headers +#include <sys/types.h> + +// Local headers +#include "local.h" +#include "reader.hpp" +#include "delta.hpp" +#include "cursor.hpp" +#include "save.hpp" + +class HexEditor : public QWidget { + Q_OBJECT +public: + HexEditor( QWidget * parent =0 ); + ~HexEditor(); + + // note: closeFile returns QMessageBox::{Yes,No,Cancel} + int closeFile(bool force = false ); + bool open(const QString& filename); + // becomes "save as" if filename != "" + bool save(QString filename = ""); + bool isModified() const; + QString filename() const; + Reader * reader(); + off_t offset() const; + + + // returns the word (string representation) that the cursor is in + // QString currentWord() const; + // + // cursor movement related fn's + // + void seeCursor(); + void cursorLeft(); + void cursorRight(); + void cursorUp(); + void cursorDown(); + int wordWidth() const; + int wordSpacing() const; + void setCursorFromXY(int x,int y); + +public: + enum SelectionPos_e { + SelectionStart, + SelectionEnd, + }; + void setSelection(SelectionPos_e pos,off_t byte_offset); + off_t selectionStart() const; + off_t selectionEnd() const; + // get the char offset from topleft of the point (x,y) + // Note: this wont work for large files, off_t is 2*size() at eof for hex + //off_t charOffsetAtXY( off_t x, off_t y ); + int offsetToPercent( off_t offset ); + + off_t localByteOffsetAtXY( off_t x, off_t y ); +protected: + // accessors for local offset's + // note: returned offset's are not necessarily visible + off_t localByteOffset() const; + off_t localWordOffset() const; + off_t localCharOffset() const; + off_t localLineOffset() const; + +signals: + // attach to know when line ranges change (for a scrollbar) + void rangeChanged(off_t low, off_t high); + void offsetChanged(off_t byte); + void topLeftChanged(off_t offset); + void selectionChanged(const QString& selection); + +public slots: + bool browseLoadFile(); + void setOffset(off_t offset); // sets cursor offset + void setTopLeftToPercent( int percent ); // for setting pos from scroll + // + // slots for setting the number of bytes per column + // I really should change all references of "bytesPerWord" to "bytesPerCol" + // sorry for the confusion -Salem + // + void setBytesPerWord( int i ); + void set1BPC() { setBytesPerWord(1); }; + void set2BPC() { setBytesPerWord(2); }; + void set4BPC() { setBytesPerWord(4); }; + void set8BPC() { setBytesPerWord(8); }; + void nextLine(); + void prevLine(); + void nextPage(); + void prevPage(); + void setFont(const QFont& font); + void undo(); + void redo(); + void search(const QString& hexText, bool forwards); + void setBase(int base); // only 2 8 16 acceptableO + void setBaseHex(); + void setBaseOctal(); + void setBaseBinary(); + void setBaseASCII(); + +protected: + // void setOffsetLabels( off_t topLeft ); + void setTopLeft( off_t offset ); + +protected: + bool wordModified( off_t widx ) const; + // template setWord so I can call it with different types of string data + template <class _vectType> + void setWord( off_t wordIdx, const _vectType& str ); + // calculate the rectangle which bounds the word at _offset+idx + QRect charBBox( off_t charIdx ) const; + QRect byteBBox( off_t byteIdx ) const; + + // translate widget coord to word index + int pointToWord(const QPoint& pt); + QChar& pointToChar(const QPoint& pt); + // inlined access fn's +protected: + void calculateFontMetrics(); + int charsPerByte() const; + int charsPerWord() const; + int charsPerLine() const; + int bytesPerPage() const; + int bytesPerWord() const; + int bytesPerLine() const; + int wordsPerLine() const; + int wordsPerPage() const; + int linesPerPage() const; + + int lineSpacing() const; + int fontHeight() const; + int fontMaxWidth() const; + int topMargin() const; + int leftMargin() const; + + // translate local offset to global offset + off_t globalOffset( off_t local ) const; + // translate global offset to local offset. + // Note: globalOffset may not exist in local viewport. + off_t localOffset ( off_t global) const; + +protected: + void showMatch( off_t pos, int len ); + // drawing utilities +protected: + bool getDisplayText( QString& text ); + void drawCursor( QPainter& p ); + void drawSelection( QPainter& p ); + void drawTextRegion( QPainter& p, const QString& text, + int row_start, int row_end, + int col_start, int col_end ); + // event handlers +protected: + void resizeEvent ( QResizeEvent *e ); + // generates update() events for the bbox for the word given byh wordIdx + // note: this is range safe, no need to do range checking before passing in + void updateWord ( off_t wordIdx ); + void paintEvent ( QPaintEvent*e ); + void paintLabels ( QPainter*painter); + void focusInEvent ( QFocusEvent*e ); + void focusOutEvent ( QFocusEvent*e ); + void keyPressEvent ( QKeyEvent *e ); + void mousePressEvent ( QMouseEvent * e ); + void mouseReleaseEvent( QMouseEvent *e ); + void mouseMoveEvent ( QMouseEvent *e ); + +protected: + Reader _reader; + + int _wordSpacing; + int _wordWidth; + int _lineSpacing; + int _fontHeight; + int _bytesPerWord; + int _charsPerByte; + off_t _topLeft; + + // + // current screen data info + // + vector<uchar> _data; + int _base; // either 2 8 or 16 + + off_t _lastValidWord; + + // data used to optimize drawing. + vector<QRect> _lineBBox; + vector<QRect> _wordBBox; + QRect _labelBBox; + + int _linspacing; + int _fontMaxWidth; + + int _topMargin,_leftMargin; + int _offsetLabelBytes; + + int _cols; + int _rows; + int _width; + Cursor _cursor; + + // + // when refering to the offset of a word, I always mean the offset of the + // first byte of the word + // + + // this class keeps track of modifications + DeltaMap _delta; + + // selection: + off_t _selection[2]; +}; + +#endif diff --git a/src/hexGui.cpp b/src/hexGui.cpp new file mode 100644 index 0000000..a2cb65e --- /dev/null +++ b/src/hexGui.cpp @@ -0,0 +1,326 @@ +/* $Id: hexGui.cpp,v 1.13 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <QFileDialog> +#include <qsizepolicy.h> +#include <qstatusbar.h> +#include <qmenubar.h> +#include <qapplication.h> +#include <qscrollbar.h> +#include <qstring.h> +#include <qmessagebox.h> +#include <qlineedit.h> +#include <QDockWidget> +#include <QLabel> +#include <QCloseEvent> +#include <QPushButton> + +#include "hexGui.hpp" +#include "box.hpp" +#include "expr.h" + +HexGui::HexGui (QWidget * p) + : QMainWindow(p) +{ + QWidget* h = new QWidget(this); + QHBoxLayout* l = new QHBoxLayout(h); + + hexEditor = new HexEditor(h); + hexEditor->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, + QSizePolicy::Expanding ) ); + l->addWidget(hexEditor); + vsb = new QScrollBar(h); + l->addWidget(vsb); + vsb->setRange(0,0); + + setCentralWidget(h); + + connect( hexEditor,SIGNAL(rangeChanged(off_t,off_t)), + this,SLOT(setScrollBarRange(off_t,off_t)) ); + connect( vsb, SIGNAL(valueChanged(int)), + hexEditor,SLOT(setTopLeftToPercent(int)) ); + connect( hexEditor, SIGNAL(topLeftChanged(off_t)), + this, SLOT(setScrollBarValue(off_t)) ); + connect( hexEditor, SIGNAL(offsetChanged(off_t)), + this, SLOT(setOffsetLabel(off_t)) ); + + // setup dock + QDockWidget* dock = new QDockWidget("Conversions Assistant",this); + vbox* vb = new vbox(dock); + conversionDlg = new ConversionDlg(vb); + connect(conversionDlg,SIGNAL(nextPressed()),this,SLOT(searchForwards())); + connect(conversionDlg,SIGNAL(prevPressed()),this,SLOT(searchBackwards())); + + dock->setWidget(vb); + dock->hide(); + connect(hexEditor,SIGNAL(selectionChanged(const QString &)), + conversionDlg, SLOT(valueChanged(const QString&)) ); + addDockWidget( Qt::RightDockWidgetArea, dock ); + dock->setFloating(true); + + // setup menu: + fileMenu = new QMenu("&File",this); + fileMenu->addAction("&Open...",this,SLOT(browseLoadFile())); + fileMenu->addAction("&Open in new editor...",this, + SLOT(browseLoadFileNew())); + fileMenu->addSeparator(); + actions[SaveAction] = fileMenu->addAction("&Save",this,SLOT(save())); + actions[SaveAsAction] = fileMenu->addAction("Save &As...",this, + SLOT(saveAs())); + // only include close functions in menu if this is a toplevel window + if( isTopLevel() ) { + fileMenu->addSeparator(); + if( isTopLevel() ) + fileMenu->addAction("Close Editor",this,SLOT(close())); + else + fileMenu->addAction("Close File",this,SLOT(closeFile())); + fileMenu->addAction("&Exit Application",qApp, SLOT(quit())); + } + menuBar()->addMenu( fileMenu ); + + // edit pulldown + editMenu = new QMenu( "&Edit", this ); + actions[UndoAction] = editMenu->addAction("&Undo",hexEditor,SLOT(undo())); + actions[RedoAction] = editMenu->addAction("&Redo",hexEditor,SLOT(redo())); + menuBar()->addMenu( editMenu ); + + // view menu + viewMenu = new QMenu("&View",this); + QAction* dockAction = dock->toggleViewAction(); + viewMenu->addAction( dockAction ); + + // menu for selecting editing base (octal/binary/hex) + QMenu * baseMenu = new QMenu("&Editing base", this); + baseMenu->addAction("&Hex",hexEditor,SLOT(setBaseHex())); + baseMenu->addAction("&ASCII",hexEditor,SLOT(setBaseASCII())); + baseMenu->addAction("&Binary",hexEditor,SLOT(setBaseBinary())); + baseMenu->addAction("&Octal",hexEditor,SLOT(setBaseOctal())); + viewMenu->addMenu(baseMenu); + // menu for selecting bytes per column + QMenu * nbytesMenu = new QMenu("&Bytes per column",this); + nbytesMenu->addAction("&1",hexEditor,SLOT(set1BPC())); + nbytesMenu->addAction("&2",hexEditor,SLOT(set2BPC())); + nbytesMenu->addAction("&4",hexEditor,SLOT(set4BPC())); + nbytesMenu->addAction("&8",hexEditor,SLOT(set8BPC())); + viewMenu->addMenu(nbytesMenu); + menuBar()->addMenu(viewMenu); + + resize(400,196); + statusBar()->showMessage("Ready",2000); + statusBar()->addWidget(new QLabel("Cursor Offset:",statusBar())); + offsetLineEdit = new QLineEdit(statusBar()); +// offsetLineEdit->setValidator( new HexValidator(offsetLineEdit) ); + connect(offsetLineEdit,SIGNAL(returnPressed()), + SLOT(setOffsetFromStatusBar())); + statusBar()->addWidget(offsetLineEdit); + // progressBar = new QProgressBar(statusBar()); + // statusBar()->addWidget(progressBar,1,FALSE); + statusLabel = new QLabel("",statusBar()); + statusBar()->addWidget(statusLabel,1); + statusBar()->setSizeGripEnabled( !parent() ); + setWindowTitle(PROGRAM_STRING); + + // deactivate save,saveas undo and redo + actions[SaveAction]->setEnabled(false); + actions[SaveAsAction]->setEnabled(false); + actions[UndoAction]->setEnabled(false); + actions[RedoAction]->setEnabled(false); +} + +HexGui::~HexGui() +{ +} + +bool HexGui::open(const char * filename) +{ + if (hexEditor->open(filename)) { + if( isTopLevel() ) + setWindowTitle(filename); + else + statusLabel->setText(filename); + actions[SaveAction]->setEnabled(true); + actions[SaveAsAction]->setEnabled(true); + actions[UndoAction]->setEnabled(true); + actions[RedoAction]->setEnabled(true); + return true; + } else { + return false; + } +} + +void HexGui::gotoOffset(off_t offset) +{ + hexEditor->setOffset(offset); + hexEditor->seeCursor(); + emit offsetChanged(offset); +} + +bool HexGui::browseLoadFile() +{ + QString filename = QFileDialog::getOpenFileName(); + if( filename.isNull() ) + return false; + return open( C_STR(filename) ); +} +bool HexGui::browseLoadFileNew() +{ + QString filename = QFileDialog::getOpenFileName(); + if( filename.isNull() ) + return false; + HexGui * hg = new HexGui(); + bool retval = hg->open( C_STR(filename) ); + hg->show(); + return retval; +} + +bool HexGui::save() +{ + statusBar()->showMessage("saveing " + hexEditor->filename()) ; + bool retval = hexEditor->save(); + statusBar()->showMessage("done.",2000); + return retval; +} + +bool HexGui::saveAs() +{ + QString filename = QFileDialog::getSaveFileName(); + if( filename.isNull() ) + return false; + statusBar()->showMessage("saveing to \"" + filename + "\"..."); + bool retval = hexEditor->save(filename); + statusBar()->showMessage("done.",2000); + setWindowTitle(filename); + return retval; +} + +int HexGui::closeFile() +{ + return closeFile( false ); +} +int HexGui::closeFile( bool force ) +{ + return hexEditor->closeFile(force); +} + +void HexGui::closeEvent( QCloseEvent * ce ) +{ + if( hexEditor->closeFile() == QMessageBox::Cancel ) + ce->ignore(); + else + ce->accept(); +} + +void HexGui::setScrollBarRange(off_t low, off_t high) +{ + (void)low;(void)high; + // range must be contained in the space of an integer, just do 100 + // increments + vsb->setRange(0,100); +} +void HexGui::setScrollBarValue(off_t pos) +{ + // pos is the topLeft pos, set the scrollbar to the + // location of the last byte on the page + // Note: offsetToPercent now rounds up, so we don't + // have to worry about if this is the topLeft or bottom right + vsb->setValue(hexEditor->offsetToPercent(pos)); +} +void HexGui::setOffsetLabel(off_t pos) +{ + QString label; + char buffer[64]; +#if _LARGEFILE_SOURCE + sprintf(buffer,"0x%lx",pos); +#else + sprintf(buffer,"0x%x",pos); +#endif + label = buffer; + offsetLineEdit->setText(label); +} + +const QString& HexGui::filename(void) const +{ + static QString value = ""; + if(!hexEditor) + return (value=""); + return (value=hexEditor->filename()); +} + +void HexGui::setOffsetFromStatusBar() +{ + // remove leading "0x" if necessary + off_t o; + if( !expr_eval( C_STR(offsetLineEdit->text()),o ) || o < 0 ) { + QApplication::beep(); + } else { + gotoOffset(o); + } + return; + bool ok; + off_t offset; + QString value = offsetLineEdit->text(); + if( value.length() > 2 && value[1] == 'x' ) { + value = value.mid(2); + offset = value.toInt(&ok,16); + } else { + offset = value.toInt(&ok,10); + if( !ok ) { + offset = value.toInt(&ok,16); + } + } + if( !ok ) { + cerr << "Error converting offset: " << C_STR(offsetLineEdit->text()) + << endl; + } else { + gotoOffset(offset); + } +} + +off_t HexGui::offset() const +{ + return hexEditor->offset(); +} + +Reader * HexGui::reader() +{ + return hexEditor->reader(); +} + +void HexGui::setSelection(off_t start,off_t stop) +{ + hexEditor->setSelection(HexEditor::SelectionStart,start); + hexEditor->setSelection(HexEditor::SelectionEnd,stop); +} + +void HexGui::search( bool forward ) +{ + QString hex = conversionDlg->hexValue(); + if( !hex.isEmpty() ) { + hexEditor->search( hex, forward ); + } +} + +void HexGui::searchForwards() +{ + search(true); +} + +void HexGui::searchBackwards() +{ + search(false); +} diff --git a/src/hexGui.hpp b/src/hexGui.hpp new file mode 100644 index 0000000..d90a4c5 --- /dev/null +++ b/src/hexGui.hpp @@ -0,0 +1,97 @@ +/* $Id: hexGui.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _GUI_HPP_ +#define _GUI_HPP_ + +#include <QMainWindow> +#include <QLabel> +#include <QCloseEvent> + +#include "hexEditor.hpp" +#include "conversionDlg.hpp" +#include "local.h" + +class QScrollBar; +class QMenu; +class QString; +class QLabel; +//class QProgressBar; + +class HexGui : public QMainWindow { + Q_OBJECT +public: + HexGui( QWidget * parent = 0 ); + ~HexGui(); + + const QString& filename(void) const; + // see through call to isModified in hexEditor + bool isModified() const {return hexEditor->isModified();} + // public access functions + off_t offset() const; + Reader * reader(); + +signals: + void offsetChanged(off_t offset); + +public slots: +// sets selection to [start,stop) + void setSelection(off_t start, off_t stop); + bool browseLoadFile(); + bool browseLoadFileNew(); + bool open(const char * filename); + void gotoOffset(off_t offset); + void setOffsetFromStatusBar(void); + + bool save(); + bool saveAs(); + void setScrollBarRange(off_t low, off_t high); + void setScrollBarValue(off_t pos); + void setOffsetLabel(off_t pos); + void closeEvent(QCloseEvent *ce); + // had to trivially overload closeFile() == closeFile(false) for Qt slots + int closeFile(); + int closeFile(bool force); + void searchForwards(); + void searchBackwards(); + +protected: + void search( bool forwards ); + +protected: + enum ActionID_e { + UndoAction, + RedoAction, + SaveAction, + SaveAsAction, + TotalActions + }; + + QLabel *statusLabel; + QLineEdit *offsetLineEdit; + // QProgressBar *progressBar; + HexEditor *hexEditor; + ConversionDlg *conversionDlg; + QScrollBar *vsb; + QAction* actions[TotalActions]; + QMenu *fileMenu; + QMenu *editMenu; + QMenu *viewMenu; +}; + +#endif diff --git a/src/images.qrc b/src/images.qrc new file mode 100644 index 0000000..6304052 --- /dev/null +++ b/src/images.qrc @@ -0,0 +1,9 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>img/exit.xbm</file> + <file>img/first.xbm</file> + <file>img/last.xbm</file> + <file>img/next.xbm</file> + <file>img/prev.xbm</file> +</qresource> +</RCC>
\ No newline at end of file diff --git a/src/img/exit.xbm b/src/img/exit.xbm new file mode 100644 index 0000000..40c6979 --- /dev/null +++ b/src/img/exit.xbm @@ -0,0 +1,6 @@ +#define exit_width 16 +#define exit_height 16 +static unsigned char exit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x70, 0x3c, 0xc0, 0x1e, 0x80, 0x07, + 0xc0, 0x03, 0xe0, 0x06, 0x70, 0x0c, 0x78, 0x1c, 0x3c, 0x1c, 0x3c, 0x18, + 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/src/img/first.xbm b/src/img/first.xbm new file mode 100644 index 0000000..081acc8 --- /dev/null +++ b/src/img/first.xbm @@ -0,0 +1,6 @@ +#define first_width 16 +#define first_height 16 +static unsigned char first_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x70, 0x70, 0x78, 0x78, + 0x7c, 0x7c, 0x7e, 0x7e, 0x7e, 0x7e, 0x7c, 0x7c, 0x78, 0x78, 0x70, 0x70, + 0x60, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00}; diff --git a/src/img/last.xbm b/src/img/last.xbm new file mode 100644 index 0000000..39907a8 --- /dev/null +++ b/src/img/last.xbm @@ -0,0 +1,6 @@ +#define last_width 16 +#define last_height 16 +static unsigned char last_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x06, 0x06, 0x0e, 0x0e, 0x1e, 0x1e, + 0x3e, 0x3e, 0x7e, 0x7e, 0x7e, 0x7e, 0x3e, 0x3e, 0x1e, 0x1e, 0x0e, 0x0e, + 0x06, 0x06, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00}; diff --git a/src/img/next.xbm b/src/img/next.xbm new file mode 100644 index 0000000..b7b5646 --- /dev/null +++ b/src/img/next.xbm @@ -0,0 +1,6 @@ +#define next_width 16 +#define next_height 16 +static unsigned char next_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x60, 0x00, 0xe0, 0x00, 0xe0, 0x01, + 0xe0, 0x03, 0xe0, 0x07, 0xe0, 0x07, 0xe0, 0x03, 0xe0, 0x01, 0xe0, 0x00, + 0x60, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/src/img/prev.xbm b/src/img/prev.xbm new file mode 100644 index 0000000..5cb72fc --- /dev/null +++ b/src/img/prev.xbm @@ -0,0 +1,6 @@ +#define prev_width 16 +#define prev_height 16 +static unsigned char prev_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x07, 0x80, 0x07, + 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0x80, 0x07, 0x00, 0x07, + 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}; diff --git a/src/lfhex b/src/lfhex Binary files differnew file mode 100755 index 0000000..08cf35b --- /dev/null +++ b/src/lfhex diff --git a/src/lfhex.pro b/src/lfhex.pro new file mode 100644 index 0000000..892df3d --- /dev/null +++ b/src/lfhex.pro @@ -0,0 +1,60 @@ +# $Id: lfhex.pro,v 1.2 2008-09-11 01:49:00 salem Exp $ +TARGET = lfhex +VERSION = 0.42 +TEMPLATE = app +SOURCES = reader.cpp \ + save.cpp \ + translate.cpp \ + hexEditor.cpp \ + hexGui.cpp \ + grid.cpp \ + compareDlg.cpp \ + conversionDlg.cpp \ + cursor.cpp \ + delta.cpp \ + offsetConstraint.cpp \ + driver.cpp +HEADERS = box.hpp \ + compareDlg.hpp \ + conversionDlg.hpp \ + cursor.hpp \ + delta.hpp \ + grid.hpp \ + hexEditor.hpp \ + hexGui.hpp \ + offsetConstraint.hpp \ + reader.hpp \ + save.hpp \ + translate.hpp \ + expr.h \ + local.h \ + mappings.h + +# The following defines are used to select large file offsets. +# If your OS does not support this comment it out. +DEFINES += _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64 +# If your machine is big endian then uncomment the following, otherwise the +# offset labels will be in little endian (which some find hard to read). +# DEFINES += WORDS_BIGENDIAN +lfhex.path = /usr/local/bin +lfhex.files = lfhex +INSTALLS += lfhex +RESOURCES = images.qrc +YACCSOURCES += expr.y +LEXSOURCES += expr.l +QMAKE_LEX = flex +QMAKE_YACC = bison +QMAKE_YACCFLAGS = -d -b expr -p expr +DISTFILES += ../README \ + ../README.install \ + ../COPYING \ + $$YACCSOURCES \ + $$LEXSOURCES \ + img/exit.xbm \ + img/first.xbm \ + img/last.xbm \ + img/next.xbm \ + img/prev.xbm +# Uncomment this to compile in debug mode +# CONFIG += debug + diff --git a/src/local.h b/src/local.h new file mode 100644 index 0000000..fd97c75 --- /dev/null +++ b/src/local.h @@ -0,0 +1,30 @@ +#ifndef _LOCAL_H_ +#define _LOCAL_H_ +/* $Id: local.h,v 1.6 2008-09-11 01:49:00 salem Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +typedef unsigned char uchar; + +using namespace std; + +#define C_STR(x) x.toAscii().constData() +#define PROGRAM "lfhex" +#define VERSION "0.42" +#define PROGRAM_STRING PROGRAM " " VERSION + +#endif diff --git a/src/mappings.h b/src/mappings.h new file mode 100755 index 0000000..73212b1 --- /dev/null +++ b/src/mappings.h @@ -0,0 +1,179 @@ +/* $Id: mappings.h,v 1.3 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* automatically generated mappings from gen*To*Map.pl scripts */ + +namespace TranslationTables { + char * byteToBinaryMap[256] = { + "00000000", "00000001", "00000010", "00000011", "00000100", "00000101", + "00000110", "00000111", "00001000", "00001001", "00001010", "00001011", + "00001100", "00001101", "00001110", "00001111", "00010000", "00010001", + "00010010", "00010011", "00010100", "00010101", "00010110", "00010111", + "00011000", "00011001", "00011010", "00011011", "00011100", "00011101", + "00011110", "00011111", "00100000", "00100001", "00100010", "00100011", + "00100100", "00100101", "00100110", "00100111", "00101000", "00101001", + "00101010", "00101011", "00101100", "00101101", "00101110", "00101111", + "00110000", "00110001", "00110010", "00110011", "00110100", "00110101", + "00110110", "00110111", "00111000", "00111001", "00111010", "00111011", + "00111100", "00111101", "00111110", "00111111", "01000000", "01000001", + "01000010", "01000011", "01000100", "01000101", "01000110", "01000111", + "01001000", "01001001", "01001010", "01001011", "01001100", "01001101", + "01001110", "01001111", "01010000", "01010001", "01010010", "01010011", + "01010100", "01010101", "01010110", "01010111", "01011000", "01011001", + "01011010", "01011011", "01011100", "01011101", "01011110", "01011111", + "01100000", "01100001", "01100010", "01100011", "01100100", "01100101", + "01100110", "01100111", "01101000", "01101001", "01101010", "01101011", + "01101100", "01101101", "01101110", "01101111", "01110000", "01110001", + "01110010", "01110011", "01110100", "01110101", "01110110", "01110111", + "01111000", "01111001", "01111010", "01111011", "01111100", "01111101", + "01111110", "01111111", "10000000", "10000001", "10000010", "10000011", + "10000100", "10000101", "10000110", "10000111", "10001000", "10001001", + "10001010", "10001011", "10001100", "10001101", "10001110", "10001111", + "10010000", "10010001", "10010010", "10010011", "10010100", "10010101", + "10010110", "10010111", "10011000", "10011001", "10011010", "10011011", + "10011100", "10011101", "10011110", "10011111", "10100000", "10100001", + "10100010", "10100011", "10100100", "10100101", "10100110", "10100111", + "10101000", "10101001", "10101010", "10101011", "10101100", "10101101", + "10101110", "10101111", "10110000", "10110001", "10110010", "10110011", + "10110100", "10110101", "10110110", "10110111", "10111000", "10111001", + "10111010", "10111011", "10111100", "10111101", "10111110", "10111111", + "11000000", "11000001", "11000010", "11000011", "11000100", "11000101", + "11000110", "11000111", "11001000", "11001001", "11001010", "11001011", + "11001100", "11001101", "11001110", "11001111", "11010000", "11010001", + "11010010", "11010011", "11010100", "11010101", "11010110", "11010111", + "11011000", "11011001", "11011010", "11011011", "11011100", "11011101", + "11011110", "11011111", "11100000", "11100001", "11100010", "11100011", + "11100100", "11100101", "11100110", "11100111", "11101000", "11101001", + "11101010", "11101011", "11101100", "11101101", "11101110", "11101111", + "11110000", "11110001", "11110010", "11110011", "11110100", "11110101", + "11110110", "11110111", "11111000", "11111001", "11111010", "11111011", + "11111100", "11111101", "11111110", "11111111", + }; + char byteToCharMap[256] = { + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.',' ','!','"','#','.','%','&','\'', + '(',')','*','+',',','-','.','/','0','1', + '2','3','4','5','6','7','8','9',':',';', + '<','=','>','?','@','A','B','C','D','E', + 'F','G','H','I','J','K','L','M','N','O', + 'P','Q','R','S','T','U','V','W','X','Y', + 'Z','[','\\',']','^','_','`','a','b','c', + 'd','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w', + 'x','y','z','{','|','}','~','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.','.','.','.','.', + '.','.','.','.','.','.', + }; + char * byteToHexMap[256] = { + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", + "0a", "0b", "0c", "0d", "0e", "0f", "10", "11", "12", "13", + "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", + "1e", "1f", "20", "21", "22", "23", "24", "25", "26", "27", + "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", "30", "31", + "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", + "3c", "3d", "3e", "3f", "40", "41", "42", "43", "44", "45", + "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", + "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", + "5a", "5b", "5c", "5d", "5e", "5f", "60", "61", "62", "63", + "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", + "6e", "6f", "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", "80", "81", + "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", + "8c", "8d", "8e", "8f", "90", "91", "92", "93", "94", "95", + "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", + "aa", "ab", "ac", "ad", "ae", "af", "b0", "b1", "b2", "b3", + "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", + "be", "bf", "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", + "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", "d0", "d1", + "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", + "dc", "dd", "de", "df", "e0", "e1", "e2", "e3", "e4", "e5", + "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", + "fa", "fb", "fc", "fd", "fe", "ff", + }; + char * byteToOctalMap[256] = { + "000", "001", "002", "003", "004", "005", "006", "007", "010", "011", + "012", "013", "014", "015", "016", "017", "020", "021", "022", "023", + "024", "025", "026", "027", "030", "031", "032", "033", "034", "035", + "036", "037", "040", "041", "042", "043", "044", "045", "046", "047", + "050", "051", "052", "053", "054", "055", "056", "057", "060", "061", + "062", "063", "064", "065", "066", "067", "070", "071", "072", "073", + "074", "075", "076", "077", "100", "101", "102", "103", "104", "105", + "106", "107", "110", "111", "112", "113", "114", "115", "116", "117", + "120", "121", "122", "123", "124", "125", "126", "127", "130", "131", + "132", "133", "134", "135", "136", "137", "140", "141", "142", "143", + "144", "145", "146", "147", "150", "151", "152", "153", "154", "155", + "156", "157", "160", "161", "162", "163", "164", "165", "166", "167", + "170", "171", "172", "173", "174", "175", "176", "177", "200", "201", + "202", "203", "204", "205", "206", "207", "210", "211", "212", "213", + "214", "215", "216", "217", "220", "221", "222", "223", "224", "225", + "226", "227", "230", "231", "232", "233", "234", "235", "236", "237", + "240", "241", "242", "243", "244", "245", "246", "247", "250", "251", + "252", "253", "254", "255", "256", "257", "260", "261", "262", "263", + "264", "265", "266", "267", "270", "271", "272", "273", "274", "275", + "276", "277", "300", "301", "302", "303", "304", "305", "306", "307", + "310", "311", "312", "313", "314", "315", "316", "317", "320", "321", + "322", "323", "324", "325", "326", "327", "330", "331", "332", "333", + "334", "335", "336", "337", "340", "341", "342", "343", "344", "345", + "346", "347", "350", "351", "352", "353", "354", "355", "356", "357", + "360", "361", "362", "363", "364", "365", "366", "367", "370", "371", + "372", "373", "374", "375", "376", "377", + }; + unsigned char hexToByteMap[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, + 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, + 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + }; +}; diff --git a/src/offsetConstraint.cpp b/src/offsetConstraint.cpp new file mode 100644 index 0000000..72c1652 --- /dev/null +++ b/src/offsetConstraint.cpp @@ -0,0 +1,98 @@ +/* $Id: offsetConstraint.cpp,v 1.7 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <QLabel> +#include <QSpinBox> +#include <QHBoxLayout> + +#include <algorithm> // for min<>() + +#include "local.h" +#include "offsetConstraint.hpp" +#include "box.hpp" + +OffsetConstraint::OffsetConstraint( QWidget * parent ) + : QGroupBox(parent) +{ + QLayout* l = new QHBoxLayout(this); + this->setLayout(l); + hbox * h = new hbox(this); + l->addWidget(h); + new QLabel("X =",h); + stride = new QSpinBox(h); + stride->setRange(1,16); + stride->setValue(1); + connect(stride,SIGNAL(valueChanged(int)), + this,SLOT(setStride(int))); + + h = new hbox(this); + l->addWidget(h); + new QLabel("Y =",h); + offset = new QSpinBox(h); + offset->setRange(1,16); + offset->setValue(1); + + setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed)); +} + +// public interface + +int OffsetConstraint::getStride(void) const +{ + return stride->text().toInt(); +} + +int OffsetConstraint::getOffset(void) const +{ + return offset->text().toInt(); +} + +off_t OffsetConstraint::next(off_t off) const +{ + return( ((off-getOffset())/getStride()+1)*getStride()+getOffset() ); +} + +off_t OffsetConstraint::prev(off_t off) const +{ + return( ((off-getOffset())/getStride() - 1)*getStride()+getOffset() ); +} + +// public slots +void OffsetConstraint::setOffset(int x) +{ + offset->setValue( min(x,getStride()-1) ); +} + +void OffsetConstraint::setStride(int x) +{ + // constrain x to (0,MAXINT) + if( x < 1 ) { + stride->setValue(1); + return; + } + + // constrain offset to [0,x) + + // setRange() does not seem to work as the documentation says, so + // we have to manually change the value + if( offset->text().toInt() >= x ) + offset->setValue(x-1); + offset->setRange(0,x-1); + return; +} + diff --git a/src/offsetConstraint.hpp b/src/offsetConstraint.hpp new file mode 100644 index 0000000..2184ce4 --- /dev/null +++ b/src/offsetConstraint.hpp @@ -0,0 +1,48 @@ +/* $Id: offsetConstraint.hpp,v 1.5 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +// widget for constraining offset to stride*n+offset + +#include <sys/types.h> +#include <QGroupBox> + +class QWidget; +class QSpinBox; + +class OffsetConstraint :public QGroupBox { + Q_OBJECT + +public: + OffsetConstraint( QWidget * parent = 0 ); + + int getStride(void) const; + int getOffset(void) const; + + // applies formula to find next/previous constrained offset + off_t next(off_t off) const; + off_t prev(off_t off) const; + +public slots: + void setStride(int); + void setOffset(int); + +protected: + QSpinBox * stride; + QSpinBox * offset; // [0,stride) + +}; diff --git a/src/reader.cpp b/src/reader.cpp new file mode 100644 index 0000000..804f54c --- /dev/null +++ b/src/reader.cpp @@ -0,0 +1,364 @@ +/* $Id: reader.cpp,v 1.11 2008-09-11 01:49:00 salem Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <stdexcept> +#include <algorithm> +#include <new> + +// for stat: +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +// for strerror and errno: +#include <string.h> +#include <errno.h> + +#include <assert.h> + +#include <stdexcept> + +#include "local.h" +#include "reader.hpp" // some systems #define to map fn's to thier 64 bit + // equivalents. make sure the header gets processed the + // same as the .cc file + +Reader::Reader( const string& filename, off_t npages, off_t pageSize ) + : _filename(filename), + _pageSize(pageSize) +{ + _maxPages = _freePages = (npages < 10) ? 10: npages; + _error = ""; + _is_open = false; + _offset = 0; + _size = 0; + _firstPage = -1; + _lastPage = -1; + + if( !filename.empty() ) + open(filename); +} + +Reader::~Reader() +{ + if( _is_open ) + close(); +} + +// +// public methods +// + +bool Reader::open( const string& filename ) +{ + // clear old data + if( is_open() ) { + this->close(); + if( is_open() ) // only occurs if close somehow fails. + return false; + } else { + _is_open = false; + } + + if( 0 == (_fptr = fopen( filename.c_str() , "r" )) ) { + _error = "Failed to open \"" + filename + "\""; + return false; + } + + // get filesize + struct stat statBuf; + if( -1 == stat(filename.c_str(), &statBuf) ) { + _error = "Could not stat \"" + filename + "\""; + return false; + } + + off_t filesize = statBuf.st_size; + _size = filesize; + // calculate necessary number of pages + off_t npages = filesize/_pageSize +1; + // initialize page pointers + _data.resize(npages); + fill( _data.begin(), _data.begin()+npages, (uchar*)0 ); + + _filename = filename; + _is_open = true; + _firstPage = _lastPage = 0; + return loadPage(0); +} + +bool Reader::close() +{ + if( !is_open() ) { + _error = "attempted to close non-open reader."; + return false; + } + + _filename = ""; + _error = ""; + if( EOF == fclose(_fptr) ) { + _error = strerror(errno); + return false; + } + // free data pages + vector<uchar*>::iterator itr; + for( itr = _data.begin(); itr != _data.end(); ++itr ) + delete [] (*itr); + _is_open = false; + _firstPage = _lastPage = -1; + _freePages = _maxPages; + return true; +} + +bool Reader::is_open() const +{ + return _is_open; +} + +size_t Reader::read(vector<uchar>& v, size_t numBytes) +{ + int lastPageIdx = 0; + size_t bytesRead; + + // if we don't have enough bytes left... then set page_end to lastPageIdx + // to the last page and set bytesRead to the remaining number of bytes + if( _offset+numBytes >= size() ) { + _eof = true; + lastPageIdx = _data.size()-1; + bytesRead = size()-tell(); + // we use numBytes as a counter for the number of operations to make + // so limit numBytes to the actual the max number of bytes left + numBytes = bytesRead; + } else { + lastPageIdx = (_offset+numBytes)/_pageSize; + bytesRead = numBytes; + } + + if( !numBytes ) + return numBytes; + + // only do one realloc if necessary + v.erase(v.begin(),v.end()); + v.reserve(v.size()+numBytes); + + // int byte_end; // == lastByteIndex+1 + // copy the data a page at a time + for(int page = _offset/_pageSize; page <= lastPageIdx; page++) { + // ensure the page is loaded. + try { + loadPage( page ); + } + catch (bad_alloc){ + // out of memory + _error = "Out of memory."; + // return the number of bytes read + return (_offset/_pageSize - page)*_pageSize; + } + + int start = _offset%_pageSize; + int stop = (page == lastPageIdx)? start+numBytes: _pageSize; + for(int i = start; i < stop; i++) { + v.push_back(_data[page][i]); + } + numBytes -= stop-start; + _offset += stop-start; + } + return bytesRead; +} +bool Reader::eof() +{ + return (is_open())? _eof : 0; +} +off_t Reader::seek(off_t offset) +{ + if( !is_open() ) + return -1; + + // seek resets eof... even if the seek is past eof + _eof = false; + + _offset = max( min( offset, size()-1 ), (off_t)0); + if( fseek(_fptr, _offset, SEEK_SET) ) { + _error = "Seek to offset:"; + _error += _offset; + _error += " failed."; + return -1; + } + assert(_offset == ftell(_fptr)); + return _offset; +} + +off_t Reader::tell() const +{ + if(!is_open()) + return -1; + return _offset; +} + +off_t Reader::size() const +{ + return _size; +} + +const char* Reader::lastError() const +{ + return _error.c_str(); +} +const char* Reader::filename() const +{ + return _filename.c_str(); +} + +// +// Protected member fn's +// + +bool Reader::loadPage(off_t pageIdx) +{ + if( !is_open() ) + return false; + if(_data[pageIdx] != 0) + return true; + + if( !nFreePages() ) { + // free the page which is the furthest away from the page we are loading + + // this could be trouble if off_t is unsigned! + if( abs(_firstPage - pageIdx) > abs(_lastPage - pageIdx) ) + while(!freePage(_firstPage++)); + else + while(!freePage(_lastPage--)); + } + _data[pageIdx] = new uchar [_pageSize]; + // page added, subtract from num available + --nFreePages(); + + fseek(_fptr,pageIdx*_pageSize, SEEK_SET); + + off_t retval = fread(_data[pageIdx], sizeof(uchar), _pageSize, _fptr); + + if( retval ) { + if( pageIdx < _firstPage ) + _firstPage = pageIdx; + + if( pageIdx > _lastPage ) + _lastPage = pageIdx; + } + return retval; +} + +bool Reader::freePage(off_t pageIdx) +{ + // check range + if( pageIdx < 0 || (unsigned)pageIdx >= _data.size() || !_data[pageIdx] ) + return false; + + delete [] _data[pageIdx]; + _data[pageIdx] = 0; + ++nFreePages(); // page freed + return true; +} + +uchar Reader::operator[] (off_t offset) +{ + if( !is_open() ) + throw logic_error("Reader::operator[] - attempt to access non-open file."); + if( offset < 0 ) + throw out_of_range("Reader::operator[] - " + "attempt to access negative offset."); + if( offset >= size() ) + throw out_of_range("Reader::operator[] - " + "attempt to access past end of file"); + + off_t page_idx = offset/_pageSize; + bool loaded = loadPage( page_idx ); + assert( loaded ); + return _data[page_idx][ offset%_pageSize ]; +} + +off_t +Reader::nFreePages() const +{ + return _freePages; +} + +off_t& +Reader::nFreePages() +{ + return _freePages; +} + +bool +Reader::dataIsAtOffset( const vector<uchar>& data, off_t pos ) +{ + size_t i = 0; + while( i < data.size() ) { + if( data[i] != (*this)[pos+i] ) { + return false; + } + ++i; + } + return true; +} + + +off_t +Reader::findIndex( off_t start, const vector<uchar>& data, off_t stop ) +{ + off_t pos = start; + while( pos <= stop ) { + if( data[0] == (*this)[pos] ) { + if( dataIsAtOffset( data, pos ) ) { + return pos; + } + } + ++pos; + } + return size(); +} + +off_t +Reader::rFindIndex( off_t start, const vector<uchar>& data, off_t stop ) +{ + off_t pos = start; + while( pos >= stop ) { + if( data[0] == (*this)[pos] ) { + if( dataIsAtOffset( data, pos ) ) { + return pos; + } + } + --pos; + } + return size(); +} + +// +// ReadBuffer friends and aquaintances (only for debugging) +// + +#if 0 +ostream& operator<< (ostream&out, const ReadBuffer& buff) +{ + ios_base::fmtflags old_flags = out.flags(); + out.flags(old_flags | ios::hex | ios::showbase); + for(size_t i = 0; i < buff.size(); i++) + out << buff[i]; + // restore old flags + out.flags(old_flags); + return out; +} +#endif diff --git a/src/reader.hpp b/src/reader.hpp new file mode 100644 index 0000000..4307c3f --- /dev/null +++ b/src/reader.hpp @@ -0,0 +1,95 @@ +/* $Id: reader.hpp,v 1.6 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _READER_H_ +#define _READER_H_ + +// +// Interface for Reader object. +// +// Reader object supports: +// open(const QString& filename ); -> open a file for reading +// bool is_open(); -> see if file is open +// close(); -> free resources for open file. +// int read( vector<uchar>& v, int maxSize ) -> fill v with maxSize data from +// open file. +// off_t seek( off_t offset ); -> move file pointer to offset offset. +// + +#include <sys/types.h> +#include <stdio.h> + +#include <vector> +#include <string> +#include <iostream> + +#include "local.h" + +typedef vector<uchar> ReadBuffer; + +#ifdef __GNUC__ +ostream& operator<< (ostream&out,const ReadBuffer& buff); +#endif + +class Reader { + public: + // default is only 50*4k = 200k memory image. + Reader(const string& filename = "",off_t npages = 50, off_t pageSize = 4096); + ~Reader(); + + bool open(const string& filename); + bool close(); + bool eof(); + bool is_open() const; + + size_t read( ReadBuffer& v, size_t numBytes ); + off_t seek( off_t offset ); + off_t tell() const; // returns the current offset or -1 if !open + off_t size() const; + const char* lastError() const; + const char* filename() const; + + uchar operator[] (off_t offset); // cannot be const because it does change + // data by loading/swapping pages + off_t findIndex( off_t start, const vector<uchar>& data, + off_t stop ); + off_t rFindIndex( off_t start, const vector<uchar>& data, + off_t stop ); + protected: + bool dataIsAtOffset( const vector<uchar>& data, off_t pos ); + bool loadPage(off_t pageIdx); + bool freePage(off_t pageIdx); + off_t nFreePages() const; + off_t& nFreePages(); + + protected: + string _error; + FILE* _fptr; + bool _is_open; + bool _eof; + string _filename; + off_t _offset; // current offset + off_t _size; // file size from fstat + off_t _pageSize; // number of bytes in a page + off_t _firstPage; // first currently loaded page + off_t _lastPage; // last currently loaded page + off_t _maxPages; // maximum number of pages which could be currently loaded + off_t _freePages; // number of free pages + vector< uchar *> _data; +}; + +#endif diff --git a/src/save.cpp b/src/save.cpp new file mode 100644 index 0000000..ba75043 --- /dev/null +++ b/src/save.cpp @@ -0,0 +1,67 @@ +/* $Id: save.cpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <errno.h> +#include <string> +#include <vector> +#include <qmessagebox.h> +#include <sys/types.h> + +#include "translate.hpp" +#include "local.h" +#include "delta.hpp" +#include "reader.hpp" + +extern int errno; + +bool writeDeltas( const string& filename , DeltaMap& dmap ) +{ + FILE* fptr = fopen( filename.c_str(), "r+" ); + if( NULL == fptr ) { + QString message = "Error opening \""; + message += filename.c_str(); + message += "\": "; + message += strerror(errno); + QMessageBox::critical( NULL, PROGRAM_STRING, + message, + "Ok"); + return false; + } + + const Delta * deltaPtr; + for(off_t offset = dmap.lower_bound(0); + offset != -1; + offset = dmap.lower_bound(offset+1)) { + if( fseek(fptr,offset,SEEK_SET) ) { + fclose(fptr); + QString message = "Error seeking to offset "; + message += offset; + message += ": "; + message += strerror(errno); + QMessageBox::critical( NULL, PROGRAM_STRING, + message, + "Ok"); + return false; + } + deltaPtr = dmap.search(offset); + fwrite( &(deltaPtr->newData()[0]), sizeof(uchar) , + deltaPtr->newData().size(), fptr); + } + fclose(fptr); + return true; +} diff --git a/src/save.hpp b/src/save.hpp new file mode 100644 index 0000000..e0c4136 --- /dev/null +++ b/src/save.hpp @@ -0,0 +1,25 @@ + +/* $Id: save.hpp,v 1.3 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _HEXEDIT_SAVE_ +#define _HEXEDIT_SAVE_ + +bool writeDeltas( const string& filename , DeltaMap& dmap ); + +#endif diff --git a/src/translate.cpp b/src/translate.cpp new file mode 100755 index 0000000..b0a96a3 --- /dev/null +++ b/src/translate.cpp @@ -0,0 +1,189 @@ +/* $Id: translate.cpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "translate.hpp" + +// translation maps from byte->hex, hex->byte, and byte->char +// mappings are static arrays for speed +#include "mappings.h" + +void Translate::CharToByte(vector<uchar>& dst, const vector<uchar>& src) +{ + // just copy the base into the byte vector + dst = vector<uchar>(src.begin(),src.end()); +} +void Translate::CharToByte(vector<uchar>& dst, const QString& src) +{ + // just copy the base into the byte vector + dst.resize( src.length() ); + for(int i =0 ; i < src.length(); ++i) + dst[i] = src[i].toAscii(); +} + + +void Translate::ByteToChar(vector<uchar>& dst, const vector<uchar>& src) +{ + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.size()); + for(unsigned int i = 0; i < src.size(); i++) { + dst.push_back(TranslationTables::byteToCharMap[src[i]]); + } +} + +void Translate::ByteToChar(QString& dst, const vector<uchar>& src) +{ + dst = ""; + for(unsigned int i = 0; i < src.size(); i++) { + dst += TranslationTables::byteToCharMap[src[i]]; + } +} + +void Translate::HexToByte(vector<uchar>& dst, const vector<uchar>& src) +{ + dst.erase(dst.begin(),dst.end()); + int start; + + if( src.size() % 2 ) { + // if odd + dst.reserve(src.size()/2+1); + dst.push_back(TranslationTables::hexToByteMap[src[0]]); + start = 1; + } else { + start = 0; + dst.reserve(src.size()/2); + } + for(unsigned int i = start; i < src.size(); i+=2) { + dst.push_back(TranslationTables::hexToByteMap[src[i]]*16 + + TranslationTables::hexToByteMap[src[i+1]]); + } +} + +void Translate::HexToByte(vector<uchar>& dst, const QString& src) +{ + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.length()/2); + int i = 0; + if( src.length() % 2 ) { + i = 1; + } + for(; i < src.length(); i+=2) { + uchar hi = src[i].toAscii(); + uchar lo = src[i+1].toAscii(); + dst.push_back( TranslationTables::hexToByteMap[hi]*16 + + TranslationTables::hexToByteMap[lo] ); + } +} + +void Translate::OctalToByte(vector<uchar> &dst, const vector<uchar>& src) +{ + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.size()/3); + for(unsigned int i = 0; i+2 < src.size(); i+=3) { + dst.push_back(TranslationTables::hexToByteMap[src[i]]*64+ + TranslationTables::hexToByteMap[src[i+1]]*8+ + TranslationTables::hexToByteMap[src[i+2]]); + } +} + +void Translate::BinaryToByte(vector<uchar> &dst, const vector<uchar>& src) +{ + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.size()/8); + // FIXME: would be faster if we compared each src[i] with '1' before mult + for(unsigned int i = 0; i < src.size(); i+=8) { + dst.push_back(TranslationTables::hexToByteMap[src[i]]*128+ + TranslationTables::hexToByteMap[src[i+1]]*64+ + TranslationTables::hexToByteMap[src[i+2]]*32+ + TranslationTables::hexToByteMap[src[i+3]]*16+ + TranslationTables::hexToByteMap[src[i+4]]*8+ + TranslationTables::hexToByteMap[src[i+5]]*4+ + TranslationTables::hexToByteMap[src[i+6]]*2+ + TranslationTables::hexToByteMap[src[i+7]]); + } +} + +const char * Translate::ByteToHex(uchar b) +{ + return TranslationTables::byteToHexMap[b]; +} + +void Translate::ByteToHex(vector<uchar>& dst, const vector<uchar>& src) +{ + const char * str; + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.size()*2); + for(unsigned int i = 0; i < src.size(); i++) { + str = TranslationTables::byteToHexMap[src[i]]; + dst.push_back(*str); + dst.push_back(*(str+1)); + } +} + +void Translate::ByteToHex(QString& dst, const vector<uchar>&src) +{ + dst = ""; + for(unsigned int i = 0; i < src.size(); i++) { + dst += TranslationTables::byteToHexMap[src[i]]; + } +} + +void Translate::ByteToOctal(vector<uchar>&dst, const vector<uchar>&src) +{ + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.size()*3); + + vector<uchar>::const_iterator itr; + const char * str; + for(itr = src.begin(); itr != src.end(); ++itr) { + str = TranslationTables::byteToOctalMap[*itr]; + dst.insert( dst.end(), str, str+3 ); + } +} + +void Translate::ByteToOctal(QString&dst, const vector<uchar>&src) +{ + dst = ""; + vector<uchar>::const_iterator itr; + for(itr = src.begin(); itr != src.end(); ++itr) { + dst += TranslationTables::byteToOctalMap[*itr]; + } +} + +void Translate::ByteToBinary(vector<uchar>&dst, const vector<uchar>&src) +{ + dst.erase(dst.begin(),dst.end()); + dst.reserve(src.size()*8); + + vector<uchar>::const_iterator itr; + const char * str; + for(itr = src.begin(); itr != src.end(); ++itr) { + str = TranslationTables::byteToBinaryMap[*itr]; + dst.insert(dst.end(), str, str+8); + } +} + +void Translate::ByteToBinary(QString&dst, const vector<uchar>&src) +{ + dst = ""; + + vector<uchar>::const_iterator itr; + for(itr = src.begin(); itr != src.end(); ++itr) { + dst += TranslationTables::byteToBinaryMap[*itr]; + } +} + diff --git a/src/translate.hpp b/src/translate.hpp new file mode 100755 index 0000000..6fa9898 --- /dev/null +++ b/src/translate.hpp @@ -0,0 +1,47 @@ +/* $Id: translate.hpp,v 1.4 2006-11-05 04:42:43 ganzhorn Exp $ + * This file is part of lfhex. + * Copyright (C) 2006 Salem Ganzhorn <eyekode@yahoo.com> + * + * 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 version 2. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <vector> +#include <QString> + +#include "local.h" + +typedef unsigned char uchar; + +namespace Translate { + const char* ByteToHex(uchar b); + void ByteToHex(vector<uchar>& dst , const vector<uchar>& src); + void ByteToChar(vector<uchar>& dst, const vector<uchar>& src); + void ByteToOctal(vector<uchar>& dst,const vector<uchar>& src); + void ByteToBinary(vector<uchar>& dst,const vector<uchar>& src); + + void ByteToHex(QString& dst , const vector<uchar>& src); + void ByteToChar(QString& dst, const vector<uchar>& src); + void ByteToOctal(QString& dst,const vector<uchar>& src); + void ByteToBinary(QString& dst,const vector<uchar>& src); + + void BinaryToByte(vector<uchar>& dst,const vector<uchar>& src); + + void OctalToByte(vector<uchar>& dst,const vector<uchar>& src); + + void CharToByte(vector<uchar>& dst, const vector<uchar>& src); + void CharToByte(vector<uchar>& dst, const QString& src); + + void HexToByte(vector<uchar>& dst , const vector<uchar>& src); + void HexToByte(vector<uchar>& dst , const QString& src); + +}; |