forked from pstavirs/ostinato
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes pstavirs#103 Fixes pstavirs#202
- Loading branch information
Showing
12 changed files
with
1,870 additions
and
1,405 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,17 @@ | ||
TEMPLATE = lib | ||
CONFIG += qt staticlib warn_on | ||
QT += core gui | ||
|
||
HEADERS = src/commands.h\ | ||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets | ||
|
||
VERSION = 4.0.0 | ||
|
||
DEFINES += QHEXEDIT_EXPORTS | ||
|
||
HEADERS = src/chunks.h\ | ||
src/commands.h \ | ||
src/qhexedit.h \ | ||
src/qhexedit_p.h \ | ||
src/xbytearray.h | ||
|
||
SOURCES = src/commands.cpp \ | ||
src/qhexedit.cpp \ | ||
src/qhexedit_p.cpp \ | ||
src/xbytearray.cpp | ||
SOURCES = src/chunks.cpp \ | ||
src/commands.cpp \ | ||
src/qhexedit.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Release 0.8.4, 2017-01-16 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
#include "chunks.h" | ||
#include <limits.h> | ||
|
||
#define NORMAL 0 | ||
#define HIGHLIGHTED 1 | ||
|
||
#define BUFFER_SIZE 0x10000 | ||
#define CHUNK_SIZE 0x1000 | ||
#define READ_CHUNK_MASK Q_INT64_C(0xfffffffffffff000) | ||
|
||
// ***************************************** Constructors and file settings | ||
|
||
Chunks::Chunks(QObject *parent): QObject(parent) | ||
{ | ||
QBuffer *buf = new QBuffer(this); | ||
setIODevice(*buf); | ||
} | ||
|
||
Chunks::Chunks(QIODevice &ioDevice, QObject *parent): QObject(parent) | ||
{ | ||
setIODevice(ioDevice); | ||
} | ||
|
||
bool Chunks::setIODevice(QIODevice &ioDevice) | ||
{ | ||
_ioDevice = &ioDevice; | ||
bool ok = _ioDevice->open(QIODevice::ReadOnly); | ||
if (ok) // Try to open IODevice | ||
{ | ||
_size = _ioDevice->size(); | ||
_ioDevice->close(); | ||
} | ||
else // Fallback is an empty buffer | ||
{ | ||
QBuffer *buf = new QBuffer(this); | ||
_ioDevice = buf; | ||
_size = 0; | ||
} | ||
_chunks.clear(); | ||
_pos = 0; | ||
return ok; | ||
} | ||
|
||
|
||
// ***************************************** Getting data out of Chunks | ||
|
||
QByteArray Chunks::data(qint64 pos, qint64 maxSize, QByteArray *highlighted) | ||
{ | ||
qint64 ioDelta = 0; | ||
int chunkIdx = 0; | ||
|
||
Chunk chunk; | ||
QByteArray buffer; | ||
|
||
// Do some checks and some arrangements | ||
if (highlighted) | ||
highlighted->clear(); | ||
|
||
if (pos >= _size) | ||
return buffer; | ||
|
||
if (maxSize < 0) | ||
maxSize = _size; | ||
else | ||
if ((pos + maxSize) > _size) | ||
maxSize = _size - pos; | ||
|
||
_ioDevice->open(QIODevice::ReadOnly); | ||
|
||
while (maxSize > 0) | ||
{ | ||
chunk.absPos = LLONG_MAX; | ||
bool chunksLoopOngoing = true; | ||
while ((chunkIdx < _chunks.count()) && chunksLoopOngoing) | ||
{ | ||
// In this section, we track changes before our required data and | ||
// we take the editdet data, if availible. ioDelta is a difference | ||
// counter to justify the read pointer to the original data, if | ||
// data in between was deleted or inserted. | ||
|
||
chunk = _chunks[chunkIdx]; | ||
if (chunk.absPos > pos) | ||
chunksLoopOngoing = false; | ||
else | ||
{ | ||
chunkIdx += 1; | ||
qint64 count; | ||
qint64 chunkOfs = pos - chunk.absPos; | ||
if (maxSize > ((qint64)chunk.data.size() - chunkOfs)) | ||
{ | ||
count = (qint64)chunk.data.size() - chunkOfs; | ||
ioDelta += CHUNK_SIZE - chunk.data.size(); | ||
} | ||
else | ||
count = maxSize; | ||
if (count > 0) | ||
{ | ||
buffer += chunk.data.mid(chunkOfs, (int)count); | ||
maxSize -= count; | ||
pos += count; | ||
if (highlighted) | ||
*highlighted += chunk.dataChanged.mid(chunkOfs, (int)count); | ||
} | ||
} | ||
} | ||
|
||
if ((maxSize > 0) && (pos < chunk.absPos)) | ||
{ | ||
// In this section, we read data from the original source. This only will | ||
// happen, whe no copied data is available | ||
|
||
qint64 byteCount; | ||
QByteArray readBuffer; | ||
if ((chunk.absPos - pos) > maxSize) | ||
byteCount = maxSize; | ||
else | ||
byteCount = chunk.absPos - pos; | ||
|
||
maxSize -= byteCount; | ||
_ioDevice->seek(pos + ioDelta); | ||
readBuffer = _ioDevice->read(byteCount); | ||
buffer += readBuffer; | ||
if (highlighted) | ||
*highlighted += QByteArray(readBuffer.size(), NORMAL); | ||
pos += readBuffer.size(); | ||
} | ||
} | ||
_ioDevice->close(); | ||
return buffer; | ||
} | ||
|
||
bool Chunks::write(QIODevice &iODevice, qint64 pos, qint64 count) | ||
{ | ||
if (count == -1) | ||
count = _size; | ||
bool ok = iODevice.open(QIODevice::WriteOnly); | ||
if (ok) | ||
{ | ||
for (qint64 idx=pos; idx < count; idx += BUFFER_SIZE) | ||
{ | ||
QByteArray ba = data(idx, BUFFER_SIZE); | ||
iODevice.write(ba); | ||
} | ||
iODevice.close(); | ||
} | ||
return ok; | ||
} | ||
|
||
|
||
// ***************************************** Set and get highlighting infos | ||
|
||
void Chunks::setDataChanged(qint64 pos, bool dataChanged) | ||
{ | ||
if ((pos < 0) || (pos >= _size)) | ||
return; | ||
int chunkIdx = getChunkIndex(pos); | ||
qint64 posInBa = pos - _chunks[chunkIdx].absPos; | ||
_chunks[chunkIdx].dataChanged[(int)posInBa] = char(dataChanged); | ||
} | ||
|
||
bool Chunks::dataChanged(qint64 pos) | ||
{ | ||
QByteArray highlighted; | ||
data(pos, 1, &highlighted); | ||
return bool(highlighted.at(0)); | ||
} | ||
|
||
|
||
// ***************************************** Search API | ||
|
||
qint64 Chunks::indexOf(const QByteArray &ba, qint64 from) | ||
{ | ||
qint64 result = -1; | ||
QByteArray buffer; | ||
|
||
for (qint64 pos=from; (pos < _size) && (result < 0); pos += BUFFER_SIZE) | ||
{ | ||
buffer = data(pos, BUFFER_SIZE + ba.size() - 1); | ||
int findPos = buffer.indexOf(ba); | ||
if (findPos >= 0) | ||
result = pos + (qint64)findPos; | ||
} | ||
return result; | ||
} | ||
|
||
qint64 Chunks::lastIndexOf(const QByteArray &ba, qint64 from) | ||
{ | ||
qint64 result = -1; | ||
QByteArray buffer; | ||
|
||
for (qint64 pos=from; (pos > 0) && (result < 0); pos -= BUFFER_SIZE) | ||
{ | ||
qint64 sPos = pos - BUFFER_SIZE - (qint64)ba.size() + 1; | ||
if (sPos < 0) | ||
sPos = 0; | ||
buffer = data(sPos, pos - sPos); | ||
int findPos = buffer.lastIndexOf(ba); | ||
if (findPos >= 0) | ||
result = sPos + (qint64)findPos; | ||
} | ||
return result; | ||
} | ||
|
||
|
||
// ***************************************** Char manipulations | ||
|
||
bool Chunks::insert(qint64 pos, char b) | ||
{ | ||
if ((pos < 0) || (pos > _size)) | ||
return false; | ||
int chunkIdx; | ||
if (pos == _size) | ||
chunkIdx = getChunkIndex(pos-1); | ||
else | ||
chunkIdx = getChunkIndex(pos); | ||
qint64 posInBa = pos - _chunks[chunkIdx].absPos; | ||
_chunks[chunkIdx].data.insert(posInBa, b); | ||
_chunks[chunkIdx].dataChanged.insert(posInBa, char(1)); | ||
for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) | ||
_chunks[idx].absPos += 1; | ||
_size += 1; | ||
_pos = pos; | ||
return true; | ||
} | ||
|
||
bool Chunks::overwrite(qint64 pos, char b) | ||
{ | ||
if ((pos < 0) || (pos >= _size)) | ||
return false; | ||
int chunkIdx = getChunkIndex(pos); | ||
qint64 posInBa = pos - _chunks[chunkIdx].absPos; | ||
_chunks[chunkIdx].data[(int)posInBa] = b; | ||
_chunks[chunkIdx].dataChanged[(int)posInBa] = char(1); | ||
_pos = pos; | ||
return true; | ||
} | ||
|
||
bool Chunks::removeAt(qint64 pos) | ||
{ | ||
if ((pos < 0) || (pos >= _size)) | ||
return false; | ||
int chunkIdx = getChunkIndex(pos); | ||
qint64 posInBa = pos - _chunks[chunkIdx].absPos; | ||
_chunks[chunkIdx].data.remove(posInBa, 1); | ||
_chunks[chunkIdx].dataChanged.remove(posInBa, 1); | ||
for (int idx=chunkIdx+1; idx < _chunks.size(); idx++) | ||
_chunks[idx].absPos -= 1; | ||
_size -= 1; | ||
_pos = pos; | ||
return true; | ||
} | ||
|
||
|
||
// ***************************************** Utility functions | ||
|
||
char Chunks::operator[](qint64 pos) | ||
{ | ||
return data(pos, 1)[0]; | ||
} | ||
|
||
qint64 Chunks::pos() | ||
{ | ||
return _pos; | ||
} | ||
|
||
qint64 Chunks::size() | ||
{ | ||
return _size; | ||
} | ||
|
||
int Chunks::getChunkIndex(qint64 absPos) | ||
{ | ||
// This routine checks, if there is already a copied chunk available. If os, it | ||
// returns a reference to it. If there is no copied chunk available, original | ||
// data will be copied into a new chunk. | ||
|
||
int foundIdx = -1; | ||
int insertIdx = 0; | ||
qint64 ioDelta = 0; | ||
|
||
|
||
for (int idx=0; idx < _chunks.size(); idx++) | ||
{ | ||
Chunk chunk = _chunks[idx]; | ||
if ((absPos >= chunk.absPos) && (absPos < (chunk.absPos + chunk.data.size()))) | ||
{ | ||
foundIdx = idx; | ||
break; | ||
} | ||
if (absPos < chunk.absPos) | ||
{ | ||
insertIdx = idx; | ||
break; | ||
} | ||
ioDelta += chunk.data.size() - CHUNK_SIZE; | ||
insertIdx = idx + 1; | ||
} | ||
|
||
if (foundIdx == -1) | ||
{ | ||
Chunk newChunk; | ||
qint64 readAbsPos = absPos - ioDelta; | ||
qint64 readPos = (readAbsPos & READ_CHUNK_MASK); | ||
_ioDevice->open(QIODevice::ReadOnly); | ||
_ioDevice->seek(readPos); | ||
newChunk.data = _ioDevice->read(CHUNK_SIZE); | ||
_ioDevice->close(); | ||
newChunk.absPos = absPos - (readAbsPos - readPos); | ||
newChunk.dataChanged = QByteArray(newChunk.data.size(), char(0)); | ||
_chunks.insert(insertIdx, newChunk); | ||
foundIdx = insertIdx; | ||
} | ||
return foundIdx; | ||
} | ||
|
||
|
||
#ifdef MODUL_TEST | ||
int Chunks::chunkSize() | ||
{ | ||
return _chunks.size(); | ||
} | ||
|
||
#endif |
Oops, something went wrong.