You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5100 lines
107 KiB
5100 lines
107 KiB
/*
|
|
* khexedit - Versatile hex editor
|
|
* Copyright (C) 1999-2000 Espen Sand, espensa@online.no
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
#include <klocale.h>
|
|
#include <kglobal.h>
|
|
#include <kglobalsettings.h>
|
|
#include <knotifyclient.h>
|
|
|
|
#include "hexbuffer.h"
|
|
#include "hexerror.h"
|
|
|
|
//
|
|
// There are some comments marked with a "// ##" at various places.
|
|
// These indicate a patch from Sergey A. Sukiyazov which I have applied
|
|
// "as is" for now. The number of TQString::fromLocal8Bit in this modification
|
|
// indicates that I should perhaps modify code elsewhere as well
|
|
// (espen 2000-11-26)
|
|
//
|
|
|
|
// #define DEBUG_FIXED_SIZE 1024
|
|
// #define PRINTER_TEST
|
|
|
|
|
|
CHexAction::CHexAction( HexAction action, uint offset )
|
|
{
|
|
mAction = action;
|
|
mOffset = offset;
|
|
mSize = 0;
|
|
mData = 0;
|
|
mDataSize = 0;
|
|
mNext = 0;
|
|
}
|
|
|
|
CHexAction::~CHexAction( void )
|
|
{
|
|
delete [] mData;
|
|
}
|
|
|
|
void CHexAction::setData( uint size, char *data, uint dataSize )
|
|
{
|
|
|
|
if( data != 0 && dataSize > 0 )
|
|
{
|
|
mData = new char[ dataSize ];
|
|
if( mData == 0 )
|
|
{
|
|
return;
|
|
}
|
|
memcpy( mData, data, dataSize );
|
|
mDataSize = dataSize;
|
|
}
|
|
else
|
|
{
|
|
mDataSize = 0;
|
|
mData = 0;
|
|
}
|
|
mSize = size;
|
|
}
|
|
|
|
|
|
CHexActionGroup::CHexActionGroup( uint startOffset, uint startBit )
|
|
{
|
|
mStartOffset = startOffset;
|
|
mStartBit = startBit;
|
|
mHexAction = 0;
|
|
}
|
|
|
|
CHexActionGroup::~CHexActionGroup( void )
|
|
{
|
|
CHexAction *ptr = mHexAction;
|
|
while( ptr != 0 )
|
|
{
|
|
CHexAction *next = ptr->mNext;
|
|
delete ptr;
|
|
ptr = next;
|
|
}
|
|
}
|
|
|
|
void CHexActionGroup::insertAction( CHexAction *hexAction )
|
|
{
|
|
hexAction->mNext = mHexAction;
|
|
mHexAction = hexAction;
|
|
}
|
|
|
|
|
|
|
|
int SFilterControl::execute( uchar *dest, uchar *src, uint size )
|
|
{
|
|
if( size == 0 )
|
|
{
|
|
return( Err_IllegalArgument );
|
|
}
|
|
|
|
uint numElement = operand.size();
|
|
if( operation == OperandAndData )
|
|
{
|
|
if( numElement == 0 ) { return( Err_IllegalArgument ); }
|
|
if( forward == true )
|
|
{
|
|
for( uint i = 0; i < size; )
|
|
{
|
|
for( uint j = 0; i < size && j < numElement; j++, i++ )
|
|
{
|
|
dest[i] = src[i] & operand[j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uint i = size; i > 0; )
|
|
{
|
|
for( uint j = numElement; i > 0 && j > 0; j--, i-- )
|
|
{
|
|
dest[i-1] = src[i-1] & operand[j-1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( operation == OperandOrData )
|
|
{
|
|
if( numElement == 0 ) { return( Err_IllegalArgument ); }
|
|
if( forward == true )
|
|
{
|
|
for( uint i = 0; i < size; )
|
|
{
|
|
for( uint j = 0; i < size && j < numElement; j++, i++ )
|
|
{
|
|
dest[i] = src[i] | operand[j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uint i = size; i > 0; )
|
|
{
|
|
for( uint j = numElement; i > 0 && j > 0; j--, i-- )
|
|
{
|
|
dest[i-1] = src[i-1] | operand[j-1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( operation == OperandXorData )
|
|
{
|
|
if( numElement == 0 ) { return( Err_IllegalArgument ); }
|
|
if( forward == true )
|
|
{
|
|
for( uint i = 0; i < size; )
|
|
{
|
|
for( uint j = 0; i < size && j < numElement; j++, i++ )
|
|
{
|
|
dest[i] = src[i] ^ operand[j];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uint i = size; i > 0; )
|
|
{
|
|
for( uint j = numElement; i > 0 && j > 0; j--, i-- )
|
|
{
|
|
dest[i-1] = src[i-1] ^ operand[j-1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( operation == InvertData )
|
|
{
|
|
for( uint i = 0; i < size; i++ )
|
|
{
|
|
dest[i] = ~src[i];
|
|
}
|
|
}
|
|
else if( operation == ReverseData )
|
|
{
|
|
for( uint i = 0; i < size; i++ )
|
|
{
|
|
uchar flag = src[i];
|
|
uchar rev = 0;
|
|
for( uint j = 0; j < 8; j++ )
|
|
{
|
|
rev |= (((flag & 0x80) >> (7-j)));
|
|
flag <<= 1;
|
|
}
|
|
dest[i] = rev;
|
|
}
|
|
}
|
|
else if( operation == RotateData || operation == ShiftData )
|
|
{
|
|
//
|
|
// Only forward here
|
|
//
|
|
bool up = rotate[1] > 0 ? true : false;
|
|
int range = rotate[0];
|
|
int shift = abs(rotate[1]);
|
|
if( range == 0 || shift == 0 ) { return( Err_IllegalArgument ); }
|
|
shift = shift % (range*8);
|
|
|
|
int b = shift / 8;
|
|
int s = shift - b * 8;
|
|
|
|
for( uint i = 0; i < size; )
|
|
{
|
|
if( up == true )
|
|
{
|
|
int j;
|
|
if( operation == RotateData )
|
|
{
|
|
for( j=0; j < b && i+range < size ; i++, j++ )
|
|
{
|
|
dest[i] = src[i+range-b];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( j=0; j < b && i < size ; dest[i] = 0, i++, j++ );
|
|
}
|
|
for( ; j < range && i < size ; i++, j++ )
|
|
{
|
|
dest[i] = src[i-b];
|
|
}
|
|
|
|
uchar last = dest[i-1];
|
|
for( int k=1; k <= j; k++ )
|
|
{
|
|
dest[i-k] >>= s;
|
|
if( k < j )
|
|
{
|
|
dest[i-k] |= dest[i-k-1]<<(8-s);
|
|
}
|
|
else if( j == range && operation == RotateData )
|
|
{
|
|
dest[i-k] |= last<<(8-s);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int j;
|
|
for( j=0; j+b < range && i+b < size ; i++, j++ )
|
|
{
|
|
dest[i] = src[i+b];
|
|
}
|
|
for( ; j < range && i < size ; i++, j++ )
|
|
{
|
|
dest[i] = operation == RotateData ? src[i+b-range] : 0;
|
|
}
|
|
|
|
uchar first = dest[i-j];
|
|
for( int k=j; k>0; k-- )
|
|
{
|
|
dest[i-k] <<= s;
|
|
if( k>1 )
|
|
{
|
|
dest[i-k] |= dest[i-k+1]>>(8-s);
|
|
}
|
|
else if( j == range && operation == RotateData )
|
|
{
|
|
dest[i-k] |= first>>(8-s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( operation == SwapBits )
|
|
{
|
|
//
|
|
// Swap bits. Based on Leon Lessing's work.
|
|
//
|
|
|
|
//
|
|
// Make non swapped version first.
|
|
//
|
|
for( uint i = 0; i < size; i++ )
|
|
{
|
|
dest[i] = src[i];
|
|
}
|
|
|
|
//
|
|
// Swap the pairs the have been defined
|
|
// Format of operand (example):
|
|
// 7 2 5 0 0 0 0 0
|
|
// Swap bit 7 with bit 2 and swap bit 5 with bit 0
|
|
//
|
|
for( uint j=0; j<4; j++ )
|
|
{
|
|
uchar b1 = 1 << (uchar)operand[j*2];
|
|
uchar b2 = 1 << (uchar)operand[j*2+1];
|
|
if( b1 == b2 ) { continue; } // Equal, no need to swap.
|
|
|
|
for( uint i = 0; i < size; i++ )
|
|
{
|
|
uchar b = 0;
|
|
if( dest[i] & b1 ) { b |= b2; }
|
|
if( dest[i] & b2 ) { b |= b1; }
|
|
|
|
//
|
|
// A short description so that I will understand what the
|
|
// h... is going on five minutes from now.
|
|
//
|
|
// Destination byte is masked (AND'ed) with the inverse bitmap
|
|
// (the noninversed bitmap contains position of the
|
|
// two swap bits, eg 7-2 gives 10000100). Then the destination
|
|
// is OR'ed with the swapped bitmap.
|
|
//
|
|
dest[i] = (dest[i] & ~(b1 | b2)) | b;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( Err_IllegalArgument );
|
|
}
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
const char *SExportCArray::printFormatted( const char *b, uint maxSize ) const
|
|
{
|
|
static char buf[12];
|
|
if( elementType == Char )
|
|
{
|
|
char e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
sprintf( buf, "%d", e );
|
|
return( buf );
|
|
}
|
|
else if( elementType == Uchar )
|
|
{
|
|
unsigned char e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
if( unsignedAsHexadecimal == true )
|
|
{
|
|
sprintf( buf, "0x%02x", e );
|
|
}
|
|
else
|
|
{
|
|
sprintf( buf, "%u", e );
|
|
}
|
|
return( buf );
|
|
}
|
|
else if( elementType == Short )
|
|
{
|
|
short e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
sprintf( buf, "%d", e );
|
|
return( buf );
|
|
|
|
}
|
|
else if( elementType == Ushort )
|
|
{
|
|
unsigned short e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
if( unsignedAsHexadecimal == true )
|
|
{
|
|
sprintf( buf, "0x%04x", e );
|
|
}
|
|
else
|
|
{
|
|
sprintf( buf, "%u", e );
|
|
}
|
|
return( buf );
|
|
}
|
|
else if( elementType == Int )
|
|
{
|
|
int e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
sprintf( buf, "%u", e );
|
|
return( buf );
|
|
}
|
|
else if( elementType == Uint )
|
|
{
|
|
unsigned int e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
if( unsignedAsHexadecimal == true )
|
|
{
|
|
sprintf( buf, "0x%08x", e );
|
|
}
|
|
else
|
|
{
|
|
sprintf( buf, "%u", e );
|
|
}
|
|
return( buf );
|
|
}
|
|
else if( elementType == Float )
|
|
{
|
|
float e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
sprintf( buf, "%f", e );
|
|
return( buf );
|
|
}
|
|
else if( elementType == Double )
|
|
{
|
|
double e = 0;
|
|
memcpy( &e, b, TQMIN(sizeof(e),maxSize) );
|
|
sprintf( buf, "%f", e );
|
|
return( buf );
|
|
}
|
|
|
|
else
|
|
{
|
|
return("");
|
|
}
|
|
}
|
|
|
|
|
|
TQString SExportCArray::variableName( uint range ) const
|
|
{
|
|
const char *typeString[] =
|
|
{
|
|
"char",
|
|
"unsigned char",
|
|
"short",
|
|
"unsigned short",
|
|
"int",
|
|
"unsigned int",
|
|
"float",
|
|
"double"
|
|
};
|
|
|
|
uint es = elementSize();
|
|
uint numElement = range / es + ((range % es) ? 1 : 0);
|
|
|
|
return( TQString("%1 %2[%2]").arg(typeString[elementType]).
|
|
arg(arrayName).arg(numElement) );
|
|
}
|
|
|
|
|
|
|
|
int SExportCArray::elementSize( void ) const
|
|
{
|
|
if( elementType == Char || elementType == Uchar )
|
|
{
|
|
return( sizeof(char) );
|
|
}
|
|
else if( elementType == Short || elementType == Ushort )
|
|
{
|
|
return( sizeof(short) );
|
|
}
|
|
else if( elementType == Int || elementType == Uint )
|
|
{
|
|
return( sizeof(int) );
|
|
}
|
|
else if( elementType == Float )
|
|
{
|
|
return( sizeof(float) );
|
|
}
|
|
else if( elementType == Double )
|
|
{
|
|
return( sizeof(double) );
|
|
}
|
|
else
|
|
{
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
|
|
char CHexBuffer::mHexBigBuffer[16]=
|
|
{
|
|
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
|
|
};
|
|
|
|
char CHexBuffer::mHexSmallBuffer[16]=
|
|
{
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
|
|
};
|
|
|
|
char CHexBuffer::mDecBuffer[10]=
|
|
{
|
|
'0','1','2','3','4','5','6','7','8','9'
|
|
};
|
|
|
|
char CHexBuffer::mOctBuffer[8]=
|
|
{
|
|
'0','1','2','3','4','5','6','7'
|
|
};
|
|
|
|
|
|
SCursorState CHexBuffer::mCursorState;
|
|
SFileState CHexBuffer::mFileState;
|
|
|
|
|
|
|
|
|
|
CHexBuffer::CHexBuffer( void )
|
|
:TQByteArray()
|
|
{
|
|
mColorIndex = 0;
|
|
mPrintBuf = 0;
|
|
mLoadingData = false;
|
|
mEditMode = EditReplace;
|
|
mActiveEditor = edit_primary;
|
|
|
|
mDocumentModified = false;
|
|
|
|
#ifdef DEBUG_FIXED_SIZE
|
|
setMaximumSize( DEBUG_FIXED_SIZE );
|
|
#else
|
|
setMaximumSize( ~0 );
|
|
#endif
|
|
|
|
setDocumentSize(0);
|
|
|
|
#ifdef PRINTER_TEST
|
|
puts("<CHexBuffer> Printer test is activated");
|
|
#endif
|
|
|
|
|
|
setInputMode( mInputMode );
|
|
|
|
int errCode = setLayout( mLayout );
|
|
if( errCode != 0 )
|
|
{
|
|
return;
|
|
}
|
|
setColor( mColor );
|
|
setFont( mFontInfo.init() );
|
|
setShowCursor( true );
|
|
setDisableCursor( false );
|
|
setEditMode( EditReplace, false, false );
|
|
setSoundState( false, false );
|
|
|
|
mUndoLimit = 10;
|
|
mUndoIndex = 0;
|
|
mUndoList.setAutoDelete( TRUE );
|
|
mBookmarkList.setAutoDelete( TRUE );
|
|
}
|
|
|
|
|
|
CHexBuffer::~CHexBuffer( void )
|
|
{
|
|
//debug("CHexBuffer::~CHexBuffer");
|
|
delete [] mColorIndex;
|
|
delete [] mPrintBuf;
|
|
}
|
|
|
|
|
|
|
|
bool CHexBuffer::hasFileName( void )
|
|
{
|
|
//
|
|
// FIXME: Files can be called "Untitled" so this must be corrected.
|
|
//
|
|
if( mUrl.isEmpty() || mUrl.contains( i18n( "Untitled" ), false ) )
|
|
{
|
|
return( false );
|
|
}
|
|
else
|
|
{
|
|
return( true );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::setLayout( SDisplayLayout &layout )
|
|
{
|
|
mLayout = layout;
|
|
mLayout.verify();
|
|
|
|
if( mLayout.primaryMode == SDisplayLayout::textOnly )
|
|
{
|
|
mActiveEditor = edit_primary;
|
|
setEditMode( mEditMode );
|
|
}
|
|
|
|
mCursor.setLineSize( mLayout.lineSize );
|
|
mCursor.addOffset( 0 ); // This will only reset the cell position
|
|
|
|
computeLineWidth();
|
|
cursorCompute();
|
|
|
|
delete [] mColorIndex; mColorIndex = 0;
|
|
delete [] mPrintBuf; mPrintBuf = 0;
|
|
|
|
mColorIndex = new unsigned char[ mLayout.lineSize ];
|
|
if( mColorIndex == 0 )
|
|
{
|
|
return( Err_NoMemory );
|
|
}
|
|
setColor( mColor );
|
|
|
|
//
|
|
// The 'mPrintBuf' is used to store formatted text. It is used for all
|
|
// print operations and must have the size of the 'mDpyState.lineSize' which
|
|
// is the number of bytes in one single display line.
|
|
//
|
|
mPrintBuf = new char[ mLayout.lineSize < 12 ? 12 : mLayout.lineSize ];
|
|
if( mPrintBuf == 0 )
|
|
{
|
|
delete [] mColorIndex; mColorIndex = 0;
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
void CHexBuffer::setColor( SDisplayColor &color )
|
|
{
|
|
mColor = color;
|
|
|
|
//
|
|
// Test...
|
|
//
|
|
//mColor.secondTextBg = TQt::yellow;
|
|
//mColor.offsetBg = TQt::lightGray;
|
|
//mColor.gridFg = TQt::darkCyan;
|
|
|
|
/*
|
|
mColor.secondTextBg = mColor.textBg;
|
|
mColor.offsetBg = mColor.textBg;
|
|
mColor.gridFg = mColor.textBg;
|
|
*/
|
|
|
|
if( mColorIndex != 0 )
|
|
{
|
|
uint columnSize = mLayout.columnSize == 0 ? 1 : mLayout.columnSize;
|
|
for( uint i = 0, entry = 0; i < mLayout.lineSize; i++ )
|
|
{
|
|
if( i > 0 && i % columnSize == 0 ) { entry = entry == 0 ? 1 : 0; }
|
|
mColorIndex[i] = entry;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CHexBuffer::setInputMode( SDisplayInputMode &mode )
|
|
{
|
|
mInputMode = mode;
|
|
if( mInputMode.allowResize == false && mEditMode != EditReplace )
|
|
{
|
|
setEditMode( EditReplace );
|
|
}
|
|
}
|
|
|
|
|
|
bool CHexBuffer::toggleEditor( void )
|
|
{
|
|
bool changed;
|
|
if( mLayout.secondaryMode == SDisplayLayout::hide )
|
|
{
|
|
changed = mActiveEditor == edit_secondary ? true : false;
|
|
mActiveEditor = edit_primary;
|
|
}
|
|
else
|
|
{
|
|
changed = true;
|
|
mActiveEditor = mActiveEditor == edit_primary ?
|
|
edit_secondary : edit_primary;
|
|
}
|
|
|
|
setEditMode( mEditMode ); // Sets the cursor shapes as well
|
|
|
|
if( changed == true )
|
|
{
|
|
mCursor.resetCell();
|
|
cursorCompute();
|
|
}
|
|
|
|
return( changed );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CHexBuffer::matchWidth( uint width )
|
|
{
|
|
if( documentPresent() == false || (uint)mFixedWidth >= width )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
width -= mFixedWidth;
|
|
|
|
uint g = mLayout.columnSpacing == 0 ? 1 : mLayout.columnSize;
|
|
uint n = g * mNumCell;
|
|
uint u = mUnitWidth;
|
|
uint s = mLayout.secondaryMode == SDisplayLayout::hide ? 0 : g;
|
|
uint o = mLayout.columnSpacing == 0 ? 0 : mSplitWidth;
|
|
float x = (float)(width+o)/(float)(u*(n+s)+o);
|
|
|
|
uint lineSize = (uint)x * g;
|
|
|
|
if( mLayout.lockColumn == false )
|
|
{
|
|
//
|
|
// Examine if we can add one or more entries from the next column. This
|
|
// will make the rightmost column smaller than the rest but we will
|
|
// utilize as much of the available space (ie., width) as possible.
|
|
// (Note that the entry itself (which represents one byte of filedata)
|
|
// can not be splitted, eg., in binary mode the entry is eight byte
|
|
// wide and will not be splitted).
|
|
//
|
|
int w = (int)((float)((int)x)* (float)(u*(n+s)+o) - (float)o);
|
|
if( w > 0 && (uint)w < width )
|
|
{
|
|
width -= w;
|
|
if( width > o )
|
|
{
|
|
x = (float)(width-o) / (float)(u*(mNumCell+1));
|
|
lineSize += (uint)x;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( lineSize == 0 || lineSize == mLayout.lineSize )
|
|
{
|
|
//
|
|
// We have to redraw all text if a change occurs so we avoid it if
|
|
// possible.
|
|
//
|
|
return( false );
|
|
}
|
|
|
|
mLayout.lineSize = lineSize;
|
|
setLayout( mLayout );
|
|
return( true );
|
|
}
|
|
|
|
|
|
void CHexBuffer::setNonPrintChar( TQChar nonPrintChar )
|
|
{
|
|
mFontInfo.nonPrintChar = nonPrintChar;
|
|
}
|
|
|
|
|
|
void CHexBuffer::setShowCursor( bool showCursor )
|
|
{
|
|
mShowCursor = showCursor;
|
|
}
|
|
|
|
|
|
void CHexBuffer::setDisableCursor( bool disableCursor )
|
|
{
|
|
mDisableCursor = disableCursor;
|
|
}
|
|
|
|
|
|
void CHexBuffer::setCursorShapeModifier( bool alwaysBlock, bool thickInsert )
|
|
{
|
|
mCursor.setShapeModifier( alwaysBlock, thickInsert );
|
|
setEditMode( mEditMode );
|
|
}
|
|
|
|
void CHexBuffer::setEditMode( EEditMode editMode, bool alwaysBlock,
|
|
bool thickInsert )
|
|
{
|
|
mCursor.setShapeModifier( alwaysBlock, thickInsert );
|
|
setEditMode( editMode );
|
|
}
|
|
|
|
void CHexBuffer::setEditMode( EEditMode editMode )
|
|
{
|
|
mEditMode = editMode;
|
|
if( mEditMode == EditInsert )
|
|
{
|
|
if( mActiveEditor == edit_primary )
|
|
{
|
|
mCursor.setShape( SCursorSpec::thin, SCursorSpec::frame, mUnitWidth,
|
|
mNumCell );
|
|
}
|
|
else
|
|
{
|
|
mCursor.setShape( SCursorSpec::frame, SCursorSpec::thin, mUnitWidth,
|
|
mNumCell );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if( mActiveEditor == edit_primary )
|
|
{
|
|
mCursor.setShape( SCursorSpec::solid, SCursorSpec::frame, mUnitWidth,
|
|
mNumCell );
|
|
}
|
|
else
|
|
{
|
|
mCursor.setShape( SCursorSpec::frame, SCursorSpec::solid, mUnitWidth,
|
|
mNumCell );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CHexBuffer::setMaximumSize( uint maximumSize )
|
|
{
|
|
if( maximumSize == 0 ) { maximumSize = ~0; }
|
|
|
|
mMaximumSize = maximumSize;
|
|
mFixedSizeMode = maximumSize == (uint)~0 ? false : true;
|
|
mCursor.setFixedSizeMode( mFixedSizeMode );
|
|
|
|
if( mLayout.offsetVisible == false )
|
|
{
|
|
mOffsetSize = 0;
|
|
mOffsetIndex = 0;
|
|
printOffset = &CHexBuffer::printDummyOffset;
|
|
}
|
|
else
|
|
{
|
|
if( mLayout.offsetMode == SDisplayLayout::decimal )
|
|
{
|
|
printOffset = &CHexBuffer::printDecimalOffset;
|
|
for( mOffsetSize=0; maximumSize > 0; mOffsetSize += 1 )
|
|
{
|
|
maximumSize = maximumSize / 10;
|
|
}
|
|
mOffsetIndex = 10 - mOffsetSize;
|
|
}
|
|
else if( mLayout.offsetMode == SDisplayLayout::hexadecimal )
|
|
{
|
|
if( mLayout.offsetUpperCase == true )
|
|
{
|
|
printOffset = &CHexBuffer::printHexadecimalBigOffset;
|
|
}
|
|
else
|
|
{
|
|
printOffset = &CHexBuffer::printHexadecimalSmallOffset;
|
|
}
|
|
for( mOffsetSize=0; maximumSize > 0; mOffsetSize += 1 )
|
|
{
|
|
maximumSize = maximumSize / 16;
|
|
}
|
|
if( mOffsetSize > 4 ) { mOffsetSize += 1; } // Space for the ':' sign
|
|
mOffsetIndex = 9 - mOffsetSize;
|
|
}
|
|
else
|
|
{
|
|
mLayout.offsetVisible = false;
|
|
mOffsetSize = 0;
|
|
mOffsetIndex = 0;
|
|
printOffset = &CHexBuffer::printDummyOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CHexBuffer::setDocumentSize( uint size )
|
|
{
|
|
if( size > mMaximumSize ) { size = mMaximumSize; }
|
|
mDocumentSize = size;
|
|
mCursor.setDocumentSize( size );
|
|
updateBookmarkMap(true);
|
|
}
|
|
|
|
|
|
void CHexBuffer::setUndoLevel( uint level )
|
|
{
|
|
if( level < 10 ) { level = 10; }
|
|
|
|
if( level >= mUndoLimit )
|
|
{
|
|
mUndoLimit = level;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The maximum size decreases. If the list is larger than the the new
|
|
// limit, then reduce the list size starting with the oldest elements.
|
|
//
|
|
mUndoLimit = level;
|
|
while( mUndoList.count() >= mUndoLimit )
|
|
{
|
|
mUndoList.removeFirst();
|
|
mUndoIndex -= (mUndoIndex > 0 ? 1 : 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CHexBuffer::setSoundState( bool inputSound, bool fatalSound )
|
|
{
|
|
mInputErrorSound = inputSound;
|
|
mFatalErrorSound = fatalSound;
|
|
}
|
|
|
|
|
|
void CHexBuffer::setBookmarkVisibility( bool showInColumn, bool showInEditor )
|
|
{
|
|
mShowBookmarkInOffsetColumn = showInColumn;
|
|
mShowBookmarkInEditor = showInEditor;
|
|
}
|
|
|
|
int CHexBuffer::writeFile( TQFile &file, CProgress &p )
|
|
{
|
|
uint offset = 0;
|
|
uint remaining = documentSize();
|
|
|
|
do
|
|
{
|
|
const uint blockSize = TQMIN( 131072 /* == 1024 * 128 */ , remaining );
|
|
const int writeSize = file.writeBlock( data() + offset, blockSize );
|
|
if( writeSize == -1 )
|
|
{
|
|
p.finish();
|
|
return( Err_ReadFailed );
|
|
}
|
|
offset += blockSize;
|
|
remaining -= blockSize;
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)offset/(float)documentSize() );
|
|
if( errCode == Err_Stop && remaining > 0 )
|
|
{
|
|
p.finish();
|
|
return( Err_Success );
|
|
}
|
|
}
|
|
}
|
|
while( remaining > 0 );
|
|
|
|
p.finish();
|
|
mDocumentModified = false;
|
|
registerDiskModifyTime( file );
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::readFile( TQFile &file, const TQString &url, CProgress &p )
|
|
{
|
|
if( resize( file.size() + 100 ) == false )
|
|
{
|
|
p.finish();
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
if( file.size() > 0 )
|
|
{
|
|
mLoadingData = true;
|
|
uint offset = 0;
|
|
uint remaining = file.size();
|
|
while( remaining > 0 )
|
|
{
|
|
const uint blockSize = TQMIN( 131072 /* == 1024 * 128 */ , remaining );
|
|
const int readSize = file.readBlock( data() + offset, blockSize );
|
|
if( readSize == -1 )
|
|
{
|
|
p.finish();
|
|
mLoadingData = false;
|
|
return( Err_ReadFailed );
|
|
}
|
|
for( uint i=0; i<blockSize; i++)
|
|
{
|
|
data()[offset+i] = mEncode[ (unsigned char) data()[offset+i] ];
|
|
}
|
|
|
|
offset += blockSize;
|
|
remaining -= blockSize;
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)offset/(float)file.size() );
|
|
if( errCode == Err_Stop && remaining > 0 )
|
|
{
|
|
p.finish();
|
|
return( Err_OperationAborted );
|
|
}
|
|
}
|
|
}
|
|
mLoadingData = false;
|
|
}
|
|
|
|
p.finish();
|
|
|
|
mDocumentModified = false;
|
|
setDocumentSize( file.size() );
|
|
registerDiskModifyTime( file );
|
|
setUrl( url );
|
|
computeNumLines();
|
|
mSelect.reset();
|
|
mMark.reset();
|
|
mUndoList.clear();
|
|
mUndoIndex = 0;
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::insertFile( TQFile &file, CProgress &p )
|
|
{
|
|
if( file.size() == 0 )
|
|
{
|
|
p.finish();
|
|
return( Err_Success );
|
|
}
|
|
|
|
TQByteArray array( file.size() );
|
|
if( array.isNull() == true )
|
|
{
|
|
p.finish();
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
uint offset = 0;
|
|
uint remaining = file.size();
|
|
while( remaining > 0 )
|
|
{
|
|
const uint blockSize = TQMIN( 131072 /* == 1024 * 128 */ , remaining );
|
|
const int readSize = file.readBlock( array.data() + offset, blockSize );
|
|
if( readSize == -1 )
|
|
{
|
|
p.finish();
|
|
return( Err_ReadFailed );
|
|
}
|
|
for( uint i=0; i<blockSize; i++)
|
|
{
|
|
array[offset+i] = mEncode[ (unsigned char) array[offset+i] ];
|
|
}
|
|
|
|
offset += blockSize;
|
|
remaining -= blockSize;
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)offset/(float)file.size() );
|
|
if( errCode == Err_Stop && remaining > 0 )
|
|
{
|
|
p.finish();
|
|
return( Err_OperationAborted );
|
|
}
|
|
}
|
|
}
|
|
|
|
p.finish();
|
|
|
|
int errCode = inputAtCursor( array, 0 );
|
|
return( errCode );
|
|
}
|
|
|
|
|
|
int CHexBuffer::newFile( const TQString &url )
|
|
{
|
|
if( resize( 100 ) == 0 )
|
|
{
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
mDocumentModified = false;
|
|
setDocumentSize( 0 );
|
|
setUrl( url );
|
|
computeNumLines();
|
|
mSelect.reset();
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
void CHexBuffer::closeFile( void )
|
|
{
|
|
resize(0);
|
|
computeNumLines();
|
|
|
|
mUndoList.clear();
|
|
mUndoIndex = 0;
|
|
|
|
setDocumentSize(0);
|
|
mDocumentModified = false;
|
|
|
|
TQString emptyUrl;
|
|
setUrl( emptyUrl );
|
|
|
|
mSelect.reset();
|
|
mMark.reset();
|
|
|
|
removeBookmark(-1); // Negative index - All bookmarks
|
|
}
|
|
|
|
|
|
void CHexBuffer::registerDiskModifyTime( const TQFile &file )
|
|
{
|
|
TQFileInfo fileInfo( file );
|
|
mDiskModifyTime = fileInfo.lastModified();
|
|
}
|
|
|
|
|
|
|
|
void CHexBuffer::setFont( const SDisplayFontInfo &fontInfo )
|
|
{
|
|
mFontInfo = fontInfo;
|
|
TQFontMetrics fm( mFontInfo.font );
|
|
mFontHeight = fm.height();
|
|
mFontAscent = fm.ascent();
|
|
computeLineWidth();
|
|
|
|
for( int i=0; i < 256; i++ )
|
|
{
|
|
mCharValid[i] = TQChar(i).isPrint();
|
|
}
|
|
|
|
/*
|
|
TQFontInfo info( mFontInfo.font );
|
|
puts("CHexBuffer mCharValid broken");
|
|
|
|
KCharset charset( info.charSet() );
|
|
for( int i=0; i < 256; i++ )
|
|
{
|
|
mCharValid[i] = charset.printable(i);
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
int CHexBuffer::setEncoding( CConversion::EMode mode, CProgress &p )
|
|
{
|
|
int errCode = mEncode.convert( *this, mode, p );
|
|
if( errCode == Err_Success )
|
|
{
|
|
//
|
|
// The cursor stores the byte it is "covering", so this information
|
|
// must be updated.
|
|
//
|
|
cursorCompute();
|
|
}
|
|
|
|
return( errCode );
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHexBuffer::computeLineWidth( void )
|
|
{
|
|
TQFontMetrics fm( mFontInfo.font );
|
|
mUnitWidth = fm.width( "M" );
|
|
|
|
if( mLayout.primaryMode == SDisplayLayout::textOnly )
|
|
{
|
|
mSplitWidth = 0;
|
|
}
|
|
else if( mLayout.columnCharSpace == true )
|
|
{
|
|
mSplitWidth = mUnitWidth;
|
|
}
|
|
else
|
|
{
|
|
mSplitWidth = mLayout.columnSpacing;
|
|
}
|
|
|
|
setMaximumSize( mMaximumSize );
|
|
|
|
if( mLayout.primaryMode == SDisplayLayout::hexadecimal )
|
|
{
|
|
mNumCell = 2;
|
|
mCursor.setCellWeight( 4 );
|
|
if( mLayout.primaryUpperCase == true )
|
|
{
|
|
printCell = &CHexBuffer::printHexadecimalBigCell;
|
|
inputCell = &CHexBuffer::inputHexadecimal;
|
|
}
|
|
else
|
|
{
|
|
printCell = &CHexBuffer::printHexadecimalSmallCell;
|
|
inputCell = &CHexBuffer::inputHexadecimal;
|
|
}
|
|
}
|
|
else if( mLayout.primaryMode == SDisplayLayout::decimal )
|
|
{
|
|
mNumCell = 3;
|
|
printCell = &CHexBuffer::printDecimalCell;
|
|
inputCell = &CHexBuffer::inputDecimal;
|
|
mCursor.setCellWeight( 3 );
|
|
}
|
|
else if( mLayout.primaryMode == SDisplayLayout::octal )
|
|
{
|
|
mNumCell = 3;
|
|
printCell = &CHexBuffer::printOctalCell;
|
|
inputCell = &CHexBuffer::inputOctal;
|
|
mCursor.setCellWeight( 3 );
|
|
}
|
|
else if( mLayout.primaryMode == SDisplayLayout::binary )
|
|
{
|
|
mNumCell = 8;
|
|
printCell = &CHexBuffer::printBinaryCell;
|
|
inputCell = &CHexBuffer::inputBinary;
|
|
mCursor.setCellWeight( 1 );
|
|
}
|
|
else if( mLayout.primaryMode == SDisplayLayout::textOnly )
|
|
{
|
|
mNumCell = 1;
|
|
printCell = &CHexBuffer::printAsciiCell;
|
|
inputCell = &CHexBuffer::inputAscii;
|
|
mCursor.setCellWeight( 8 );
|
|
}
|
|
else
|
|
{
|
|
mNumCell = 2;
|
|
mLayout.primaryMode = SDisplayLayout::hexadecimal;
|
|
mLayout.primaryUpperCase = false;
|
|
printCell = &CHexBuffer::printHexadecimalSmallCell;
|
|
inputCell = &CHexBuffer::inputHexadecimal;
|
|
mCursor.setCellWeight( 4 );
|
|
}
|
|
|
|
//
|
|
// 'mPrimaryWidth' is the number of pixels that are needed to display a
|
|
// line in the primary field.
|
|
//
|
|
mPrimaryWidth = mLayout.lineSize * mNumCell * mUnitWidth;
|
|
|
|
if( mLayout.columnSpacing != 0 )
|
|
{
|
|
int numSplit = mLayout.lineSize / mLayout.columnSize;
|
|
numSplit -= mLayout.lineSize % mLayout.columnSize == 0 ? 1 : 0;
|
|
mPrimaryWidth += numSplit * mSplitWidth;
|
|
}
|
|
|
|
//
|
|
// 'mSecondaryWidth' is the number of pixels that are needed to display a
|
|
// line in the secondary field (there are no spaces).
|
|
//
|
|
if( mLayout.secondaryMode == SDisplayLayout::hide )
|
|
{
|
|
mSecondaryWidth = 0;
|
|
}
|
|
else
|
|
{
|
|
mSecondaryWidth = mLayout.lineSize * mUnitWidth;
|
|
}
|
|
|
|
//
|
|
// 'mLineWidth' is the total number of pixels required to display
|
|
// offset data, separators, primary and secondary data on a line.
|
|
//
|
|
mLineWidth = mPrimaryWidth + mSecondaryWidth + mOffsetSize * mUnitWidth;
|
|
|
|
//
|
|
// The 'mFixedWidth' is the number of pixels of the width that stays the
|
|
// same regardless of how many characters that are displayed.
|
|
// This entity consists of the edge margins, the inner margins and the
|
|
// separators.
|
|
//
|
|
mFixedWidth = mOffsetSize * mUnitWidth;
|
|
|
|
//
|
|
// The edge margin is always present in both ends.
|
|
//
|
|
mLineWidth += mLayout.edgeMarginWidth * 2;
|
|
mFixedWidth += mLayout.edgeMarginWidth * 2;
|
|
|
|
//
|
|
// 'mTextStart1' is the number of pixels from the left edge where the
|
|
// primary field starts.
|
|
//
|
|
mTextStart1 = mLayout.edgeMarginWidth;
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
int width;
|
|
if( mLayout.leftSeparatorWidth > 0 )
|
|
{
|
|
width = mLayout.separatorMarginWidth * 2 + mLayout.leftSeparatorWidth;
|
|
}
|
|
else
|
|
{
|
|
width = (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
|
|
mLineWidth += width;
|
|
mFixedWidth += width;
|
|
mTextStart1 += width + mOffsetSize * mUnitWidth;
|
|
}
|
|
|
|
//
|
|
// 'mTextStart2' is the number of pixels from the left edge where the
|
|
// secondary fields start.
|
|
//
|
|
mTextStart2 = mTextStart1;
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
int width;
|
|
if( mLayout.rightSeparatorWidth > 0 )
|
|
{
|
|
width = mLayout.separatorMarginWidth * 2 + mLayout.rightSeparatorWidth;
|
|
}
|
|
else
|
|
{
|
|
width = (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
|
|
mLineWidth += width;
|
|
mFixedWidth += width;
|
|
mTextStart2 += width + mPrimaryWidth;
|
|
}
|
|
|
|
setEditMode( mEditMode );
|
|
computeNumLines();
|
|
}
|
|
|
|
|
|
void CHexBuffer::computeNumLines( void )
|
|
{
|
|
if( mLayout.lineSize == 0 )
|
|
{
|
|
mNumLines = 1;
|
|
}
|
|
else
|
|
{
|
|
uint s = mFixedSizeMode == true ? mMaximumSize : documentSize() + 1;
|
|
mNumLines = s / mLayout.lineSize + (s % mLayout.lineSize ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CHexBuffer::drawSelection( TQPainter &paint, TQColor &color, uint start,
|
|
uint stop, int sx )
|
|
{
|
|
if( start >= stop ) { return; }
|
|
uint width = stop - start;
|
|
|
|
uint addStart, addWidth;
|
|
addStart = (start / mLayout.columnSize) * mSplitWidth;
|
|
if( width == 0 )
|
|
{
|
|
addWidth = 0;
|
|
}
|
|
else
|
|
{
|
|
uint g = mLayout.columnSize;
|
|
addWidth = (((start % g) + width - 1) / g) * mSplitWidth;
|
|
}
|
|
|
|
int offset = mTextStart1 - sx;
|
|
paint.fillRect( offset + start * mNumCell * mUnitWidth + addStart,
|
|
0, width * mNumCell * mUnitWidth + addWidth,
|
|
mFontHeight, color );
|
|
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
offset = mTextStart2 - sx;
|
|
paint.fillRect( offset + start * mUnitWidth,
|
|
0, width * mUnitWidth,
|
|
mFontHeight, color );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CHexBuffer::drawText( TQPainter &paint, uint line, int sx, int x1, int x2 )
|
|
{
|
|
uint fileOffset = line * mLayout.lineSize;
|
|
if( documentPresent() == false || mLoadingData == true )
|
|
{
|
|
paint.fillRect( x1, 0, x2-x1, lineHeight(), mColor.inactiveBg );
|
|
return;
|
|
}
|
|
|
|
bool outsideText;
|
|
if( size() == 0 || fileOffset > documentSize() || fileOffset >= mMaximumSize)
|
|
{
|
|
outsideText = true;
|
|
}
|
|
else
|
|
{
|
|
outsideText = false;
|
|
}
|
|
|
|
if( (line+1) % 2 || outsideText == true )
|
|
{
|
|
paint.fillRect( x1, 0, x2-x1, lineHeight(), mColor.textBg );
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( x1, 0, x2-x1, lineHeight(), mColor.secondTextBg );
|
|
}
|
|
if( mLayout.horzGridWidth > 0 && outsideText == false )
|
|
{
|
|
paint.setPen( mColor.gridFg );
|
|
paint.drawLine( x1, mFontHeight, x2, mFontHeight );
|
|
}
|
|
|
|
if( mSelect.inside( fileOffset, mLayout.lineSize ) == true )
|
|
{
|
|
uint start = mSelect.start( fileOffset );
|
|
uint stop = mSelect.stop( fileOffset, mLayout.lineSize );
|
|
drawSelection( paint, mColor.selectBg, start, stop, sx );
|
|
}
|
|
|
|
//
|
|
// A marked area will be displayed "above" a selcted area (given
|
|
// the mark background color is different)
|
|
//
|
|
if( mMark.inside( fileOffset, mLayout.lineSize ) == true )
|
|
{
|
|
uint start = mMark.start( fileOffset );
|
|
uint stop = mMark.stop( fileOffset, mLayout.lineSize );
|
|
drawSelection( paint, mColor.markBg, start, stop, sx );
|
|
}
|
|
|
|
uint dataSize;
|
|
unsigned char *fileData;
|
|
if( outsideText == true )
|
|
{
|
|
if( size() == 0 )
|
|
{
|
|
return;
|
|
}
|
|
dataSize = 0;
|
|
fileData = 0;
|
|
}
|
|
else
|
|
{
|
|
dataSize = documentSize() - fileOffset;
|
|
if( dataSize > mLayout.lineSize ) { dataSize = mLayout.lineSize; }
|
|
fileData = (unsigned char*)&(data()[ fileOffset ]);
|
|
}
|
|
|
|
//
|
|
// Compute the offset area size. We postpose the actual drawing
|
|
// until we have drawn any bookmark indicators in the editor areas.
|
|
// because we may want to draw an indicator in the offset area as well.
|
|
//
|
|
int offset = mLayout.edgeMarginWidth - sx;
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
offset += mOffsetSize * mUnitWidth;
|
|
if( mLayout.leftSeparatorWidth > 0 )
|
|
{
|
|
offset += mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth*2;
|
|
}
|
|
else
|
|
{
|
|
offset += (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
int offset = mLayout.edgeMarginWidth - sx;
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
int s0 = mOffsetSize * mUnitWidth;
|
|
int s1 = s0 + mLayout.separatorMarginWidth + mLayout.edgeMarginWidth - sx;
|
|
if( x1 < s1 && x2 > 0 )
|
|
{
|
|
if( outsideText == true )
|
|
{
|
|
paint.fillRect( 0, 0, s1, lineHeight(), mColor.offsetBg );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// I want to display the grid here so I cant use lineHeight()
|
|
//
|
|
paint.fillRect( 0, 0, s1, mFontHeight, mColor.offsetBg );
|
|
}
|
|
}
|
|
|
|
if( x1 < offset + s0 && x2 >= offset && fileData != 0 )
|
|
{
|
|
paint.setPen( mColor.offsetFg );
|
|
THIS_FPTR(printOffset)( mPrintBuf, fileOffset );
|
|
// ## paint.drawText(offset,mFontAscent,&mPrintBuf[mOffsetIndex],
|
|
// mOffsetSize);
|
|
paint.drawText( offset, mFontAscent,
|
|
TQString::fromLocal8Bit(&mPrintBuf[mOffsetIndex]),
|
|
mOffsetSize );
|
|
}
|
|
offset += s0;
|
|
|
|
if( mLayout.leftSeparatorWidth > 0 )
|
|
{
|
|
offset += mLayout.separatorMarginWidth;
|
|
|
|
int s2 = mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth;
|
|
if( x1 < offset + s2 && x2 >= offset )
|
|
{
|
|
TQPen pen( mColor.leftSeparatorFg, mLayout.leftSeparatorWidth );
|
|
paint.setPen( pen );
|
|
int center = offset + mLayout.leftSeparatorWidth/2;
|
|
paint.drawLine( center, 0, center, lineHeight() );
|
|
}
|
|
offset += s2;
|
|
}
|
|
else
|
|
{
|
|
offset += (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Draw the primary area
|
|
//
|
|
int localOffset = offset;
|
|
for( uint i = 0; i < dataSize; i++ )
|
|
{
|
|
int s = mNumCell * mUnitWidth +
|
|
((i+1) % mLayout.columnSize == 0) * mSplitWidth;
|
|
if( x1 < localOffset + s && x2 >= localOffset )
|
|
{
|
|
int flag = THIS_FPTR(printCell)( mPrintBuf, fileData[i] );
|
|
if( mSelect.inside( fileOffset+i ) )
|
|
{
|
|
paint.setPen( mColor.selectFg );
|
|
}
|
|
else if( mMark.inside( fileOffset+i ) )
|
|
{
|
|
paint.setPen( mColor.markFg );
|
|
}
|
|
else
|
|
{
|
|
paint.setPen( flag == 0 ? foregroundColor( i ) : mColor.nonPrintFg );
|
|
}
|
|
|
|
// ## paint.drawText( localOffset, mFontAscent, mPrintBuf, mNumCell );
|
|
paint.drawText( localOffset, mFontAscent,
|
|
TQString::fromLocal8Bit(mPrintBuf), mNumCell );
|
|
}
|
|
localOffset += s;
|
|
|
|
if( mLayout.vertGridWidth > 0 && i+1 < dataSize )
|
|
{
|
|
if( (i+1) % mLayout.columnSize == 0 )
|
|
{
|
|
paint.setPen( mColor.gridFg );
|
|
int x = localOffset - (mSplitWidth+1) / 2;
|
|
paint.drawLine( x, 0, x, mFontHeight );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the secondary area
|
|
//
|
|
offset += mPrimaryWidth;
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
if( mLayout.rightSeparatorWidth > 0 )
|
|
{
|
|
offset += mLayout.separatorMarginWidth;
|
|
int s = mLayout.separatorMarginWidth + mLayout.rightSeparatorWidth;
|
|
if( x1 < offset + s && x2 >= offset )
|
|
{
|
|
TQPen pen( mColor.rightSeparatorFg, mLayout.rightSeparatorWidth );
|
|
paint.setPen( pen );
|
|
int center = offset + mLayout.rightSeparatorWidth/2;
|
|
paint.drawLine( center, 0, center, lineHeight() );
|
|
}
|
|
offset += s;
|
|
}
|
|
else
|
|
{
|
|
offset += (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
|
|
int s = mUnitWidth;
|
|
for( uint i = 0; i < dataSize; i++ )
|
|
{
|
|
if( x1 < offset + s && x2 >= offset )
|
|
{
|
|
int flag = printAsciiCell( mPrintBuf, fileData[i] );
|
|
if( mSelect.inside( fileOffset+i ) )
|
|
{
|
|
paint.setPen( mColor.selectFg );
|
|
}
|
|
else if( mMark.inside( fileOffset+i ) )
|
|
{
|
|
paint.setPen( mColor.markFg );
|
|
}
|
|
else
|
|
{
|
|
paint.setPen( flag == 0 ? mColor.secondaryFg : mColor.nonPrintFg );
|
|
}
|
|
|
|
// ## paint.drawText( offset, mFontAscent, mPrintBuf, 1 );
|
|
paint.drawText( offset, mFontAscent,
|
|
TQString::fromLocal8Bit(mPrintBuf), 1 );
|
|
}
|
|
offset += s;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the bookmark identifiers on this line (if any). We use the
|
|
// bitmask to minimize the number of times we try to draw the bookmarks.
|
|
//
|
|
int bookmarkPosition = 0;
|
|
if( mBookmarkMap.testBit(fileOffset/200) ||
|
|
mBookmarkMap.testBit((fileOffset+mLayout.lineSize-1)/200 ) )
|
|
{
|
|
// Returns a bookmark postion state
|
|
bookmarkPosition = drawBookmarks( paint, line, sx );
|
|
}
|
|
|
|
//
|
|
// Draw the offset area. We have delayed the drawing until now because
|
|
// it is possible to draw a bookmark indicator in this area.
|
|
//
|
|
offset = mLayout.edgeMarginWidth - sx;
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
int s0 = mOffsetSize * mUnitWidth;
|
|
int s1 = s0 + mLayout.separatorMarginWidth + mLayout.edgeMarginWidth - sx;
|
|
if( x1 < s1 && x2 > 0 )
|
|
{
|
|
TQColor bg = mShowBookmarkInOffsetColumn &&
|
|
(bookmarkPosition & BookmarkOnLine) ?
|
|
mColor.bookmarkBg : mColor.offsetBg;
|
|
if( outsideText == true )
|
|
{
|
|
paint.fillRect( 0, 0, s1, lineHeight(), bg );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// I want to display the grid here so I cant use lineHeight()
|
|
//
|
|
paint.fillRect( 0, 0, s1, mFontHeight, bg );
|
|
}
|
|
}
|
|
|
|
if( x1 < offset + s0 && x2 >= offset && fileData != 0 )
|
|
{
|
|
paint.setPen( mShowBookmarkInOffsetColumn &&
|
|
bookmarkPosition & BookmarkOnLine ?
|
|
mColor.bookmarkFg : mColor.offsetFg );
|
|
THIS_FPTR(printOffset)( mPrintBuf, fileOffset );
|
|
// ## paint.drawText(offset,mFontAscent,&mPrintBuf[mOffsetIndex],
|
|
// mOffsetSize);
|
|
paint.drawText( offset, mFontAscent,
|
|
TQString::fromLocal8Bit(&mPrintBuf[mOffsetIndex]),
|
|
mOffsetSize );
|
|
}
|
|
|
|
offset += s0;
|
|
|
|
if( mLayout.leftSeparatorWidth > 0 )
|
|
{
|
|
offset += mLayout.separatorMarginWidth;
|
|
|
|
int s2 = mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth;
|
|
if( x1 < offset + s2 && x2 >= offset )
|
|
{
|
|
TQPen pen( mColor.leftSeparatorFg, mLayout.leftSeparatorWidth );
|
|
paint.setPen( pen );
|
|
int center = offset + mLayout.leftSeparatorWidth/2;
|
|
paint.drawLine( center, 0, center, lineHeight() );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the cursors are located on the line we have drawn we redraw
|
|
// them unless they have been disabled.
|
|
//
|
|
if( mDisableCursor == false )
|
|
{
|
|
if( mCursor.curr.inside( fileOffset, fileOffset + mLayout.lineSize ) )
|
|
{
|
|
drawCursor( paint, line, sx, bookmarkPosition & BookmarkOnCursor );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHexBuffer::drawText( TQPainter &paint, uint line, int x1, int x2, int y,
|
|
bool useBlackWhite )
|
|
{
|
|
uint fileOffset = line * mLayout.lineSize;
|
|
|
|
bool outsideText;
|
|
if( size() == 0 || fileOffset > documentSize() || fileOffset >= mMaximumSize)
|
|
{
|
|
outsideText = true;
|
|
}
|
|
else
|
|
{
|
|
outsideText = false;
|
|
}
|
|
|
|
if( (line+1) % 2 || outsideText == true )
|
|
{
|
|
paint.fillRect( x1, y, x2, lineHeight(),
|
|
useBlackWhite == true ? TQt::white : mColor.textBg );
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( x1, y, x2, lineHeight(),
|
|
useBlackWhite == true ? TQt::white : mColor.secondTextBg );
|
|
}
|
|
|
|
if( mLayout.horzGridWidth > 0 && outsideText == false )
|
|
{
|
|
TQPen pen( useBlackWhite == true ? TQt::black : mColor.gridFg,
|
|
mLayout.horzGridWidth );
|
|
paint.setPen( pen );
|
|
paint.drawLine( x1, y+mFontHeight, x2+x1, y+mFontHeight );
|
|
}
|
|
|
|
uint dataSize;
|
|
unsigned char *fileData;
|
|
if( outsideText == true )
|
|
{
|
|
if( size() == 0 )
|
|
{
|
|
return;
|
|
}
|
|
dataSize = 0;
|
|
fileData = 0;
|
|
}
|
|
else
|
|
{
|
|
dataSize = documentSize() - fileOffset;
|
|
if( dataSize > mLayout.lineSize ) { dataSize = mLayout.lineSize; }
|
|
fileData = (unsigned char*)&(data()[ fileOffset ]);
|
|
}
|
|
|
|
int offset = mLayout.edgeMarginWidth + x1;
|
|
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
int s1 = mOffsetSize * mUnitWidth;
|
|
if( fileData != 0 )
|
|
{
|
|
paint.setPen( useBlackWhite == true ? TQt::black : mColor.offsetFg );
|
|
THIS_FPTR(printOffset)( mPrintBuf, fileOffset );
|
|
// ## paint.drawText( offset, mFontAscent+y, &mPrintBuf[mOffsetIndex],
|
|
// mOffsetSize );
|
|
paint.drawText( offset, mFontAscent+y,
|
|
TQString::fromLocal8Bit(&mPrintBuf[mOffsetIndex]),
|
|
mOffsetSize );
|
|
}
|
|
offset += s1;
|
|
|
|
if( mLayout.leftSeparatorWidth > 0 )
|
|
{
|
|
offset += mLayout.separatorMarginWidth;
|
|
|
|
int s2 = mLayout.leftSeparatorWidth + mLayout.separatorMarginWidth;
|
|
TQPen pen( useBlackWhite == true ? TQt::black : mColor.leftSeparatorFg,
|
|
mLayout.leftSeparatorWidth );
|
|
paint.setPen( pen );
|
|
int center = offset + mLayout.leftSeparatorWidth/2;
|
|
paint.drawLine( center, y, center, mFontHeight+y );
|
|
offset += s2;
|
|
}
|
|
else
|
|
{
|
|
offset += (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
}
|
|
|
|
int localOffset = offset;
|
|
for( uint i = 0; i < dataSize; i++ )
|
|
{
|
|
int s = mNumCell * mUnitWidth +
|
|
((i+1) % mLayout.columnSize == 0) * mSplitWidth;
|
|
int flag = THIS_FPTR(printCell)( mPrintBuf, fileData[i] );
|
|
if( useBlackWhite == true )
|
|
{
|
|
paint.setPen( TQt::black );
|
|
}
|
|
else
|
|
{
|
|
paint.setPen( flag == 0 ? foregroundColor( i ) : mColor.nonPrintFg );
|
|
}
|
|
// ## paint.drawText( localOffset, mFontAscent+y, mPrintBuf, mNumCell );
|
|
paint.drawText( localOffset, mFontAscent+y,
|
|
TQString::fromLocal8Bit(mPrintBuf), mNumCell );
|
|
localOffset += s;
|
|
|
|
if( mLayout.vertGridWidth > 0 && i+1 < dataSize )
|
|
{
|
|
if( (i+1) % mLayout.columnSize == 0 )
|
|
{
|
|
TQPen pen( useBlackWhite == true ? TQt::black : mColor.gridFg,
|
|
mLayout.vertGridWidth );
|
|
paint.setPen( pen );
|
|
int x = localOffset - (mSplitWidth+1) / 2;
|
|
paint.drawLine( x, y, x, y+mFontHeight );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
offset += mPrimaryWidth;
|
|
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
if( mLayout.rightSeparatorWidth > 0 )
|
|
{
|
|
offset += mLayout.separatorMarginWidth;
|
|
int s = mLayout.separatorMarginWidth + mLayout.rightSeparatorWidth;
|
|
TQPen pen( useBlackWhite == true ? TQt::black : mColor.rightSeparatorFg,
|
|
mLayout.rightSeparatorWidth );
|
|
paint.setPen( pen );
|
|
int center = offset + mLayout.rightSeparatorWidth/2;
|
|
paint.drawLine( center, y, center, mFontHeight+y );
|
|
offset += s;
|
|
}
|
|
else
|
|
{
|
|
offset += (mLayout.separatorMarginWidth * 3) / 2;
|
|
}
|
|
|
|
|
|
int s = mUnitWidth;
|
|
for( uint i = 0; i < dataSize; i++ )
|
|
{
|
|
int flag = printAsciiCell( mPrintBuf, fileData[i] );
|
|
if( useBlackWhite == true )
|
|
{
|
|
paint.setPen( TQt::black );
|
|
}
|
|
else
|
|
{
|
|
paint.setPen( flag == 0 ? mColor.secondaryFg : mColor.nonPrintFg );
|
|
}
|
|
// ## paint.drawText( offset, mFontAscent+y, mPrintBuf, 1 );
|
|
paint.drawText( offset, mFontAscent+y,
|
|
TQString::fromLocal8Bit(mPrintBuf), 1 );
|
|
offset += s;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
int CHexBuffer::headerHeight( TQPainter &paint )
|
|
{
|
|
TQFont font( paint.font() );
|
|
paint.setFont( TDEGlobalSettings::generalFont() );
|
|
const TQFontMetrics &fm = paint.fontMetrics();
|
|
|
|
int height = fm.height();
|
|
paint.setFont( font );
|
|
return( height );
|
|
}
|
|
|
|
int CHexBuffer::headerMargin( TQPainter &paint )
|
|
{
|
|
TQFont font( paint.font() );
|
|
paint.setFont( TDEGlobalSettings::generalFont() );
|
|
const TQFontMetrics &fm = paint.fontMetrics();
|
|
|
|
int margin = fm.height() / 2;
|
|
paint.setFont( font );
|
|
return( margin );
|
|
}
|
|
|
|
|
|
void CHexBuffer::drawHeader( TQPainter &paint, int sx, int width, int y,
|
|
bool isFooter, const SPageHeader &header,
|
|
const SPagePosition &position )
|
|
{
|
|
TQFont font( paint.font() );
|
|
paint.setFont( TDEGlobalSettings::generalFont() );
|
|
const TQFontMetrics &fm = paint.fontMetrics();
|
|
|
|
paint.fillRect( sx, y, width, fm.height(), TQt::white );
|
|
paint.setPen( TQt::black );
|
|
if( header.line == SPageHeader::SingleLine )
|
|
{
|
|
if( isFooter == false )
|
|
{
|
|
paint.drawLine( sx, y+fm.height(), sx+width, y+fm.height() );
|
|
}
|
|
else
|
|
{
|
|
paint.drawLine( sx, y, sx+width, y );
|
|
}
|
|
}
|
|
else if( header.line == SPageHeader::Rectangle )
|
|
{
|
|
paint.drawRect( sx, y, width, fm.height() );
|
|
}
|
|
|
|
int pos[3] =
|
|
{
|
|
TQPainter::AlignLeft, TQPainter::AlignHCenter, TQPainter::AlignRight
|
|
};
|
|
|
|
TQString msg;
|
|
for( int i=0; i<3; i++ )
|
|
{
|
|
if( header.pos[i] == SPageHeader::DateTime )
|
|
{
|
|
TQDateTime datetime;
|
|
datetime.setTime_t( position.now );
|
|
msg = TDEGlobal::locale()->formatDateTime(datetime);
|
|
}
|
|
else if( header.pos[i] == SPageHeader::PageNumber )
|
|
{
|
|
msg = i18n("Page %1 of %2")
|
|
.arg(TDEGlobal::locale()->formatNumber(position.curPage, 0))
|
|
.arg(TDEGlobal::locale()->formatNumber(position.maxPage, 0));
|
|
}
|
|
else if( header.pos[i] == SPageHeader::FileName )
|
|
{
|
|
msg = mUrl;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( 0 && pos[i] == TQPainter::AlignRight )
|
|
{
|
|
//const TQFontMetrics &f = TQFontMetrics( TDEGlobalSettings::generalFont() );
|
|
//TQRect r = paint.boundingRect(sx, y, width, fm.height(), pos[i], msg );
|
|
//printf("R: %d, %d, %d, %d\n", r.x(), r.y(), r.width(), r.height() );
|
|
|
|
int x = sx + width - /*r.width();*/ fm.width(msg);
|
|
paint.drawText( x, y+fm.height(), msg );
|
|
//printf("paint at %d\n", x );
|
|
}
|
|
else
|
|
{
|
|
paint.drawText( sx, y, width, fm.height(), pos[i], msg );
|
|
}
|
|
}
|
|
|
|
//
|
|
// restore original font.
|
|
//
|
|
paint.setFont( font );
|
|
}
|
|
|
|
|
|
|
|
|
|
int CHexBuffer::drawBookmarks( TQPainter &paint, uint line, int startx )
|
|
{
|
|
if( documentPresent() == false || mLoadingData == true )
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
uint start = line*mLayout.lineSize;
|
|
uint stop = start+mLayout.lineSize;
|
|
TQColor bg = mColor.bookmarkBg;
|
|
TQColor fg = mColor.bookmarkFg;
|
|
|
|
int bookmarkPosition = 0;
|
|
|
|
for( SCursorOffset *c=mBookmarkList.first(); c!=0; c=mBookmarkList.next() )
|
|
{
|
|
if( c->offset >= start && c->offset < stop )
|
|
{
|
|
int x = c->offset - start;
|
|
int x1 = mTextStart1 + x * mUnitWidth * mNumCell;
|
|
x1 += (x / mLayout.columnSize) * mSplitWidth;
|
|
int x2 = mTextStart2 + x * mUnitWidth;
|
|
|
|
bookmarkPosition |= BookmarkOnLine;
|
|
|
|
if( mShowBookmarkInEditor == false )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint offset = line*mLayout.lineSize+x;
|
|
if( offset == mCursor.curr.offset )
|
|
{
|
|
bookmarkPosition |= BookmarkOnCursor;
|
|
}
|
|
|
|
if( mSelect.inside( offset ) || mMark.inside( offset ) )
|
|
{
|
|
paint.fillRect( x1-startx, 2, mUnitWidth*mNumCell, mFontHeight-4, bg );
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
paint.fillRect( x2-startx, 2, mUnitWidth, mFontHeight-4, bg );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( x1-startx, 1, mUnitWidth*mNumCell, mFontHeight-2, bg );
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
paint.fillRect( x2-startx, 1, mUnitWidth, mFontHeight-2, bg );
|
|
}
|
|
}
|
|
|
|
unsigned char c = (data()[ line*mLayout.lineSize+x]);
|
|
|
|
int flag = THIS_FPTR(printCell)( mPrintBuf, c );
|
|
paint.setPen( flag == 0 ? fg : mColor.nonPrintFg );
|
|
// ## paint.drawText( x1-startx, mFontAscent, mPrintBuf, mNumCell );
|
|
paint.drawText( x1-startx, mFontAscent,
|
|
TQString::fromLocal8Bit(mPrintBuf), mNumCell );
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
flag = printAsciiCell( mPrintBuf, c );
|
|
paint.setPen( flag == 0 ? fg : mColor.nonPrintFg );
|
|
// ## paint.drawText( x2-startx, mFontAscent, mPrintBuf, 1 );
|
|
paint.drawText( x2-startx, mFontAscent,
|
|
TQString::fromLocal8Bit(mPrintBuf), 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
return bookmarkPosition;
|
|
}
|
|
|
|
|
|
|
|
void CHexBuffer::drawCursor( TQPainter &paint, uint line, int startx,
|
|
bool onBookmark )
|
|
{
|
|
if( documentPresent() == false || mLoadingData == true )
|
|
{
|
|
return;
|
|
}
|
|
|
|
SCursorSpec &c = mCursor.curr;
|
|
|
|
//
|
|
// Draw the cursor in primary edit area.
|
|
//
|
|
TQColor bg, fg;
|
|
bool useFg;
|
|
if( mMark.inside( c.offset ) == true )
|
|
{
|
|
bg = mColor.markBg;
|
|
fg = mSelect.inside( c.offset ) ? mColor.selectFg : mColor.markFg;
|
|
useFg = true;
|
|
}
|
|
else if( mSelect.inside( c.offset ) == true )
|
|
{
|
|
bg = mColor.selectBg;
|
|
fg = mColor.selectFg;
|
|
useFg = true;
|
|
}
|
|
else
|
|
{
|
|
bg = (line+1) % 2 ? mColor.textBg : mColor.secondTextBg;
|
|
fg = foregroundColor( c.offset % mLayout.lineSize );
|
|
useFg = false; // Can be true later.
|
|
}
|
|
|
|
TQColor cbg = mColor.cursorBg;
|
|
TQColor cfg = mColor.cursorFg;
|
|
|
|
//
|
|
// Fill in the general backround color
|
|
//
|
|
paint.fillRect( c.x1 - startx, 0, mUnitWidth, mFontHeight, bg );
|
|
if( onBookmark == true )
|
|
{
|
|
int w = mUnitWidth * (mNumCell-c.cell); // Rest of cell
|
|
if( useFg == true )
|
|
{
|
|
paint.fillRect( c.x1-startx, 2, w, mFontHeight-4, mColor.bookmarkBg );
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( c.x1-startx, 1, w, mFontHeight-2, mColor.bookmarkBg );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the cursor shape
|
|
//
|
|
bool transparent = false;
|
|
if( mActiveEditor == edit_primary )
|
|
{
|
|
if( mShowCursor == true ) // Cursor blink on
|
|
{
|
|
if( c.mPrimaryShape == SCursorSpec::thin )
|
|
{
|
|
paint.setPen( cbg );
|
|
int center = c.x1 - startx - 1;
|
|
transparent = true;
|
|
|
|
if( c.thickState == true )
|
|
{
|
|
paint.drawLine( center, 0, center, mFontHeight - 1 );
|
|
paint.drawLine( center+1, 0, center+1, mFontHeight - 1 );
|
|
}
|
|
else
|
|
{
|
|
paint.drawLine( center, 0, center, mFontHeight - 1 );
|
|
paint.drawLine( center-2, 0, center+2, 0 );
|
|
paint.drawLine( center-2, mFontHeight-1, center+2, mFontHeight-1 );
|
|
}
|
|
}
|
|
else // Solid block shape
|
|
{
|
|
paint.fillRect( c.x1 - startx, 0, mUnitWidth, mFontHeight, cbg );
|
|
useFg = true;
|
|
fg = cfg;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
transparent = true;
|
|
paint.setPen( cbg );
|
|
paint.drawRect( c.x1 - startx, 0, mUnitWidth*mNumCell, mFontHeight );
|
|
}
|
|
|
|
//
|
|
// Draw the text on the cursor position and to the end of the cell.
|
|
//
|
|
if( c.offset < documentSize() )
|
|
{
|
|
int flag = THIS_FPTR(printCell)( mPrintBuf, (unsigned char)c.data );
|
|
if( onBookmark == true )
|
|
{
|
|
// Inside bookmark. Draw text with bookmark foreground.
|
|
paint.setPen( mColor.bookmarkFg );
|
|
// ## paint.drawText( c.x1-startx, mFontAscent, &mPrintBuf[c.cell],
|
|
// mNumCell-c.cell );
|
|
paint.drawText( c.x1-startx, mFontAscent,
|
|
TQString::fromLocal8Bit(&mPrintBuf[c.cell]),
|
|
mNumCell-c.cell );
|
|
}
|
|
|
|
if( transparent == false || onBookmark == false )
|
|
{
|
|
paint.setPen( flag == 0 || useFg == true ? fg : mColor.nonPrintFg );
|
|
// ## paint.drawText( c.x1 - startx, mFontAscent, &mPrintBuf[c.cell], 1);
|
|
paint.drawText( c.x1 - startx, mFontAscent,
|
|
TQString::fromLocal8Bit(&mPrintBuf[c.cell]), 1 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw the cursor in secodary edit area.
|
|
//
|
|
if( mLayout.secondaryMode == SDisplayLayout::hide )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
if( mMark.inside( c.offset ) == true )
|
|
{
|
|
bg = mColor.markBg;
|
|
fg = mSelect.inside( c.offset ) ? mColor.selectFg : mColor.markFg;
|
|
useFg = true;
|
|
}
|
|
else if( mSelect.inside( c.offset ) == true )
|
|
{
|
|
bg = mColor.selectBg;
|
|
fg = mColor.selectFg;
|
|
useFg = true;
|
|
}
|
|
else
|
|
{
|
|
bg = (line+1) % 2 ? mColor.textBg : mColor.secondTextBg;
|
|
fg = mColor.secondaryFg;
|
|
useFg = false; // Can be true later.
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Fill in the general backround color
|
|
//
|
|
if( onBookmark == true )
|
|
{
|
|
if( useFg == true )
|
|
{
|
|
paint.fillRect( c.x2-startx, 2, mUnitWidth, mFontHeight-4,
|
|
mColor.bookmarkBg );
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( c.x2-startx, 1, mUnitWidth, mFontHeight-2,
|
|
mColor.bookmarkBg );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( c.x2 - startx, 0, mUnitWidth, mFontHeight, bg );
|
|
}
|
|
|
|
//
|
|
// Draw the cursor shape
|
|
//
|
|
transparent = false;
|
|
if( mActiveEditor == edit_secondary )
|
|
{
|
|
if( mShowCursor == true ) // Cursor blink on
|
|
{
|
|
if( c.mSecondaryShape == SCursorSpec::thin )
|
|
{
|
|
paint.setPen( cbg );
|
|
int center = c.x2 - startx - 1;
|
|
transparent = true;
|
|
|
|
if( c.thickState == true )
|
|
{
|
|
paint.drawLine( center, 0, center, mFontHeight - 1 );
|
|
paint.drawLine( center+1, 0, center+1, mFontHeight - 1 );
|
|
}
|
|
else
|
|
{
|
|
paint.drawLine( center, 0, center, mFontHeight - 1 );
|
|
paint.drawLine( center-2, 0, center+2, 0 );
|
|
paint.drawLine( center-2, mFontHeight-1, center+2, mFontHeight-1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
paint.fillRect( c.x2 - startx, 0, mUnitWidth, mFontHeight, cbg );
|
|
useFg = true;
|
|
fg = cfg;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
transparent = true;
|
|
paint.setPen( cbg );
|
|
paint.drawRect( c.x2 - startx, 0, mUnitWidth, mFontHeight );
|
|
}
|
|
|
|
//
|
|
// Draw the text on the cursor position and to the end of the cell.
|
|
//
|
|
if( c.offset < documentSize() )
|
|
{
|
|
int flag = printAsciiCell( mPrintBuf, (unsigned char)c.data );
|
|
if( onBookmark == true )
|
|
{
|
|
// Inside bookmark. Draw text with bookmark foreground.
|
|
paint.setPen( flag == 0 ? mColor.bookmarkFg : mColor.nonPrintFg );
|
|
// ## paint.drawText( c.x2-startx, mFontAscent, mPrintBuf, 1 );
|
|
paint.drawText( c.x2-startx, mFontAscent,
|
|
TQString::fromLocal8Bit(mPrintBuf), 1 );
|
|
}
|
|
if( transparent == false || onBookmark == false )
|
|
{
|
|
paint.setPen( flag == 0 || useFg == true ? fg : mColor.nonPrintFg );
|
|
// ## paint.drawText( c.x2 - startx, mFontAscent, mPrintBuf, 1 );
|
|
paint.drawText( c.x2 - startx, mFontAscent,
|
|
TQString::fromLocal8Bit(mPrintBuf), 1 );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHexBuffer::cursorReset( void )
|
|
{
|
|
mCursor.reset();
|
|
cursorCompute();
|
|
}
|
|
|
|
void CHexBuffer::cursorCompute( void )
|
|
{
|
|
mCursor.prev = mCursor.curr;
|
|
|
|
if( mCursor.next.offset >= documentSize() )
|
|
{
|
|
if( documentSize() == 0 )
|
|
{
|
|
mCursor.curr.offset = 0;
|
|
mCursor.curr.data = 0;
|
|
mCursor.curr.cell = 0;
|
|
mCursor.curr.maxCell = mNumCell;
|
|
|
|
int x = mCursor.curr.offset % mLayout.lineSize;
|
|
mCursor.curr.x1 = mTextStart1;
|
|
mCursor.curr.x1 += (x * mNumCell + mCursor.curr.cell) * mUnitWidth;
|
|
mCursor.curr.x1 += (x / mLayout.columnSize) * mSplitWidth;
|
|
mCursor.curr.x2 = mTextStart2 + x * mUnitWidth;
|
|
mCursor.curr.y = (mCursor.curr.offset/mLayout.lineSize) *
|
|
(mFontHeight+mLayout.horzGridWidth);
|
|
return;
|
|
|
|
}
|
|
if( mFixedSizeMode == true )
|
|
{
|
|
uint max = mMaximumSize - 1;
|
|
uint off = mCursor.curr.offset % mLayout.lineSize;
|
|
uint end = max % mLayout.lineSize;
|
|
if( off > end )
|
|
{
|
|
uint diff = off - end;
|
|
if( max + diff > mLayout.lineSize )
|
|
{
|
|
mCursor.next.offset = max + diff - mLayout.lineSize;
|
|
}
|
|
else
|
|
{
|
|
mCursor.next.offset = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint diff = end - off;
|
|
mCursor.next.offset = diff > max ? max : max - diff;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mCursor.next.offset = documentSize();
|
|
}
|
|
}
|
|
|
|
mCursor.curr.offset = mCursor.next.offset;
|
|
mCursor.curr.data = data()[ mCursor.curr.offset ];
|
|
mCursor.curr.cell = mCursor.next.cell;
|
|
mCursor.curr.maxCell = mNumCell;
|
|
|
|
int x = mCursor.curr.offset % mLayout.lineSize;
|
|
|
|
mCursor.curr.x1 = mTextStart1;
|
|
mCursor.curr.x1 += (x * mNumCell + mCursor.curr.cell) * mUnitWidth;
|
|
mCursor.curr.x1 += (x / mLayout.columnSize) * mSplitWidth;
|
|
mCursor.curr.x2 = mTextStart2 + x * mUnitWidth;
|
|
mCursor.curr.y = (mCursor.curr.offset/mLayout.lineSize) *
|
|
(mFontHeight + mLayout.horzGridWidth);
|
|
}
|
|
|
|
|
|
bool CHexBuffer::setCursorPosition( int x, int y, bool init, bool cellLevel )
|
|
{
|
|
if( documentPresent() == false )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
uint line = y < 0 ? 0 : y / lineHeight();
|
|
uint entry = 0;
|
|
int bit = 7;
|
|
|
|
if( init == false )
|
|
{
|
|
if( mCursor.area() == edit_primary )
|
|
{
|
|
int start = mTextStart1;
|
|
if( x < start - (int)mLayout.separatorMarginWidth )
|
|
{
|
|
return( false );
|
|
}
|
|
else
|
|
{
|
|
int stop = mTextStart1 + mPrimaryWidth + mLayout.separatorMarginWidth;
|
|
int width = mNumCell * mUnitWidth;
|
|
int space = mSplitWidth;
|
|
|
|
for( int position = start, i=0; position < stop; i++ )
|
|
{
|
|
if( x <= position + width )
|
|
{
|
|
if( cellLevel == true )
|
|
{
|
|
while( bit > 0 )
|
|
{
|
|
if( x <= position + mUnitWidth )
|
|
{
|
|
break;
|
|
}
|
|
bit -= mCursor.cellWeight();
|
|
position += mUnitWidth;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
position += width + (((i+1) % mLayout.columnSize) ? 0 : space);
|
|
entry += 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int start = mTextStart2;
|
|
if( x < start - (int)mLayout.separatorMarginWidth ||
|
|
mLayout.secondaryMode == SDisplayLayout::hide )
|
|
{
|
|
return( false );
|
|
}
|
|
int stop = mTextStart2 + mLayout.lineSize * mUnitWidth;
|
|
int width = mUnitWidth * 1;
|
|
int space = 0;
|
|
|
|
for( int position = start; position < stop; )
|
|
{
|
|
if( x <= position + width )
|
|
{
|
|
break;
|
|
}
|
|
position += width + space;
|
|
entry += 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int start = mTextStart1;
|
|
int stop = start + mPrimaryWidth + mLayout.separatorMarginWidth;
|
|
if( x >= start - (int)mLayout.separatorMarginWidth && x <= stop )
|
|
{
|
|
int width = mUnitWidth * mNumCell;
|
|
int space = mSplitWidth;
|
|
|
|
for( int position = start, i=0; position < stop; i++ )
|
|
{
|
|
if( x <= position + width )
|
|
{
|
|
if( cellLevel == true )
|
|
{
|
|
while( bit > 0 )
|
|
{
|
|
if( x <= position + mUnitWidth )
|
|
{
|
|
break;
|
|
}
|
|
bit -= mCursor.cellWeight();
|
|
position += mUnitWidth;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
position += width + (((i+1) % mLayout.columnSize) ? 0 : space);
|
|
entry += 1;
|
|
}
|
|
|
|
mActiveEditor = edit_primary;
|
|
}
|
|
else if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
start = mTextStart2;
|
|
stop = mTextStart2 + mLayout.lineSize * mUnitWidth +
|
|
mLayout.edgeMarginWidth;
|
|
if( x >= start - (int)mLayout.separatorMarginWidth && x <= stop )
|
|
{
|
|
int width = mUnitWidth * 1;
|
|
int space = 0;
|
|
|
|
for( int position = start; position < stop; )
|
|
{
|
|
if( x <= position + width )
|
|
{
|
|
break;
|
|
}
|
|
position += width + space;
|
|
entry += 1;
|
|
}
|
|
|
|
mActiveEditor = edit_secondary;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( false );
|
|
}
|
|
}
|
|
|
|
uint offset = line * mLayout.lineSize + entry;
|
|
if( offset > documentSize() )
|
|
{
|
|
offset = documentSize();
|
|
}
|
|
|
|
mCursor.setOffset( offset );
|
|
mCursor.setBit( bit < 0 ? 0 : bit );
|
|
|
|
cursorCompute();
|
|
if( mActiveEditor != mCursor.area() )
|
|
{
|
|
mCursor.setArea( mActiveEditor );
|
|
setEditMode( mEditMode );
|
|
}
|
|
|
|
return( true );
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHexBuffer::inputAtCursor( TQChar c )
|
|
{
|
|
if( documentPresent() == false || mInputMode.noInput() == true )
|
|
{
|
|
if( mInputMode.noInput() == true ) { inputSound(); }
|
|
return( false );
|
|
}
|
|
|
|
if( c.isPrint() == false )
|
|
{
|
|
inputSound();
|
|
return( false );
|
|
}
|
|
|
|
unsigned char dest;
|
|
bool insert;
|
|
if( mEditMode == EditReplace || mCursor.curr.cell > 0 )
|
|
{
|
|
if( mCursor.curr.offset >= documentSize() )
|
|
{
|
|
dest = 0;
|
|
insert = true;
|
|
}
|
|
else
|
|
{
|
|
dest = (unsigned char)data()[ mCursor.curr.offset ];
|
|
insert = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dest = 0;
|
|
insert = true;
|
|
}
|
|
|
|
if( insert == true && mInputMode.allowResize == false )
|
|
{
|
|
inputSound();
|
|
return( false );
|
|
}
|
|
|
|
if( mActiveEditor == edit_primary )
|
|
{
|
|
// ## if( THIS_FPTR(inputCell)( &dest, c.latin1(), mCursor.curr.cell )
|
|
//== false )
|
|
if( THIS_FPTR(inputCell)( &dest, TQString(c).local8Bit()[0],
|
|
mCursor.curr.cell ) == false )
|
|
{
|
|
inputSound();
|
|
return( false );
|
|
}
|
|
}
|
|
else if( mActiveEditor == edit_secondary )
|
|
{
|
|
// ## if( inputAscii( &dest, c.latin1(), mCursor.curr.cell ) == false )
|
|
if( !inputAscii( &dest, TQString(c).local8Bit()[0], mCursor.curr.cell ) )
|
|
{
|
|
inputSound();
|
|
return( false );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
recordReplace( mCursor, insert == true ? 0 : 1, (char*)&dest, 1 );
|
|
cursorRight( cursorPrimaryEdit() );
|
|
recordEnd( mCursor );
|
|
|
|
computeNumLines();
|
|
return( true );
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::inputAtCursor( const TQByteArray &buf, uint oldSize )
|
|
{
|
|
if( documentPresent() == false )
|
|
{
|
|
return( Err_NoActiveDocument );
|
|
}
|
|
if( buf.isNull() == true )
|
|
{
|
|
return( Err_EmptyArgument );
|
|
}
|
|
|
|
if( mInputMode.noInput() == true )
|
|
{
|
|
inputSound();
|
|
return( Err_WriteProtect );
|
|
}
|
|
|
|
if( mInputMode.allowResize == false )
|
|
{
|
|
inputSound();
|
|
return( Err_NoResize );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
recordReplace( mCursor, oldSize, (char*)&buf[0], buf.size() );
|
|
cursorStep( buf.size(), true, false );
|
|
recordEnd( mCursor );
|
|
|
|
computeNumLines();
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::removeAtCursor( bool beforeCursor )
|
|
{
|
|
if( documentPresent() == false )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
if( mInputMode.noInput() == true || mInputMode.allowResize == false )
|
|
{
|
|
inputSound();
|
|
return( false );
|
|
}
|
|
|
|
|
|
if( mSelect.valid() == true )
|
|
{
|
|
cutSelection();
|
|
return( true );
|
|
}
|
|
|
|
|
|
if( beforeCursor == true )
|
|
{
|
|
if( mCursor.curr.offset == 0 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
cursorLeft( false );
|
|
recordReplace( mCursor, 1, 0, 0 );
|
|
recordEnd( mCursor );
|
|
|
|
computeNumLines();
|
|
return( true );
|
|
}
|
|
else
|
|
{
|
|
if( mCursor.curr.offset + 1 > documentSize() )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
recordReplace( mCursor, 1, 0, 0 );
|
|
recordEnd( mCursor );
|
|
|
|
computeNumLines();
|
|
return( true );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::locateRange(const SExportRange &range, uint &start, uint &stop)
|
|
{
|
|
if( range.mode == SExportRange::All )
|
|
{
|
|
start = 0;
|
|
stop = documentSize();
|
|
}
|
|
else if( range.mode == SExportRange::Selection )
|
|
{
|
|
if( mSelect.valid() == false )
|
|
{
|
|
return( Err_NoSelection );
|
|
}
|
|
start = mSelect.curr.start;
|
|
stop = mSelect.curr.stop;
|
|
}
|
|
else if( range.mode == SExportRange::Range )
|
|
{
|
|
start = range.start;
|
|
stop = range.stop;
|
|
}
|
|
else
|
|
{
|
|
return( Err_IllegalMode );
|
|
}
|
|
|
|
if( start >= stop )
|
|
{
|
|
return( Err_IllegalRange );
|
|
}
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::exportText( const SExportText &ex, CProgress &p )
|
|
{
|
|
uint start, stop;
|
|
int errCode = locateRange( ex.range, start, stop );
|
|
if( errCode != Err_Success )
|
|
{
|
|
p.finish();
|
|
return( errCode );
|
|
}
|
|
|
|
TQFile file( ex.destFile );
|
|
if( file.open( IO_WriteOnly ) == false )
|
|
{
|
|
p.finish();
|
|
return( Err_OpenWriteFailed );
|
|
}
|
|
|
|
uint startLine = calculateLine( start );
|
|
if( startLine >= (uint)numLines() )
|
|
{
|
|
startLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint stopLine = calculateLine( stop );
|
|
if( stopLine >= (uint)numLines() )
|
|
{
|
|
stopLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint totalSize = stopLine - startLine + 1;
|
|
uint remaining = stopLine - startLine + 1;
|
|
uint bytePerLine = mOffsetSize + 1 + (mNumCell + 2)*mLayout.lineSize + 1;
|
|
uint linePerStep = 20;
|
|
|
|
TQByteArray array( bytePerLine * linePerStep + 1 ); // Line is 0 terminated
|
|
if( array.isEmpty() == true )
|
|
{
|
|
p.finish();
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
while( remaining > 0 )
|
|
{
|
|
uint blockSize = remaining > linePerStep ? linePerStep : remaining;
|
|
uint printSize = 0;
|
|
|
|
for( uint i = 0; i < blockSize; i++, startLine++ )
|
|
{
|
|
printSize += printLine( &array[printSize], startLine );
|
|
}
|
|
|
|
int writeSize = file.writeBlock( &array[0], printSize );
|
|
if( writeSize == -1 )
|
|
{
|
|
p.finish();
|
|
return( Err_WriteFailed );
|
|
}
|
|
|
|
remaining -= blockSize;
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)(totalSize-remaining)/(float)totalSize );
|
|
if( errCode == Err_Stop && remaining > 0 )
|
|
{
|
|
p.finish();
|
|
return( Err_OperationAborted );
|
|
}
|
|
}
|
|
}
|
|
|
|
p.finish();
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::exportHtml( const SExportHtml &ex, CProgress &p )
|
|
{
|
|
uint start, stop;
|
|
int errCode = locateRange( ex.range, start, stop );
|
|
if( errCode != Err_Success )
|
|
{
|
|
p.finish();
|
|
return( errCode );
|
|
}
|
|
|
|
uint startLine = calculateLine( start );
|
|
if( startLine >= (uint)numLines() )
|
|
{
|
|
startLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint stopLine = calculateLine( stop );
|
|
if( stopLine >= (uint)numLines() )
|
|
{
|
|
stopLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint totalSize = stopLine - startLine + 1;
|
|
uint remaining = stopLine - startLine + 1;
|
|
|
|
if( ex.linePerPage == 0 )
|
|
{
|
|
p.finish();
|
|
return( Err_IllegalArgument );
|
|
}
|
|
|
|
uint linePerPage = ex.linePerPage;
|
|
uint numFiles = remaining/linePerPage + (remaining%linePerPage ? 1 : 0);
|
|
uint fileCount = 0;
|
|
|
|
TQStringList fileNames, offsets;
|
|
TQString name, offset;
|
|
for( uint i=0; i < numFiles; i++ )
|
|
{
|
|
name.sprintf( "%08d.html", i+1 );
|
|
fileNames.append( TQString("%1/%2%3").arg(ex.package).arg(ex.prefix).
|
|
arg(name));
|
|
}
|
|
name.sprintf( "%08d.html", 0 );
|
|
TQString tocName =TQString("%1/%2%3").arg(ex.package).arg(ex.prefix).arg(name);
|
|
|
|
TQString linkName;
|
|
if( ex.symLink == true )
|
|
{
|
|
linkName = TQString("%1/%2").arg(ex.package).arg("index.html");
|
|
}
|
|
|
|
while( remaining > 0 )
|
|
{
|
|
THIS_FPTR(printOffset)( mPrintBuf, startLine*mLayout.lineSize );
|
|
mPrintBuf[mOffsetSize]=0;
|
|
offset.sprintf("[%s]", mPrintBuf );
|
|
|
|
uint pageSize = remaining > linePerPage ? linePerPage : remaining;
|
|
printHtmlDataPage( tocName, fileNames, fileCount, ex, startLine, pageSize);
|
|
|
|
remaining -= pageSize;
|
|
startLine += pageSize;
|
|
fileCount += 1;
|
|
|
|
THIS_FPTR(printOffset)( mPrintBuf, (startLine-1)*mLayout.lineSize );
|
|
mPrintBuf[mOffsetSize]=0;
|
|
offset += TQString(" %1 [%2]").arg(i18n("to")).arg(mPrintBuf);
|
|
offsets.append(offset);
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)(totalSize-remaining)/(float)totalSize );
|
|
if( errCode == Err_Stop && remaining > 0 )
|
|
{
|
|
printHtmlTocPage( tocName, linkName, fileNames, offsets, fileCount );
|
|
p.finish();
|
|
return( Err_OperationAborted );
|
|
}
|
|
}
|
|
}
|
|
|
|
printHtmlTocPage( tocName, linkName, fileNames, offsets, fileCount );
|
|
|
|
p.finish();
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::exportCArray( const SExportCArray &ex, CProgress &p )
|
|
{
|
|
uint start, stop;
|
|
int errCode = locateRange( ex.range, start, stop );
|
|
if( errCode != Err_Success )
|
|
{
|
|
p.finish();
|
|
return( errCode );
|
|
}
|
|
|
|
TQFile file( ex.destFile );
|
|
if( file.open( IO_WriteOnly ) == false )
|
|
{
|
|
p.finish();
|
|
return( Err_OpenWriteFailed );
|
|
}
|
|
|
|
uint startLine = calculateLine( start );
|
|
if( startLine >= (uint)numLines() )
|
|
{
|
|
startLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint stopLine = calculateLine( stop );
|
|
if( stopLine >= (uint)numLines() )
|
|
{
|
|
stopLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint elementSize = ex.elementSize();
|
|
uint elementOnThisLine = 0;
|
|
|
|
TQTextStream dest( &file );
|
|
|
|
dest << ex.variableName(stop-start).latin1() << "={" << endl;
|
|
for( unsigned int i=start; i<stop; i+=elementSize )
|
|
{
|
|
dest << ex.printFormatted( (const char*)&data()[i], stop-i );
|
|
if( i + elementSize < stop )
|
|
{
|
|
dest << ",";
|
|
}
|
|
|
|
if( ++elementOnThisLine >= ex.elementPerLine )
|
|
{
|
|
dest << endl;
|
|
elementOnThisLine = 0;
|
|
}
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)(i-start)/(float)(stop-start) );
|
|
if( errCode == Err_Stop && (i+elementSize) < stop)
|
|
{
|
|
p.finish();
|
|
return( Err_OperationAborted );
|
|
}
|
|
}
|
|
}
|
|
dest << "};" << endl;
|
|
|
|
p.finish();
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int CHexBuffer::copySelectedText( TQByteArray &array, int columnSegment )
|
|
{
|
|
SExportRange range;
|
|
range.mode = SExportRange::Selection;
|
|
return( copyText( array, range, columnSegment ) );
|
|
}
|
|
|
|
|
|
int CHexBuffer::copyAllText( TQByteArray &array )
|
|
{
|
|
SExportRange range;
|
|
range.mode = SExportRange::All;
|
|
return( copyText( array, range, VisibleColumn ) );
|
|
}
|
|
|
|
|
|
int CHexBuffer::copyText( TQByteArray &array, const SExportRange &range,
|
|
int columnSegment )
|
|
{
|
|
uint start, stop;
|
|
int errCode = locateRange( range, start, stop );
|
|
if( errCode != Err_Success )
|
|
{
|
|
return( errCode );
|
|
}
|
|
|
|
uint startLine = calculateLine( start );
|
|
uint stopLine = calculateLine( stop );
|
|
if( startLine >= (uint)numLines() )
|
|
{
|
|
startLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
if( stopLine >= (uint)numLines() )
|
|
{
|
|
stopLine = numLines() == 0 ? 0 : numLines() - 1;
|
|
}
|
|
|
|
uint bytePerLine = mOffsetSize + 1 + (mNumCell + 2)*mLayout.lineSize + 1;
|
|
uint size = (stopLine - startLine + 1)*bytePerLine;
|
|
if( array.resize( size+1 ) == false )
|
|
{
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
if( columnSegment == VisibleColumn )
|
|
{
|
|
columnSegment = PrimaryColumn; // Always visible
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
columnSegment |= OffsetColumn;
|
|
}
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
columnSegment |= SecondaryColumn;
|
|
}
|
|
}
|
|
|
|
uint offset = 0;
|
|
for( uint i = startLine; i <= stopLine; i++ )
|
|
{
|
|
offset += printLine( &array[offset], i, columnSegment );
|
|
}
|
|
array[size] = 0;
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::copySelectedData( TQByteArray &array )
|
|
{
|
|
uint start = mSelect.start();
|
|
uint stop = mSelect.stop();
|
|
|
|
if( mSelect.valid() == false || start >= stop )
|
|
{
|
|
return( Err_IllegalRange );
|
|
}
|
|
|
|
uint size = stop - start;
|
|
if( array.resize( size ) == false )
|
|
{
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
//unsigned char *src = (unsigned char*)data();
|
|
//char *dst = (char*)array.data();
|
|
|
|
memcpy( &array[0], &data()[start], size );
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
uint CHexBuffer::numPage( CHexPrinter &printer )
|
|
{
|
|
TQPainter paint( &printer );
|
|
paint.setFont( font() );
|
|
|
|
SPageMargin margin = printer.pageMargin();
|
|
SPageSize size = printer.pageUsableSize();
|
|
int headHeight, footHeight, headMargin, footMargin, freeHeight;
|
|
|
|
headHeight = footHeight = headMargin = footMargin = 0;
|
|
if( printer.pageHeader().enable == true )
|
|
{
|
|
headHeight = headerHeight( paint );
|
|
headMargin = headerMargin( paint );
|
|
}
|
|
if( printer.pageFooter().enable == true )
|
|
{
|
|
footHeight = headerHeight( paint );
|
|
footMargin = headerMargin( paint );
|
|
}
|
|
freeHeight = size.height - headHeight - footHeight - headMargin - footMargin;
|
|
|
|
float scale = 1.0;
|
|
if( (uint)mLineWidth > size.width )
|
|
{
|
|
scale = (float)size.width / (float)mLineWidth;
|
|
}
|
|
uint linePerPage = (uint) ((float)freeHeight/((float)lineHeight()*scale));
|
|
|
|
uint remaining = numLines();
|
|
|
|
return( remaining / linePerPage + (remaining % linePerPage ? 1 : 0) );
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::print( CHexPrinter &printer, CProgress &p )
|
|
{
|
|
printer.setDocName( mUrl );
|
|
|
|
TQPainter paint( &printer );
|
|
paint.setFont( font() );
|
|
|
|
SPageMargin margin = printer.pageMargin();
|
|
SPageSize size = printer.pageUsableSize();
|
|
paint.setClipRect( margin.left, margin.top, size.width, size.height );
|
|
|
|
//printf("%d,%d,%d,%d\n", margin.left, margin.top, size.width, size.height );
|
|
|
|
int headHeight, footHeight, headMargin, footMargin, freeHeight;
|
|
|
|
headHeight = footHeight = headMargin = footMargin = 0;
|
|
if( printer.pageHeader().enable == true )
|
|
{
|
|
headHeight = headerHeight( paint );
|
|
headMargin = headerMargin( paint );
|
|
}
|
|
if( printer.pageFooter().enable == true )
|
|
{
|
|
footHeight = headerHeight( paint );
|
|
footMargin = headerMargin( paint );
|
|
}
|
|
freeHeight = size.height - headHeight - footHeight - headMargin - footMargin;
|
|
|
|
float scale = 1.0;
|
|
if( (uint)mLineWidth > size.width )
|
|
{
|
|
scale = (float)size.width / (float)mLineWidth;
|
|
paint.scale( scale, scale );
|
|
}
|
|
|
|
uint linePerPage = (uint) ((float)freeHeight/((float)lineHeight()*scale));
|
|
uint sx = (uint) ((float)margin.left/scale);
|
|
uint sy = (uint) ((float)(margin.top+headHeight+headMargin)/scale);
|
|
|
|
uint remaining = numLines();
|
|
uint line = 0;
|
|
|
|
#ifdef PRINTER_TEST
|
|
remaining = remaining > linePerPage * 10 ? linePerPage * 10 : remaining;
|
|
#endif
|
|
|
|
|
|
SPagePosition pageData( time(0), remaining, linePerPage );
|
|
while( remaining > 0 )
|
|
{
|
|
uint lineInPage = remaining > linePerPage ? linePerPage : remaining;
|
|
uint y = sy;
|
|
|
|
//
|
|
// Draw header and footer. Reset scaling during that operation.
|
|
//
|
|
paint.scale( 1.0/scale, 1.0/scale );
|
|
if( printer.pageHeader().enable == true )
|
|
{
|
|
drawHeader( paint, margin.left, size.width, margin.top, false,
|
|
printer.pageHeader(), pageData );
|
|
}
|
|
if( printer.pageFooter().enable == true )
|
|
{
|
|
drawHeader( paint, margin.left, size.width,
|
|
margin.top+size.height-footHeight, true,
|
|
printer.pageFooter(), pageData );
|
|
}
|
|
paint.scale( scale, scale );
|
|
|
|
//
|
|
// Draw actual data
|
|
//
|
|
for( uint i=0; i < lineInPage; i++, line++ )
|
|
{
|
|
drawText( paint, line, sx, mLineWidth, y, false/*printer.printBlackWhite()*/ );
|
|
y += lineHeight();// - mLayout.horzGridWidth; // FIXME not really nice :)
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( pageData.current(), pageData.max() );
|
|
if( errCode == Err_Stop )
|
|
{
|
|
p.finish();
|
|
return( Err_Success ); // Success here, even if we cancel
|
|
}
|
|
}
|
|
}
|
|
|
|
if( p.expired() == true )
|
|
{
|
|
int errCode = p.step( pageData.current(), pageData.max() );
|
|
if( errCode == Err_Stop )
|
|
{
|
|
p.finish();
|
|
return( Err_Success );// Success here, even if we cancel
|
|
}
|
|
}
|
|
|
|
remaining -= lineInPage;
|
|
if( remaining > 0 )
|
|
{
|
|
printer.newPage();
|
|
}
|
|
|
|
pageData.step();
|
|
}
|
|
|
|
p.finish();
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint CHexBuffer::printLine( char *dst, uint line )
|
|
{
|
|
uint offset = line * mLayout.lineSize;
|
|
unsigned char *src;
|
|
char *start = dst;
|
|
|
|
uint dataSize;
|
|
if( offset >= documentSize() )
|
|
{
|
|
src = 0;
|
|
dataSize = 0;
|
|
}
|
|
else
|
|
{
|
|
src = (unsigned char*)&data()[ offset ];
|
|
dataSize = documentSize() - offset;
|
|
}
|
|
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
THIS_FPTR(printOffset)( dst, offset ); dst += mOffsetSize;
|
|
sprintf( dst, " " ); dst += 1;
|
|
}
|
|
for( uint i=0; i < mLayout.lineSize; i++ )
|
|
{
|
|
if( i<dataSize )
|
|
{
|
|
THIS_FPTR(printCell)( dst, src[i] ); dst += mNumCell;
|
|
}
|
|
else
|
|
{
|
|
memset( dst, ' ', mNumCell ); dst += mNumCell;
|
|
}
|
|
if( mSplitWidth != 0 )
|
|
{
|
|
sprintf( dst, " " ); dst += 1;
|
|
}
|
|
}
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
for( uint i=0; i < mLayout.lineSize; i++ )
|
|
{
|
|
if( i < dataSize )
|
|
{
|
|
printAsciiCell( dst, src[i] ); dst += 1;
|
|
}
|
|
else
|
|
{
|
|
memset( dst, ' ', 1 ); dst += 1;
|
|
}
|
|
}
|
|
}
|
|
sprintf( dst, "\n" ); dst += 1;
|
|
return( (uint)(dst-start) );
|
|
}
|
|
|
|
|
|
uint CHexBuffer::printLine( char *dst, uint line, int columnSegment )
|
|
{
|
|
uint offset = line * mLayout.lineSize;
|
|
unsigned char *src;
|
|
char *start = dst;
|
|
|
|
uint dataSize;
|
|
if( offset >= documentSize() )
|
|
{
|
|
src = 0;
|
|
dataSize = 0;
|
|
}
|
|
else
|
|
{
|
|
src = (unsigned char*)&data()[ offset ];
|
|
dataSize = documentSize() - offset;
|
|
}
|
|
|
|
if( columnSegment & OffsetColumn )
|
|
{
|
|
THIS_FPTR(printOffset)( dst, offset ); dst += mOffsetSize;
|
|
sprintf( dst, " " ); dst += 1;
|
|
}
|
|
|
|
if( columnSegment & PrimaryColumn )
|
|
{
|
|
for( uint i=0; i < mLayout.lineSize; i++ )
|
|
{
|
|
if( i<dataSize )
|
|
{
|
|
THIS_FPTR(printCell)( dst, src[i] ); dst += mNumCell;
|
|
}
|
|
else
|
|
{
|
|
memset( dst, ' ', mNumCell ); dst += mNumCell;
|
|
}
|
|
if( mSplitWidth != 0 )
|
|
{
|
|
sprintf( dst, " " ); dst += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( columnSegment & SecondaryColumn )
|
|
{
|
|
for( uint i=0; i < mLayout.lineSize; i++ )
|
|
{
|
|
if( i < dataSize )
|
|
{
|
|
printAsciiCell( dst, src[i] ); dst += 1;
|
|
}
|
|
else
|
|
{
|
|
memset( dst, ' ', 1 ); dst += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf( dst, "\n" ); dst += 1;
|
|
return( (uint)(dst-start) );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CHexBuffer::cutSelection( void )
|
|
{
|
|
if( documentPresent() == false || mSelect.size() == 0 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
if( mInputMode.noInput() == true || mInputMode.allowResize == false )
|
|
{
|
|
inputSound();
|
|
return( false );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
cursorGoto( mSelect.start(), 0 );
|
|
recordReplace( mCursor, mSelect.size(), 0, 0 );
|
|
recordEnd( mCursor );
|
|
|
|
mSelect.reset();
|
|
|
|
computeNumLines();
|
|
return( true );
|
|
}
|
|
|
|
|
|
|
|
bool CHexBuffer::undo( void )
|
|
{
|
|
if( documentPresent() == false || mUndoIndex == 0 ||
|
|
mInputMode.noInput() == true )
|
|
{
|
|
if( mInputMode.noInput() == true ) { inputSound(); }
|
|
return( false );
|
|
}
|
|
|
|
CHexActionGroup *group = mUndoList.at( mUndoIndex-1 );
|
|
if( group == 0 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
mUndoIndex -= 1;
|
|
doActionGroup( group );
|
|
|
|
cursorGoto( group->mStartOffset, group->mStartBit );
|
|
|
|
return( true );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::redo( void )
|
|
{
|
|
if( documentPresent() == false || mUndoIndex >= mUndoList.count() ||
|
|
mInputMode.noInput() == true )
|
|
{
|
|
if( mInputMode.noInput() == true ) { inputSound(); }
|
|
return( false );
|
|
}
|
|
|
|
CHexActionGroup *group = mUndoList.at( mUndoIndex );
|
|
if( group == 0 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
mUndoIndex += 1;
|
|
doActionGroup( group );
|
|
|
|
cursorGoto( group->mStopOffset, group->mStopBit );
|
|
|
|
return( true );
|
|
}
|
|
|
|
|
|
int CHexBuffer::addBookmark( int position )
|
|
{
|
|
if( documentPresent() == false )
|
|
{
|
|
return( Err_NoData );
|
|
}
|
|
|
|
if( mBookmarkList.count() >= 9 && position == -1 )
|
|
{
|
|
return( Err_ListFull );
|
|
}
|
|
|
|
SCursorOffset *co = new SCursorOffset;
|
|
if( co == 0 )
|
|
{
|
|
fatalSound();
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
co->offset = mCursor.curr.offset;
|
|
co->bit = mCursor.bit();
|
|
|
|
if( position == -1 || position > (int)mBookmarkList.count() )
|
|
{
|
|
mBookmarkList.append( co );
|
|
}
|
|
else
|
|
{
|
|
mBookmarkList.remove( (uint)position );
|
|
mBookmarkList.insert( (uint)position, co );
|
|
}
|
|
|
|
updateBookmarkMap(false);
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::removeBookmark( int position )
|
|
{
|
|
if( position < 0 )
|
|
{
|
|
if( mBookmarkList.count() == 0 )
|
|
{
|
|
return( false );
|
|
}
|
|
mBookmarkList.clear();
|
|
}
|
|
else
|
|
{
|
|
if( (uint)position >= mBookmarkList.count() )
|
|
{
|
|
return( false );
|
|
}
|
|
mBookmarkList.remove( position );
|
|
}
|
|
|
|
updateBookmarkMap(false);
|
|
return( true );
|
|
}
|
|
|
|
|
|
void CHexBuffer::updateBookmarkMap( bool resize )
|
|
{
|
|
if( resize == true )
|
|
{
|
|
mBookmarkMap.resize( documentSize()/200 + 3 );
|
|
}
|
|
mBookmarkMap.fill(0);
|
|
|
|
int bookmarkMapSize = mBookmarkMap.size();
|
|
for( SCursorOffset *c=mBookmarkList.first(); c!=0; c=mBookmarkList.next() )
|
|
{
|
|
int bookmarkOffset = c->offset / 200;
|
|
if( bookmarkOffset < bookmarkMapSize )
|
|
{
|
|
//
|
|
// Espen 2000-05-16:
|
|
// I do this test to avoid some TQt warnings when I have closed
|
|
// or reduced the size of the documnet while the (now invalid)
|
|
// bookmarks still exist.
|
|
//
|
|
mBookmarkMap.setBit(bookmarkOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int CHexBuffer::findFirst( SSearchControl &sc )
|
|
{
|
|
mMark.reset();
|
|
int errCode = scanData( sc, true );
|
|
return( errCode );
|
|
}
|
|
|
|
int CHexBuffer::findNext( SSearchControl &sc )
|
|
{
|
|
sc.fromCursor = true;
|
|
int errCode = scanData( sc, false );
|
|
return( errCode );
|
|
}
|
|
|
|
int CHexBuffer::findWrap( SSearchControl &sc )
|
|
{
|
|
if( sc.wrapValid == false )
|
|
{
|
|
return( Err_NoMatch );
|
|
}
|
|
sc.wrapValid = false;
|
|
|
|
sc.fromCursor = false;
|
|
sc.wrapActive = true;
|
|
int errCode = scanData( sc, false );
|
|
sc.fromCursor = true;
|
|
return( errCode );
|
|
}
|
|
|
|
|
|
|
|
|
|
int CHexBuffer::replaceAll( SSearchControl &sc, bool init )
|
|
{
|
|
if( init == true )
|
|
{
|
|
initScanData( sc );
|
|
}
|
|
|
|
if( sc.key.isEmpty() == true )
|
|
{
|
|
return( Err_EmptyArgument );
|
|
}
|
|
|
|
if( documentSize() == 0 )
|
|
{
|
|
return( Err_EmptyDocument );
|
|
}
|
|
|
|
uint head, tail;
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( mSelect.valid() == false )
|
|
{
|
|
return( Err_NoSelection );
|
|
}
|
|
|
|
head = mSelect.start();
|
|
tail = mSelect.stop();
|
|
}
|
|
else
|
|
{
|
|
head = 0;
|
|
tail = documentSize();
|
|
}
|
|
|
|
uint start, stop;
|
|
if( sc.fromCursor == false )
|
|
{
|
|
if( sc.wrapActive == true )
|
|
{
|
|
start = sc.forward == true ? head : sc.wrapMark;
|
|
stop = sc.forward == true ? sc.wrapMark+sc.key.size() : tail;
|
|
}
|
|
else
|
|
{
|
|
start = head;
|
|
stop = tail;
|
|
}
|
|
}
|
|
else if( sc.forward == true )
|
|
{
|
|
start = cursorOffset() < head ? head : cursorOffset();
|
|
stop = sc.wrapActive == true ? sc.wrapMark+sc.key.size() : tail;
|
|
}
|
|
else
|
|
{
|
|
start = sc.wrapActive == true ? sc.wrapMark : head;
|
|
stop = cursorOffset() > tail ? tail : cursorOffset();
|
|
}
|
|
|
|
if( sc.forward == true && start + sc.key.size() > stop )
|
|
{
|
|
//
|
|
// When searching backwards "stop" is the last offset from where
|
|
// we do a memcmp() upward in memory. An overflow for that
|
|
// situation is taken care of below.
|
|
//
|
|
return( Err_NoMatch );
|
|
}
|
|
|
|
if( stop + sc.key.size() > tail )
|
|
{
|
|
uint diff = stop + sc.key.size() - tail;
|
|
stop = stop > diff ? stop - diff : 0;
|
|
}
|
|
|
|
if( mInputMode.noInput() == true )
|
|
{
|
|
inputSound();
|
|
return( Err_WriteProtect );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
uint numReplaced = 0;
|
|
|
|
if( sc.forward == true )
|
|
{
|
|
for( uint i = start; i <= stop ; )
|
|
{
|
|
if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) != 0 )
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
cursorGoto( i, 7 );
|
|
recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() );
|
|
numReplaced += 1;
|
|
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( sc.key.size() > sc.val.size() )
|
|
{
|
|
mSelect.shrink( sc.key.size() - sc.val.size() );
|
|
}
|
|
else
|
|
{
|
|
mSelect.expand( sc.val.size() - sc.key.size() );
|
|
}
|
|
}
|
|
|
|
if( sc.key.size() > sc.val.size() )
|
|
{
|
|
uint diff = sc.key.size() - sc.val.size();
|
|
stop -= TQMIN( stop, diff );
|
|
}
|
|
else if( sc.key.size() < sc.val.size() )
|
|
{
|
|
stop += sc.val.size() - sc.key.size();
|
|
}
|
|
|
|
i += sc.val.size();
|
|
cursorStep( sc.val.size(), true, false );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uint i = stop; i >= start; )
|
|
{
|
|
if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) != 0 )
|
|
{
|
|
if( i == 0 ) { break; }
|
|
i--;
|
|
}
|
|
else
|
|
{
|
|
cursorGoto( i, 7 );
|
|
recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() );
|
|
numReplaced += 1;
|
|
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( sc.key.size() > sc.val.size() )
|
|
{
|
|
mSelect.shrink( sc.key.size() - sc.val.size() );
|
|
}
|
|
else
|
|
{
|
|
mSelect.expand( sc.val.size() - sc.key.size() );
|
|
}
|
|
}
|
|
|
|
i -= TQMIN( i, sc.key.size() );
|
|
if( i == 0 ) { break; }
|
|
}
|
|
}
|
|
}
|
|
|
|
recordEnd( mCursor );
|
|
computeNumLines();
|
|
|
|
if( numReplaced == 0 )
|
|
{
|
|
return( Err_NoMatch );
|
|
}
|
|
|
|
sc.numReplace += numReplaced;
|
|
sc.match = true;
|
|
mMark.reset();
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::replaceMarked( SSearchControl &sc )
|
|
{
|
|
if( documentSize() == 0 )
|
|
{
|
|
return( Err_EmptyDocument );
|
|
}
|
|
|
|
if( mMark.valid() == false )
|
|
{
|
|
return( Err_NoMark );
|
|
}
|
|
|
|
bool inSelection;
|
|
if( mSelect.valid() == true )
|
|
{
|
|
if( mMark.start() >= mSelect.start() && mMark.stop() <= mSelect.stop() )
|
|
{
|
|
inSelection = true;
|
|
}
|
|
else
|
|
{
|
|
inSelection = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
inSelection = false;
|
|
}
|
|
|
|
if( mInputMode.noInput() == true )
|
|
{
|
|
inputSound();
|
|
return( Err_WriteProtect );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
cursorGoto( mMark.start(), 7 );
|
|
recordReplace( mCursor, mMark.size(), sc.val.data(), sc.val.size() );
|
|
sc.numReplace += 1;
|
|
|
|
if( inSelection == true )
|
|
{
|
|
if( mMark.size() > sc.val.size() )
|
|
{
|
|
mSelect.shrink( mMark.size() - sc.val.size() );
|
|
}
|
|
else
|
|
{
|
|
sc.wrapMark += sc.val.size() - mMark.size();
|
|
mSelect.expand( sc.val.size() - mMark.size() );
|
|
}
|
|
}
|
|
|
|
|
|
if( sc.wrapActive == false )
|
|
{
|
|
if( sc.forward == false )
|
|
{
|
|
sc.wrapMark += mMark.size() > sc.val.size() ?
|
|
mMark.size() - sc.val.size() : sc.val.size() - mMark.size();
|
|
}
|
|
}
|
|
|
|
|
|
recordEnd( mCursor );
|
|
computeNumLines();
|
|
|
|
if( sc.forward == true )
|
|
{
|
|
//
|
|
// We must step over the area we have just altered. This is
|
|
// vital if the search key contains a pattern that exists in
|
|
// the replace data buffer.
|
|
//
|
|
cursorStep( sc.val.size(), true, false );
|
|
}
|
|
mMark.reset();
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
int CHexBuffer::replaceAll( SSearchControl &sc, bool init )
|
|
{
|
|
if( init == true )
|
|
{
|
|
initScanData( sc );
|
|
}
|
|
|
|
if( sc.key.isEmpty() == true )
|
|
{
|
|
return( Err_EmptyArgument );
|
|
}
|
|
|
|
if( documentSize() == 0 )
|
|
{
|
|
return( Err_EmptyDocument );
|
|
}
|
|
|
|
uint head, tail;
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( mSelect.valid() == false )
|
|
{
|
|
return( Err_NoSelection );
|
|
}
|
|
|
|
head = mSelect.start();
|
|
tail = mSelect.stop();
|
|
}
|
|
else
|
|
{
|
|
head = 0;
|
|
tail = documentSize();
|
|
}
|
|
|
|
uint start, stop;
|
|
if( sc.fromCursor == false )
|
|
{
|
|
if( sc.wrapActive == true )
|
|
{
|
|
start = sc.forward == true ? head : sc.wrapMark;
|
|
stop = sc.forward == true ? sc.wrapMark : tail;
|
|
}
|
|
else
|
|
{
|
|
start = head;
|
|
stop = tail;
|
|
}
|
|
}
|
|
else if( sc.forward == true )
|
|
{
|
|
start = cursorOffset() < head ? head : cursorOffset();
|
|
stop = sc.wrapActive == true ? sc.wrapMark : tail;
|
|
}
|
|
else
|
|
{
|
|
start = sc.wrapActive == true ? sc.wrapMark : head;
|
|
stop = cursorOffset() > tail ? tail : cursorOffset();
|
|
}
|
|
|
|
|
|
if( start + sc.key.size() > stop )
|
|
{
|
|
return( Err_NoMatch );
|
|
}
|
|
|
|
if( stop + sc.key.size() > tail )
|
|
{
|
|
uint diff = stop + sc.key.size() - tail;
|
|
stop = stop > diff ? stop - diff : 0;
|
|
}
|
|
|
|
if( mInputMode.noInput() == true )
|
|
{
|
|
inputSound();
|
|
return( Err_WriteProtect );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
uint numReplaced = 0;
|
|
|
|
if( sc.forward == true )
|
|
{
|
|
for( uint i = start; i <= stop; i++ )
|
|
{
|
|
if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) == 0 )
|
|
{
|
|
cursorGoto( i, 7 );
|
|
recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() );
|
|
numReplaced += 1;
|
|
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( sc.key.size() > sc.val.size() )
|
|
{
|
|
mSelect.shrink( sc.key.size() - sc.val.size() );
|
|
}
|
|
else
|
|
{
|
|
mSelect.expand( sc.val.size() - sc.key.size() );
|
|
}
|
|
}
|
|
|
|
if( sc.key.size() > sc.key.size() )
|
|
{
|
|
uint diff = sc.key.size() - sc.val.size();
|
|
i += diff - 1;
|
|
}
|
|
else if( sc.key.size() < sc.val.size() )
|
|
{
|
|
uint diff = sc.val.size() - sc.key.size();
|
|
stop += diff;
|
|
}
|
|
else
|
|
{
|
|
i += sc.val.size() - 1;
|
|
}
|
|
cursorStep( sc.val.size(), true, false );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( uint i = stop; i >= start; i-- )
|
|
{
|
|
if( memcmp( &data()[i], sc.key.data(), sc.key.size() ) == 0 )
|
|
{
|
|
cursorGoto( i, 7 );
|
|
recordReplace( mCursor, sc.key.size(), sc.val.data(), sc.val.size() );
|
|
numReplaced += 1;
|
|
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( sc.key.size() > sc.val.size() )
|
|
{
|
|
mSelect.shrink( sc.key.size() - sc.val.size() );
|
|
}
|
|
else
|
|
{
|
|
mSelect.expand( sc.val.size() - sc.key.size() );
|
|
}
|
|
}
|
|
|
|
}
|
|
if( i == 0 ) { break; }
|
|
}
|
|
}
|
|
|
|
recordEnd( mCursor );
|
|
computeNumLines();
|
|
|
|
if( numReplaced == 0 )
|
|
{
|
|
return( Err_NoMatch );
|
|
}
|
|
|
|
sc.numReplace += numReplaced;
|
|
sc.match = true;
|
|
mMark.reset();
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::replaceMarked( SSearchControl &sc )
|
|
{
|
|
if( documentSize() == 0 )
|
|
{
|
|
return( Err_EmptyDocument );
|
|
}
|
|
|
|
if( mMark.valid() == false )
|
|
{
|
|
return( Err_NoMark );
|
|
}
|
|
|
|
bool inSelection;
|
|
if( mSelect.valid() == false )
|
|
{
|
|
if( mMark.start() >= mSelect.start() && mMark.stop() <= mSelect.stop() )
|
|
{
|
|
inSelection = true;
|
|
}
|
|
else
|
|
{
|
|
inSelection = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
inSelection = false;
|
|
}
|
|
|
|
if( mInputMode.noInput() == true )
|
|
{
|
|
inputSound();
|
|
return( Err_WriteProtect );
|
|
}
|
|
|
|
recordStart( mCursor );
|
|
cursorGoto( mMark.start(), 7 );
|
|
recordReplace( mCursor, mMark.size(), sc.val.data(), sc.val.size() );
|
|
sc.numReplace += 1;
|
|
|
|
if( inSelection == true )
|
|
{
|
|
if( mMark.size() > sc.val.size() )
|
|
{
|
|
mSelect.shrink( mMark.size() - sc.val.size() );
|
|
}
|
|
else
|
|
{
|
|
mSelect.expand( sc.val.size() - mMark.size() );
|
|
}
|
|
}
|
|
|
|
recordEnd( mCursor );
|
|
computeNumLines();
|
|
mMark.reset();
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
int CHexBuffer::initScanData( SSearchControl &sc )
|
|
{
|
|
sc.wrapValid = false;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = 0;
|
|
sc.match = false;
|
|
sc.numReplace = 0;
|
|
|
|
uint head, tail;
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( mSelect.valid() == false )
|
|
{
|
|
return( Err_NoSelection );
|
|
}
|
|
|
|
head = mSelect.start();
|
|
tail = mSelect.stop();
|
|
}
|
|
else
|
|
{
|
|
head = 0;
|
|
tail = documentSize();
|
|
}
|
|
|
|
if( sc.fromCursor == false )
|
|
{
|
|
sc.wrapValid = false;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = 0;
|
|
}
|
|
else if( sc.forward == true )
|
|
{
|
|
if( cursorOffset() > tail )
|
|
{
|
|
sc.wrapValid = true;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = tail;
|
|
}
|
|
else if( cursorOffset() <= head )
|
|
{
|
|
sc.wrapValid = false;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = 0;
|
|
}
|
|
else
|
|
{
|
|
sc.wrapValid = true;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = cursorOffset();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( cursorOffset() >= tail )
|
|
{
|
|
sc.wrapValid = false;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = 0;
|
|
}
|
|
else if( cursorOffset() < head )
|
|
{
|
|
sc.wrapValid = true;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = head;
|
|
}
|
|
else
|
|
{
|
|
sc.wrapValid = true;
|
|
sc.wrapActive = false;
|
|
sc.wrapMark = cursorOffset();
|
|
}
|
|
}
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::scanData( SSearchControl &sc, bool init )
|
|
{
|
|
if( init == true )
|
|
{
|
|
int errCode = initScanData( sc );
|
|
if( errCode != Err_Success )
|
|
{
|
|
return( errCode );
|
|
}
|
|
}
|
|
|
|
if( sc.key.isEmpty() == true )
|
|
{
|
|
return( Err_EmptyArgument );
|
|
}
|
|
|
|
if( documentSize() == 0 )
|
|
{
|
|
return( Err_EmptyDocument );
|
|
}
|
|
|
|
uint head, tail;
|
|
if( sc.inSelection == true )
|
|
{
|
|
if( mSelect.valid() == false )
|
|
{
|
|
return( Err_NoSelection );
|
|
}
|
|
|
|
head = mSelect.start();
|
|
tail = mSelect.stop();
|
|
}
|
|
else
|
|
{
|
|
head = 0;
|
|
tail = documentSize();
|
|
}
|
|
|
|
uint start, stop;
|
|
if( sc.fromCursor == false )
|
|
{
|
|
if( sc.wrapActive == true )
|
|
{
|
|
start = sc.forward == true ? head : sc.wrapMark;
|
|
stop = sc.forward == true ? sc.wrapMark+sc.key.size() : tail;
|
|
}
|
|
else
|
|
{
|
|
start = head;
|
|
stop = tail;
|
|
}
|
|
}
|
|
else if( sc.forward == true )
|
|
{
|
|
start = cursorOffset() < head ? head : cursorOffset();
|
|
stop = sc.wrapActive == true ? sc.wrapMark : tail;
|
|
}
|
|
else
|
|
{
|
|
start = sc.wrapActive == true ? sc.wrapMark : head;
|
|
stop = cursorOffset() > tail ? tail : cursorOffset();
|
|
}
|
|
|
|
if( sc.forward == true && start + sc.key.size() > stop )
|
|
{
|
|
//
|
|
// When searching backwards "stop" is the last offset from where
|
|
// we do a memcmp() upward in memory. An overflow for that
|
|
// situation is taken care of below.
|
|
//
|
|
return( stop + sc.key.size() < tail ? Err_WrapBuffer : Err_NoData );
|
|
}
|
|
|
|
if( stop + sc.key.size() > tail )
|
|
{
|
|
uint diff = stop + sc.key.size() - tail;
|
|
stop = stop > diff ? stop - diff : 0;
|
|
}
|
|
|
|
if( sc.forward == true )
|
|
{
|
|
for( uint i = start; i <= stop; i++ )
|
|
{
|
|
int result;
|
|
if( sc.ignoreCase == true )
|
|
{
|
|
result = strncasecmp( &data()[i], sc.key.data(), sc.key.size() );
|
|
}
|
|
else
|
|
{
|
|
result = memcmp( &data()[i], sc.key.data(), sc.key.size() );
|
|
}
|
|
if( result == 0 )
|
|
{
|
|
if( i != cursorOffset() || mMark.size() != sc.key.size() )
|
|
{
|
|
sc.match = true;
|
|
cursorGoto( i, 7 );
|
|
markSet( i, (uint)sc.key.size() );
|
|
return( Err_Success );
|
|
}
|
|
}
|
|
}
|
|
return( start > head ? Err_WrapBuffer : Err_NoData );
|
|
}
|
|
else
|
|
{
|
|
for( uint i = stop; i >= start; i-- )
|
|
{
|
|
int result;
|
|
if( sc.ignoreCase == true )
|
|
{
|
|
result = strncasecmp( &data()[i], sc.key.data(), sc.key.size() );
|
|
}
|
|
else
|
|
{
|
|
result = memcmp( &data()[i], sc.key.data(), sc.key.size() );
|
|
}
|
|
if( result == 0 )
|
|
{
|
|
if( i != cursorOffset() || mMark.size() != sc.key.size() )
|
|
{
|
|
sc.match = true;
|
|
cursorGoto( i, 7 );
|
|
markSet( i, (uint)sc.key.size() );
|
|
return( Err_Success );
|
|
}
|
|
}
|
|
if( i == 0 ) { break; }
|
|
}
|
|
|
|
return( stop + sc.key.size() <= tail ? Err_WrapBuffer : Err_NoData );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CHexBuffer::filter( SFilterControl &fc )
|
|
{
|
|
uint head, tail;
|
|
if( fc.inSelection == true )
|
|
{
|
|
if( mSelect.valid() == false )
|
|
{
|
|
return( Err_NoSelection );
|
|
}
|
|
|
|
head = mSelect.start();
|
|
tail = mSelect.stop();
|
|
}
|
|
else
|
|
{
|
|
head = 0;
|
|
tail = documentSize();
|
|
}
|
|
|
|
uint start, stop;
|
|
if( fc.fromCursor == false )
|
|
{
|
|
start = head;
|
|
stop = tail;
|
|
}
|
|
else if( fc.forward == true )
|
|
{
|
|
start = cursorOffset() < head ? head : cursorOffset();
|
|
stop = tail;
|
|
}
|
|
else
|
|
{
|
|
start = head;
|
|
stop = cursorOffset() > tail ? tail : cursorOffset();
|
|
}
|
|
|
|
if( mInputMode.noInput() == true )
|
|
{
|
|
inputSound();
|
|
return( Err_WriteProtect );
|
|
}
|
|
|
|
if( start >= stop ) { return( Err_IllegalRange ); }
|
|
TQByteArray buf( stop - start );
|
|
if( buf.isEmpty() == true ) { return( Err_NoMemory ); }
|
|
|
|
int errCode = fc.execute((uchar*)&buf[0],(uchar*)&data()[start],buf.size());
|
|
if( errCode == Err_Success )
|
|
{
|
|
recordStart( mCursor );
|
|
cursorGoto( start, 7 );
|
|
recordReplace( mCursor, buf.size(), buf.data(), buf.size() );
|
|
recordEnd( mCursor );
|
|
}
|
|
|
|
return( errCode );
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::collectStrings( CStringCollectControl &sc )
|
|
{
|
|
uint startOffset = 0;
|
|
uint start, i;
|
|
bool on = false;
|
|
|
|
if( sc.minLength < 1 ) { sc.minLength = 1; }
|
|
|
|
start = startOffset;
|
|
for( i = startOffset; i<documentSize(); i++ )
|
|
{
|
|
unsigned char item = data()[i];
|
|
if( isprint( item ) == 0 || item >= 128 )
|
|
{
|
|
if( on == true && i-start >= sc.minLength )
|
|
{
|
|
TQByteArray a( i-start );
|
|
for( uint j=0; j<(i-start); a[j]=data()[start+j], j++ );
|
|
sc.add( start, a );
|
|
}
|
|
on = false;
|
|
}
|
|
else
|
|
{
|
|
if( on == false ) { start = i; }
|
|
on = true;
|
|
}
|
|
}
|
|
|
|
if( on == true && i-start >= sc.minLength )
|
|
{
|
|
TQByteArray a( i-start );
|
|
for( uint j=0; j<(i-start); a[j]=data()[start+j], j++ );
|
|
sc.add( start, a );
|
|
}
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::collectStatistic( SStatisticControl &sc, CProgress &p )
|
|
{
|
|
sc.documentSize = documentSize();
|
|
sc.documentName = mUrl;
|
|
|
|
for( uint i = 0; i<documentSize(); i++ )
|
|
{
|
|
sc.occurrence[ (unsigned char)data()[i] ] += 1;
|
|
|
|
//
|
|
// The expired() function introduces too much overhead in this case
|
|
// so it is only executed every 100'th character
|
|
//
|
|
if( i % 100 == 0 && p.expired() == true )
|
|
{
|
|
int errCode = p.step( (float)i/(float)documentSize() );
|
|
if( errCode == Err_Stop && i+1 < documentSize() )
|
|
{
|
|
p.finish();
|
|
return( Err_OperationAborted );
|
|
}
|
|
}
|
|
}
|
|
p.finish();
|
|
return( Err_NoErr );
|
|
}
|
|
|
|
|
|
void CHexBuffer::doActionGroup( CHexActionGroup *group )
|
|
{
|
|
if( group == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
CHexAction *action = group->mHexAction;
|
|
group->mHexAction = 0;
|
|
|
|
while( action != 0 )
|
|
{
|
|
doAction( action );
|
|
CHexAction *next = action->mNext;
|
|
group->insertAction( action );
|
|
action = next;
|
|
}
|
|
|
|
computeNumLines();
|
|
}
|
|
|
|
|
|
void CHexBuffer::doAction( CHexAction *action )
|
|
{
|
|
if( action->mAction == CHexAction::replace )
|
|
{
|
|
doReplace( action, true );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CHexBuffer::recordStart( SCursor &cursor )
|
|
{
|
|
//
|
|
// Step 1: Remove any undo element that is more recent than the
|
|
// current undo index
|
|
//
|
|
while( mUndoList.count() > mUndoIndex )
|
|
{
|
|
mUndoList.removeLast();
|
|
}
|
|
|
|
//
|
|
// Step 2: Make sure the undo list is no larger than the undo limit.
|
|
// We remove the oldest elements in the list.
|
|
//
|
|
while( mUndoList.count() >= mUndoLimit )
|
|
{
|
|
mUndoList.removeFirst();
|
|
mUndoIndex -= 1;
|
|
}
|
|
|
|
CHexActionGroup *group = new CHexActionGroup( cursor.curr.offset,
|
|
cursor.bit() );
|
|
if( group == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mUndoList.append( group );
|
|
mUndoIndex += 1;
|
|
}
|
|
|
|
|
|
void CHexBuffer::recordReplace( SCursor &cursor, uint size, char *data1,
|
|
uint data1Size )
|
|
{
|
|
CHexAction *hexAction = new CHexAction( CHexAction::replace,
|
|
cursor.curr.offset );
|
|
if( hexAction == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
hexAction->mSize = size;
|
|
hexAction->mData = data1;
|
|
hexAction->mDataSize = data1Size;
|
|
|
|
doReplace( hexAction, false );
|
|
mUndoList.getLast()->insertAction( hexAction );
|
|
|
|
if( mCursor.curr.offset < documentSize() )
|
|
{
|
|
mCursor.curr.data = data()[ mCursor.curr.offset ];
|
|
}
|
|
|
|
}
|
|
|
|
void CHexBuffer::recordEnd( SCursor &cursor )
|
|
{
|
|
mUndoList.getLast()->mStopOffset = cursor.curr.offset;
|
|
mUndoList.getLast()->mStopBit = cursor.bit();
|
|
}
|
|
|
|
|
|
//
|
|
// This method is the only place where the doucument data can be changed.
|
|
//
|
|
void CHexBuffer::doReplace( CHexAction *hexAction, bool removeData )
|
|
{
|
|
uint offset = hexAction->mOffset;
|
|
uint oldSize = hexAction->mSize;
|
|
char *newData = hexAction->mData;
|
|
uint newSize = hexAction->mDataSize;
|
|
|
|
hexAction->setData( newSize, &data()[offset], oldSize );
|
|
|
|
//
|
|
// Input new data. Resize buffer first if necessary. We always mark the
|
|
// data as changed (dirty) when the buffer is resized, otherwise only
|
|
// when the new data differ from the current. Nice feature :-)
|
|
//
|
|
int errCode;
|
|
if( newSize > oldSize )
|
|
{
|
|
errCode = moveBuffer( offset + newSize - oldSize, offset );
|
|
mDocumentModified = true;
|
|
}
|
|
else if( newSize < oldSize )
|
|
{
|
|
errCode = moveBuffer( offset, offset + oldSize - newSize );
|
|
mDocumentModified = true;
|
|
}
|
|
else
|
|
{
|
|
errCode = Err_Success;
|
|
if( memcmp( &data()[offset], newData, newSize ) != 0 )
|
|
{
|
|
mDocumentModified = true;
|
|
}
|
|
}
|
|
|
|
if( errCode == Err_Success )
|
|
{
|
|
memcpy( &data()[offset], newData, newSize );
|
|
}
|
|
|
|
//
|
|
// Data is removed regardless of success or not. Otherwise we will
|
|
// have a mmeory leak. The single reason why the operation above could
|
|
// fail is because there was that no more memory that could be
|
|
// allocated.
|
|
//
|
|
if( removeData == true )
|
|
{
|
|
delete [] newData;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
bool CHexBuffer::inputDummy( unsigned char *dest, int value, uint cell )
|
|
{
|
|
(void)dest;
|
|
(void)value;
|
|
(void)cell;
|
|
return( false );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::inputHexadecimal( unsigned char *dest, int value, uint cell )
|
|
{
|
|
if( value >= '0' && value <= '9' )
|
|
{
|
|
value = value - '0';
|
|
}
|
|
else if( value >= 'A' && value <= 'F' )
|
|
{
|
|
value = value - 'A' + 10;
|
|
}
|
|
else if( value >= 'a' && value <= 'f' )
|
|
{
|
|
value = value - 'a' + 10;
|
|
}
|
|
else
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
if( cell > 1 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
uint shift = 1 - cell;
|
|
*dest = (*dest & ~(0xF<<(shift*4)) ) | (value<<(shift*4));
|
|
return( true );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::inputDecimal( unsigned char *dest, int value, uint cell )
|
|
{
|
|
//
|
|
// 2000-01-22 Espen Sand
|
|
// I do the insertion a bit different here since decimal is special
|
|
// with respect to bitwidths.
|
|
//
|
|
if( value < '0' || value > '9' || cell > 2 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
char buf[4];
|
|
printDecimalCell( buf, *dest );
|
|
buf[cell]=value;
|
|
buf[3]=0;
|
|
|
|
int tmp = atoi(buf);
|
|
if( tmp > 255 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
*dest = tmp;
|
|
return( true );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::inputOctal( unsigned char *dest, int value, uint cell )
|
|
{
|
|
if( value >= '0' && value <= '7' )
|
|
{
|
|
value = value - '0';
|
|
if( cell == 0 && value > 3 )
|
|
{
|
|
return( false );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
if( cell >= 3 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
uint shift = 2 - cell;
|
|
*dest = (*dest & ~(0x7<<(shift*3)) ) | (value<<(shift*3));
|
|
return( true );
|
|
}
|
|
|
|
|
|
bool CHexBuffer::inputBinary( unsigned char *dest, int value, uint cell )
|
|
{
|
|
if( value >= '0' && value <= '1' )
|
|
{
|
|
value = value - '0';
|
|
}
|
|
else
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
if( cell > 7 )
|
|
{
|
|
return( false );
|
|
}
|
|
|
|
uint shift = 7 - cell;
|
|
*dest = (*dest & ~(1<<shift)) | (value<<shift);
|
|
return( true );
|
|
}
|
|
|
|
|
|
|
|
bool CHexBuffer::inputAscii( unsigned char *dest, int value, uint )
|
|
{
|
|
*dest = value;
|
|
return( true );
|
|
}
|
|
|
|
|
|
|
|
int CHexBuffer::moveBuffer( uint destOffset, uint srcOffset )
|
|
{
|
|
if( srcOffset > documentSize() || destOffset == srcOffset )
|
|
{
|
|
return( Err_Success );
|
|
}
|
|
|
|
if( destOffset < srcOffset )
|
|
{
|
|
char *dest = &data()[ destOffset ];
|
|
char *src = &data()[ srcOffset ];
|
|
|
|
memmove( dest, src, documentSize() - srcOffset );
|
|
setDocumentSize( documentSize() - (srcOffset - destOffset) );
|
|
return( Err_Success );
|
|
}
|
|
else
|
|
{
|
|
uint s = documentSize() - srcOffset;
|
|
if( destOffset + s >= size() )
|
|
{
|
|
int errCode = resizeBuffer( destOffset + s );
|
|
if( errCode != Err_Success )
|
|
{
|
|
fatalSound();
|
|
return( errCode );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setDocumentSize( documentSize() + (destOffset - srcOffset) );
|
|
}
|
|
|
|
char *dest = &data()[ destOffset ];
|
|
char *src = &data()[ srcOffset ];
|
|
|
|
memmove( dest, src, s );
|
|
memset( src, 0, destOffset - srcOffset );
|
|
return( Err_Success );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
int CHexBuffer::resizeBuffer( uint newSize )
|
|
{
|
|
if( newSize < documentSize() )
|
|
{
|
|
return( Err_Success );
|
|
}
|
|
|
|
if( newSize >= size() )
|
|
{
|
|
TQByteArray tmp;
|
|
tmp.duplicate( data(), size() );
|
|
if( tmp.isNull() == true )
|
|
{
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
if( fill( '\0', newSize + 100 ) == false )
|
|
{
|
|
return( Err_NoMemory );
|
|
}
|
|
|
|
memcpy( data(), &tmp[0], tmp.size() );
|
|
}
|
|
|
|
setDocumentSize( newSize );
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
void CHexBuffer::inputSound( void )
|
|
{
|
|
if( mInputErrorSound == true )
|
|
{
|
|
KNotifyClient::beep( TQObject::tr("Edit operation failed") );
|
|
}
|
|
}
|
|
|
|
|
|
void CHexBuffer::fatalSound( void )
|
|
{
|
|
if( mFatalErrorSound == true )
|
|
{
|
|
KNotifyClient::beep( TQObject::tr("Could not allocate memory") );
|
|
}
|
|
}
|
|
|
|
|
|
int CHexBuffer::printHtmlDataPage( const TQString &tocName,
|
|
const TQStringList &fileNames, uint index,
|
|
const SExportHtml &ex,
|
|
uint line, uint numLine )
|
|
{
|
|
if( fileNames.count() == 0 )
|
|
{
|
|
return( Err_NullArgument );
|
|
}
|
|
|
|
if( index >= fileNames.count() )
|
|
{
|
|
index = fileNames.count()-1;
|
|
}
|
|
|
|
TQFile file( fileNames[index] );
|
|
if( file.open( IO_WriteOnly ) == false )
|
|
{
|
|
return( Err_OperationAborted );
|
|
}
|
|
|
|
TQTextStream os( &file );
|
|
const TQString *next = index+1 >= fileNames.count() ? 0 : &fileNames[index+1];
|
|
const TQString *prev = index == 0 ? 0 : &fileNames[index-1];
|
|
const TQString *toc = tocName.length() == 0 ? 0 : &tocName;
|
|
|
|
printHtmlHeader( os, true );
|
|
if( ex.navigator == true )
|
|
{
|
|
printHtmlNavigator( os, next, prev, toc );
|
|
}
|
|
|
|
printHtmlCaption( os, ex.topCaption, index+1, fileNames.count() );
|
|
printHtmlTable( os, line, numLine, ex.blackWhite );
|
|
printHtmlCaption( os, ex.bottomCaption, index+1, fileNames.count() );
|
|
|
|
if( ex.navigator == true )
|
|
{
|
|
printHtmlNavigator( os, next, prev, toc );
|
|
}
|
|
printHtmlHeader( os, false );
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
void CHexBuffer::printHtmlTocPage( const TQString &tocName,
|
|
const TQString &linkName,
|
|
const TQStringList &fileNames,
|
|
const TQStringList &offsets,
|
|
uint numPage )
|
|
{
|
|
if( numPage == 0 || fileNames.count() == 0 )
|
|
{
|
|
return;
|
|
}
|
|
if( numPage >= fileNames.count() )
|
|
{
|
|
numPage = fileNames.count() - 1;
|
|
}
|
|
|
|
TQFile file( tocName );
|
|
if( file.open( IO_WriteOnly ) == false )
|
|
{
|
|
return;
|
|
}
|
|
|
|
TQTextStream os( &file );
|
|
printHtmlHeader( os, true );
|
|
|
|
os << "<P ALIGN=\"CENTER\">" << endl;
|
|
os << "<B><FONT COLOR=BLACK>" << endl;
|
|
os << mUrl << endl;
|
|
os << "</FONT></B></CAPTION>" << endl;
|
|
os << "</P>" << endl;
|
|
|
|
os << "<P ALIGN=\"CENTER\"><TT>" << endl;
|
|
for( uint i=0; i<=numPage; i++ )
|
|
{
|
|
TQString n( fileNames[i].right( fileNames[i].length() -
|
|
fileNames[i].findRev('/') - 1) );
|
|
os << "<A HREF=\"" << n << "\">" << i18n("Page") << i+1;
|
|
os << "</A>";
|
|
os << " " << offsets[i];
|
|
os << "<br>" << endl;
|
|
}
|
|
os << "</P>" << endl;
|
|
|
|
printHtmlHeader( os, false );
|
|
|
|
if( linkName.isEmpty() == false )
|
|
{
|
|
//
|
|
// Make a symlink. We ignore any error here. I don't consider
|
|
// it to be fatal.
|
|
//
|
|
TQString n( tocName.right( tocName.length() - tocName.findRev('/') - 1) );
|
|
symlink( n.latin1(), linkName.latin1() );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CHexBuffer::printHtmlCaption( TQTextStream &os, uint captionType,
|
|
uint curPage, uint numPage )
|
|
{
|
|
TQString caption;
|
|
switch( captionType )
|
|
{
|
|
case 0:
|
|
return;
|
|
break;
|
|
|
|
case 1:
|
|
caption = mUrl;
|
|
break;
|
|
|
|
case 2:
|
|
caption = mUrl.right( mUrl.length() - mUrl.findRev('/') - 1);
|
|
break;
|
|
|
|
case 3:
|
|
caption = i18n("Page %1 of %2").arg(curPage).arg(numPage);
|
|
break;
|
|
}
|
|
|
|
os << "<P ALIGN=\"CENTER\">" << endl;
|
|
os << "<B><FONT COLOR=BLACK>" << endl;
|
|
os << caption << endl;
|
|
os << "</FONT></B></CAPTION>" << endl;
|
|
os << "</P>" << endl;
|
|
}
|
|
|
|
|
|
|
|
void CHexBuffer::printHtmlNavigator( TQTextStream &os, const TQString *next,
|
|
const TQString *prev, const TQString *toc )
|
|
{
|
|
os << "<TABLE BORDER=\"0\" CELLSPACING=\"0\" WIDTH=\"100%\">" << endl;
|
|
os << "<TR>" << endl;
|
|
os << "<TD>" << endl;
|
|
if( next == 0 )
|
|
{
|
|
os << i18n("Next") << " ";
|
|
}
|
|
else
|
|
{
|
|
TQString n( next->right( next->length() - next->findRev('/') - 1) );
|
|
os << "<A HREF=\"" << n << "\">" << i18n("Next") << "</A>" << " ";
|
|
}
|
|
|
|
if( prev == 0 )
|
|
{
|
|
os << i18n("Previous") << " ";
|
|
}
|
|
else
|
|
{
|
|
TQString p( prev->right( prev->length() - prev->findRev('/') - 1) );
|
|
os << "<A HREF=\"" << p << "\">" << i18n("Previous") << "</A>" << " ";
|
|
}
|
|
|
|
if( toc == 0 )
|
|
{
|
|
os << i18n("Contents") << " ";
|
|
}
|
|
else
|
|
{
|
|
TQString t( toc->right( toc->length() - toc->findRev('/') - 1) );
|
|
os << "<A HREF=\"" << t << "\">" << i18n("Contents");
|
|
os << "</A>" << " ";
|
|
}
|
|
|
|
os << "</TD>" << endl;
|
|
|
|
os << "<TD ALIGN=\"RIGHT\">" << endl;
|
|
os << "<A HREF=\"" << "http://home.sol.no/~espensa/khexedit" << "\">";
|
|
os << i18n("Generated by khexedit");
|
|
os << "</A>" << " ";
|
|
|
|
os << "</TD>" << endl;
|
|
os << "</TR>" << endl << "</TABLE>" << endl;
|
|
}
|
|
|
|
|
|
int CHexBuffer::printHtmlHeader( TQTextStream &os, bool isFront )
|
|
{
|
|
if( isFront == true )
|
|
{
|
|
os << "<HTML>" << endl << "<HEAD>" << endl;
|
|
os << "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; ";
|
|
os << "charset=iso-8859-1\">" << endl;
|
|
os << "<META NAME=\"hexdata\" CONTENT=\"khexedit dump\">" << endl;
|
|
os << "</HEAD>" << endl << "<BODY>" << endl;
|
|
}
|
|
else
|
|
{
|
|
os << "</BODY>" << endl << "</HTML>" << endl;
|
|
}
|
|
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::printHtmlTable( TQTextStream &os, uint line, uint numLine,
|
|
bool bw )
|
|
{
|
|
uint i;
|
|
TQColor color;
|
|
|
|
|
|
int numCol = 1;
|
|
if( mLayout.offsetVisible == true ) { numCol += 1; }
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide ) { numCol += 1; }
|
|
|
|
os << "<TABLE BORDER=1 COLS=" << numCol << " WIDTH=\"100%\" ";
|
|
os << "CELLSPACING=0 CELLPADDING=2>" << endl;
|
|
if( mLayout.offsetVisible == true )
|
|
{
|
|
color = bw == true ? TQt::white : mColor.offsetBg;
|
|
os << "<TD BGCOLOR=" << TQString(color.name()).latin1() << ">" << endl;
|
|
os << "<TABLE BORDER=0 COLS=1 WIDTH=\"100%\" ";
|
|
os << "CELLSPACING=0 CELLPADDING=2>" << endl;
|
|
|
|
color = bw == true ? TQt::black : mColor.offsetFg;
|
|
for( i=0; i<numLine; i++ )
|
|
{
|
|
os << "<TR><TD><TT><b><FONT COLOR=" << TQString(color.name()).latin1() << ">";
|
|
THIS_FPTR(printOffset)( mPrintBuf, (line+i)*mLayout.lineSize );
|
|
mPrintBuf[mOffsetSize]=0;
|
|
os << mPrintBuf << "</TD></TR>" << endl;
|
|
}
|
|
os << "</TABLE>" << endl << "</TD>" << endl;
|
|
}
|
|
|
|
color = bw == true ? TQt::white : mColor.textBg;
|
|
os << "<TD BGCOLOR=" << TQString(color.name()).latin1() << ">" << endl;
|
|
os << "<TABLE BORDER=0 COLS=1 WIDTH=\"100%\" ";
|
|
os << "CELLSPACING=0 CELLPADDING=2>" << endl;
|
|
for( i=0; i<numLine; i++ )
|
|
{
|
|
printHtmlLine( os, line+i, true, bw );
|
|
}
|
|
os << "</TABLE>" << endl << "</TD>" << endl;
|
|
|
|
if( mLayout.secondaryMode != SDisplayLayout::hide )
|
|
{
|
|
color = bw == true ? TQt::white : mColor.textBg;
|
|
os << "<TD BGCOLOR=" << TQString(color.name()).latin1() << ">" << endl;
|
|
os << "<TABLE BORDER=0 COLS=1 WIDTH=\"100%\" ";
|
|
os << "CELLSPACING=0 CELLPADDING=2>" << endl;
|
|
for( i=0; i<numLine; i++ )
|
|
{
|
|
printHtmlLine( os, line+i, false, bw );
|
|
}
|
|
os << "</TABLE>" << endl << "</TD>" << endl;
|
|
}
|
|
|
|
os << "</TR>" << endl << "</TABLE>" << endl;
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
int CHexBuffer::printHtmlLine( TQTextStream &os, uint line, bool isPrimary,
|
|
bool bw )
|
|
{
|
|
uint offset = line * mLayout.lineSize;
|
|
TQColor prevColor;
|
|
|
|
TQColor color;
|
|
if( bw == true )
|
|
{
|
|
color = TQt::white;
|
|
}
|
|
else
|
|
{
|
|
color = (line+1) % 2 ? mColor.textBg : mColor.secondTextBg;
|
|
}
|
|
|
|
os << "<TR><TD NOWRAP BGCOLOR=" << TQString(color.name()).latin1() << "><TT><B>"
|
|
<< endl;
|
|
if( offset >= documentSize() )
|
|
{
|
|
os << "<BR></TD></TR>" << endl;
|
|
return( Err_Success );
|
|
}
|
|
|
|
for( uint i=0; i < mLayout.lineSize; i++ )
|
|
{
|
|
if( isPrimary == true )
|
|
{
|
|
if( offset+i >= documentSize() )
|
|
{
|
|
memset(mPrintBuf, ' ', mNumCell );
|
|
mPrintBuf[mNumCell] = 0;
|
|
if( i == 0 )
|
|
{
|
|
color = bw == true ? TQt::black : foregroundColor(i);
|
|
}
|
|
else
|
|
{
|
|
color = prevColor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned char val = (unsigned char)data()[offset+i];
|
|
if( THIS_FPTR(printCell)( mPrintBuf, val ) == 0 )
|
|
{
|
|
color = bw == true ? TQt::black : foregroundColor(i);
|
|
}
|
|
else
|
|
{
|
|
color = bw == true ? TQt::black : mColor.nonPrintFg;
|
|
}
|
|
}
|
|
mPrintBuf[mNumCell] = 0;
|
|
if( i == 0 )
|
|
{
|
|
os << "<FONT COLOR=" << TQString(color.name()).latin1() << ">";
|
|
}
|
|
else if( color != prevColor )
|
|
{
|
|
os << "</FONT><FONT COLOR=" << TQString(color.name()).latin1() << ">";
|
|
}
|
|
prevColor = color;
|
|
|
|
if( mPrintBuf[0] == '<' )
|
|
{
|
|
os << "<";
|
|
}
|
|
else
|
|
{
|
|
os << mPrintBuf;
|
|
if( (i+1) % mLayout.columnSize == 0 && (i+1) != mLayout.lineSize )
|
|
{
|
|
os << " ";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( offset+i >= documentSize() )
|
|
{
|
|
memset(mPrintBuf, ' ', 1 );
|
|
if( i == 0 )
|
|
{
|
|
color = bw == true ? TQt::black : mColor.secondaryFg;
|
|
}
|
|
else
|
|
{
|
|
color = prevColor;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned char val = (unsigned char)data()[offset+i];
|
|
if( printAsciiCell( mPrintBuf, val ) == 0 )
|
|
{
|
|
color = bw == true ? TQt::black : mColor.secondaryFg;
|
|
}
|
|
else
|
|
{
|
|
color = bw == true ? TQt::black : mColor.nonPrintFg;
|
|
}
|
|
mPrintBuf[1] = 0;
|
|
|
|
if( i == 0 )
|
|
{
|
|
os << "<FONT COLOR=" << TQString(color.name()).latin1() << ">";
|
|
}
|
|
else if( color != prevColor )
|
|
{
|
|
os << "</FONT><FONT COLOR=" << TQString(color.name()).latin1() << ">";
|
|
}
|
|
prevColor = color;
|
|
|
|
mPrintBuf[1] = 0;
|
|
os << (mPrintBuf[0] == '<' ? "<" : mPrintBuf);
|
|
}
|
|
|
|
}
|
|
}
|
|
os << "</TD></TR>" << endl;
|
|
return( Err_Success );
|
|
}
|
|
|
|
|
|
|
|
|
|
|