Started to work on a DiskProbe replacement as a side project.

Implemented the basic editor engine that has features like undo/redo
and everything else DiskProbe could possibly need - not complete yet,
though it already has everything that would be needed for a 1:1 DiskProbe
duplicate.
The DiskProbe app is currently just a small text based test for that engine.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6096 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-01-15 17:21:23 +00:00
parent e1e76c7813
commit 1df68d1dee
4 changed files with 736 additions and 0 deletions
+475
View File
@@ -0,0 +1,475 @@
/*
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "DataEditor.h"
#include <Autolock.h>
#include <NodeMonitor.h>
class DataChange {
public:
virtual ~DataChange();
virtual void Apply(off_t offset, uint8 *buffer, size_t size) = 0;
virtual void Revert(off_t offset, uint8 *buffer, size_t size) = 0;
};
class ReplaceChange : public DataChange {
public:
ReplaceChange(off_t bufferOffset, uint8 *buffer,
off_t offset, const uint8 *data, size_t size);
~ReplaceChange();
virtual void Apply(off_t offset, uint8 *buffer, size_t size);
virtual void Revert(off_t offset, uint8 *buffer, size_t size);
private:
void Normalize(off_t bufferOffset, size_t bufferSize,
off_t &offset, size_t &dataOffset, size_t &size);
uint8 *fNewData;
uint8 *fOldData;
size_t fSize;
off_t fOffset;
};
DataChange::~DataChange()
{
}
// #pragma mark -
ReplaceChange::ReplaceChange(off_t bufferOffset, uint8 *buffer,
off_t offset, const uint8 *data, size_t size)
{
fOffset = offset;
fNewData = (uint8 *)malloc(size);
fOldData = (uint8 *)malloc(size);
if (fNewData != NULL && fOldData != NULL) {
// Save old data, and replace the data in the supplied buffer.
// Note, the buffer must be large enough to hold the changes
// at this point!
memcpy(fNewData, data, size);
memcpy(fOldData, buffer + offset - bufferOffset, size);
memcpy(buffer + offset - bufferOffset, fNewData, size);
fSize = size;
} else
fSize = 0;
}
ReplaceChange::~ReplaceChange()
{
free(fNewData);
free(fOldData);
}
/** Normalizes the supplied offset & size pair to be limited by
* the buffer offset and size.
* All parameters must have been initialized before calling this
* method.
*/
void
ReplaceChange::Normalize(off_t bufferOffset, size_t bufferSize, off_t &offset,
size_t &dataOffset, size_t &size)
{
if (fOffset < bufferOffset) {
offset = bufferOffset;
dataOffset = bufferOffset - fOffset;
size -= dataOffset;
}
if (offset + size > bufferOffset + bufferSize)
size = offset - bufferOffset + offset;
}
void
ReplaceChange::Apply(off_t bufferOffset, uint8 *buffer, size_t bufferSize)
{
// is it in our range?
if (fOffset - bufferOffset > bufferSize || fOffset + fSize < bufferOffset)
return;
// don't change anything outside the supplied buffer
off_t offset = fOffset;
size_t dataOffset = 0;
size_t size = fSize;
Normalize(bufferOffset, bufferSize, offset, dataOffset, size);
if (size == 0)
return;
// now we can safely change the buffer!
memcpy(buffer + offset - bufferOffset, fNewData + dataOffset, size);
}
void
ReplaceChange::Revert(off_t bufferOffset, uint8 *buffer, size_t bufferSize)
{
// is it in our range?
if (fOffset - bufferOffset > bufferSize || fOffset + fSize < bufferOffset)
return;
// don't change anything outside the supplied buffer
off_t offset = fOffset;
size_t dataOffset = 0;
size_t size = fSize;
Normalize(bufferOffset, bufferSize, offset, dataOffset, size);
if (size == 0)
return;
// now we can safely revert the buffer!
memcpy(buffer + offset - bufferOffset, fOldData + dataOffset, size);
}
// #pragma mark -
DataEditor::DataEditor()
:
fLock("data view")
{
}
DataEditor::DataEditor(entry_ref &ref, const char *attribute)
:
fLock("data view")
{
SetTo(ref, attribute);
}
DataEditor::DataEditor(BEntry &entry, const char *attribute)
:
fLock("data view")
{
SetTo(entry, attribute);
}
DataEditor::DataEditor(const DataEditor &editor)
:
fLock("data view")
{
}
DataEditor::~DataEditor()
{
}
status_t
DataEditor::SetTo(const char *path, const char *attribute)
{
BEntry entry(path);
SetTo(entry, attribute);
}
status_t
DataEditor::SetTo(entry_ref &ref, const char *attribute)
{
BEntry entry(&ref);
SetTo(entry, attribute);
}
status_t
DataEditor::SetTo(BEntry &entry, const char *attribute)
{
status_t status = fFile.SetTo(&entry, B_READ_WRITE);
if (status < B_OK) {
// try to open read only
status = fFile.SetTo(&entry, B_READ_ONLY);
if (status < B_OK)
return status;
fIsReadOnly = true;
}
status = fFile.GetSize(&fSize);
if (status < B_OK) {
fFile.Unset();
return status;
}
fBlockSize = 512;
fAttribute = attribute;
fRealViewOffset = -1;
fViewOffset = 0;
fRealViewSize = fViewSize = fBlockSize;
fNeedsUpdate = true;
}
status_t
DataEditor::SetToAttribute(const char *attribute)
{
status_t status = InitCheck();
if (status < B_OK)
return status;
fAttribute = attribute;
// ToDo: attributes are not yet supported
return B_ERROR;
}
status_t
DataEditor::InitCheck()
{
if (fAttribute != NULL)
// ToDo: for now!
return B_ERROR;
return fFile.InitCheck();
}
void
DataEditor::AddChange(DataChange *change)
{
if (change == NULL)
return;
fChanges.AddItem(change);
fLastChange = change;
}
status_t
DataEditor::Replace(off_t offset, const uint8 *data, size_t length)
{
if (!fLock.IsLocked())
debugger("DataEditor: view not locked");
if (fNeedsUpdate) {
status_t status = Update();
if (status < B_OK)
return status;
}
ReplaceChange *change = new ReplaceChange(fRealViewOffset, fView, offset, data, length);
AddChange(change);
return B_OK;
}
status_t
DataEditor::Remove(off_t offset, off_t length)
{
if (!fLock.IsLocked())
debugger("DataEditor: view not locked");
// not yet implemented
return B_ERROR;
}
status_t
DataEditor::Insert(off_t offset, const uint8 *text, size_t length)
{
if (!fLock.IsLocked())
debugger("DataEditor: view not locked");
// not yet implemented
return B_ERROR;
}
void
DataEditor::ApplyChanges()
{
int32 count = fChanges.CountItems();
for (int32 i = 0; i < count; i++) {
DataChange *change = fChanges.ItemAt(i);
change->Apply(fRealViewOffset, fView, fRealViewSize);
}
}
void
DataEditor::RemoveRedos()
{
}
status_t
DataEditor::Undo()
{
if (!CanUndo())
return B_ERROR;
int32 index = fChanges.IndexOf(fLastChange);
fLastChange->Revert(fRealViewOffset, fView, fRealViewSize);
if (index > 0)
fLastChange = fChanges.ItemAt(index - 1);
else
fLastChange = NULL;
return B_OK;
}
status_t
DataEditor::Redo()
{
}
bool
DataEditor::CanUndo() const
{
return fLastChange != NULL;
}
bool
DataEditor::CanRedo() const
{
return fLastChange != NULL && fChanges.IndexOf(fLastChange) < fChanges.CountItems() - 1;
}
status_t
DataEditor::SetFileSize(off_t size)
{
fSize = size;
}
status_t
DataEditor::SetViewOffset(off_t offset)
{
if (fView == NULL) {
status_t status = SetViewSize(fViewSize);
if (status < B_OK)
return status;
}
fRealViewOffset = (offset / fBlockSize) * fBlockSize;
fViewOffset = offset;
fNeedsUpdate = true;
}
status_t
DataEditor::SetViewSize(size_t size)
{
size_t realSize = (size + fBlockSize - 1) & ~(fBlockSize - 1);
// round to the next multiple of block size
if (realSize == fRealViewSize && fView != NULL) {
fViewSize = size;
return B_OK;
}
uint8 *view = (uint8 *)realloc(fView, realSize);
if (view == NULL)
return B_NO_MEMORY;
fView = view;
fRealViewSize = realSize;
fViewSize = size;
fNeedsUpdate = true;
return B_OK;
}
void
DataEditor::SetBlockSize(size_t size)
{
fBlockSize = size;
}
status_t
DataEditor::Update()
{
ssize_t bytesRead = fFile.ReadAt(fRealViewOffset, fView, fRealViewSize);
if (bytesRead < B_OK)
return bytesRead;
ApplyChanges();
fNeedsUpdate = false;
return B_OK;
}
status_t
DataEditor::GetViewBuffer(const uint8 **_buffer)
{
if (!fLock.IsLocked())
debugger("DataEditor: view not locked");
status_t status = B_OK;
if (fView == NULL)
status = SetViewOffset(fViewOffset);
if (status == B_OK && fNeedsUpdate)
status = Update();
if (status < B_OK)
return status;
*_buffer = fView + fViewOffset - fRealViewOffset;
return B_OK;
}
bool
DataEditor::Lock()
{
return fLock.Lock();
}
void
DataEditor::Unlock()
{
fLock.Unlock();
}
status_t
DataEditor::StartWatching(BMessenger target)
{
node_ref node;
status_t status = fFile.GetNodeRef(&node);
if (status < B_OK)
return status;
return watch_node(&node, B_WATCH_STAT | B_WATCH_ATTR, target);
}
void
DataEditor::StopWatching(BMessenger target)
{
stop_watching(target);
}
+96
View File
@@ -0,0 +1,96 @@
/*
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef DATA_EDITOR_H
#define DATA_EDITOR_H
#include <File.h>
#include <Entry.h>
#include <Locker.h>
#include <ObjectList.h>
class DataChange;
class DataEditor {
public:
DataEditor();
DataEditor(entry_ref &ref, const char *attribute = NULL);
DataEditor(BEntry &entry, const char *attribute = NULL);
DataEditor(const DataEditor &editor);
~DataEditor();
status_t SetTo(const char *path, const char *attribute = NULL);
status_t SetTo(entry_ref &ref, const char *attribute = NULL);
status_t SetTo(BEntry &entry, const char *attribute = NULL);
status_t SetToAttribute(const char *attribute);
bool IsReadOnly() const { return fIsReadOnly; }
bool IsDevice() const { return fIsDevice; }
//bool IsModified() const { return fIsModified; }
status_t InitCheck();
status_t Replace(off_t offset, const uint8 *data, size_t length);
status_t Remove(off_t offset, off_t length);
status_t Insert(off_t offset, const uint8 *data, size_t length);
status_t MoveBy(int32 bytes);
status_t MoveTo(off_t offset);
status_t Undo();
status_t Redo();
bool CanUndo() const;
bool CanRedo() const;
status_t SetFileSize(off_t size);
off_t FileSize() const { return fSize; }
status_t SetViewOffset(off_t offset);
off_t ViewOffset() const { return fViewOffset; }
status_t SetViewSize(size_t size);
off_t ViewSize() const { return fViewSize; }
void SetBlockSize(size_t size);
size_t BlockSize() const { return fBlockSize; }
status_t GetViewBuffer(const uint8 **_buffer);
BLocker &Locker() { return fLock; }
bool Lock();
void Unlock();
status_t StartWatching(BMessenger target);
void StopWatching(BMessenger target);
BFile &File() { return fFile; }
private:
status_t Update();
void AddChange(DataChange *change);
void ApplyChanges();
void RemoveRedos();
BFile fFile;
const char *fAttribute;
bool fIsDevice, fIsReadOnly;
off_t fRealSize, fSize;
BObjectList<DataChange> fChanges;
DataChange *fFirstChange;
DataChange *fLastChange;
BLocker fLock;
uint8 *fView;
off_t fRealViewOffset, fViewOffset;
size_t fRealViewSize, fViewSize;
bool fNeedsUpdate;
size_t fBlockSize;
};
#endif /* DATA_EDITOR_H */
+153
View File
@@ -0,0 +1,153 @@
/*
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "DataEditor.h"
#include <Application.h>
#include <Autolock.h>
#include <stdio.h>
#include <string.h>
static const char *kSignature = "application/x-vnd.OpenBeOS-DiskProbe";
class DiskProbe : public BApplication {
public:
DiskProbe();
~DiskProbe();
};
#define DUMPED_BLOCK_SIZE 16
void
dumpBlock(const uint8 *buffer, int size, const char *prefix)
{
int i;
for (i = 0; i < size;) {
int start = i;
printf(prefix);
for (; i < start+DUMPED_BLOCK_SIZE; i++) {
if (!(i % 4))
printf(" ");
if (i >= size)
printf(" ");
else
printf("%02x", *(unsigned char *)(buffer + i));
}
printf(" ");
for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) {
if (i < size) {
char c = buffer[i];
if (c < 30)
printf(".");
else
printf("%c", c);
} else
break;
}
printf("\n");
}
}
status_t
printBlock(DataEditor &editor, const char *text)
{
puts(text);
const uint8 *buffer;
status_t status = editor.GetViewBuffer(&buffer);
if (status < B_OK) {
fprintf(stderr, "Could not get block: %s\n", strerror(status));
return status;
}
dumpBlock(buffer, editor.FileSize() > editor.ViewOffset() + editor.ViewSize() ?
editor.ViewSize() : editor.FileSize() - editor.ViewOffset(),
"\t");
return B_OK;
}
// #pragma mark -
DiskProbe::DiskProbe()
: BApplication(kSignature)
{
DataEditor editor;
status_t status = editor.SetTo("/boot/beos/apps/DiskProbe");
if (status < B_OK) {
fprintf(stderr, "Could not set editor: %s\n", strerror(status));
return;
}
editor.SetBlockSize(512);
editor.SetViewOffset(0);
editor.SetViewSize(32);
BAutolock locker(editor.Locker());
if (printBlock(editor, "before (location 0):") < B_OK)
return;
editor.Replace(5, (const uint8 *)"*REPLACED*", 10);
if (printBlock(editor, "after (location 0):") < B_OK)
return;
editor.SetViewOffset(700);
if (printBlock(editor, "before (location 700):") < B_OK)
return;
editor.Replace(713, (const uint8 *)"**REPLACED**", 12);
if (printBlock(editor, "after (location 700):") < B_OK)
return;
status = editor.Undo();
if (status < B_OK)
fprintf(stderr, "Could not undo: %s\n", strerror(status));
if (printBlock(editor, "undo (location 700):") < B_OK)
return;
editor.SetViewOffset(0);
if (printBlock(editor, "after (location 0):") < B_OK)
return;
status = editor.Undo();
if (status < B_OK)
fprintf(stderr, "Could not undo: %s\n", strerror(status));
if (printBlock(editor, "undo (location 0):") < B_OK)
return;
PostMessage(B_QUIT_REQUESTED);
}
DiskProbe::~DiskProbe()
{
}
// #pragma mark -
int
main(int argc, char **argv)
{
DiskProbe probe;
probe.Run();
return 0;
}
+12
View File
@@ -0,0 +1,12 @@
SubDir OBOS_TOP src apps diskprobe ;
UsePrivateHeaders shared ;
# AddResources DiskProbe : DiskProbe.rsrc ;
App DiskProbe :
DiskProbe.cpp
DataEditor.cpp
;
LinkSharedOSLibs DiskProbe : be ;