mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03:00
fd66dda1d7
To support editing of large files it is an advantage to not load the entire file into memory but only load whatever is needed for display at the moment. To make it work, file access is abstracted into a socalled HexDocument, of which there two: a memory based and a file based one. The former can be used for newly created documents, the latter for file based editing. Hex documents now do track changes instead of the HexEditor. HexEditor only sets new values. This frees HexEditor of some responsibility.
155 lines
3.4 KiB
C++
155 lines
3.4 KiB
C++
/*
|
|
* Copyright (c) 2021, Arne Elster <arne@elster.li>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "HexDocument.h"
|
|
|
|
void HexDocument::set(size_t position, u8 value)
|
|
{
|
|
m_changes.set(position, value);
|
|
}
|
|
|
|
bool HexDocument::is_dirty() const
|
|
{
|
|
return m_changes.size() > 0;
|
|
}
|
|
|
|
HexDocumentMemory::HexDocumentMemory(ByteBuffer&& buffer)
|
|
: m_buffer(move(buffer))
|
|
{
|
|
}
|
|
|
|
HexDocument::Cell HexDocumentMemory::get(size_t position)
|
|
{
|
|
auto tracked_change = m_changes.get(position);
|
|
if (tracked_change.has_value()) {
|
|
return Cell { tracked_change.value(), true };
|
|
} else {
|
|
return Cell { m_buffer[position], false };
|
|
}
|
|
}
|
|
|
|
size_t HexDocumentMemory::size() const
|
|
{
|
|
return m_buffer.size();
|
|
}
|
|
|
|
HexDocument::Type HexDocumentMemory::type() const
|
|
{
|
|
return Type::Memory;
|
|
}
|
|
|
|
void HexDocumentMemory::clear_changes()
|
|
{
|
|
m_changes.clear();
|
|
}
|
|
|
|
bool HexDocumentMemory::write_to_file(NonnullRefPtr<Core::File> file)
|
|
{
|
|
if (!file->seek(0))
|
|
return false;
|
|
if (!file->write(m_buffer.data(), m_buffer.size()))
|
|
return false;
|
|
for (auto& change : m_changes) {
|
|
file->seek(change.key, Core::SeekMode::SetPosition);
|
|
file->write(&change.value, 1);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
HexDocumentFile::HexDocumentFile(NonnullRefPtr<Core::File> file)
|
|
: m_file(file)
|
|
{
|
|
set_file(file);
|
|
}
|
|
|
|
void HexDocumentFile::write_to_file()
|
|
{
|
|
for (auto& change : m_changes) {
|
|
m_file->seek(change.key, Core::SeekMode::SetPosition);
|
|
m_file->write(&change.value, 1);
|
|
}
|
|
clear_changes();
|
|
// make sure the next get operation triggers a read
|
|
m_buffer_file_pos = m_file_size + 1;
|
|
}
|
|
|
|
bool HexDocumentFile::write_to_file(NonnullRefPtr<Core::File> file)
|
|
{
|
|
if (!file->truncate(size())) {
|
|
return false;
|
|
}
|
|
|
|
if (!file->seek(0) || !m_file->seek(0)) {
|
|
return false;
|
|
}
|
|
|
|
while (true) {
|
|
auto copy_buffer = m_file->read(64 * KiB);
|
|
if (copy_buffer.size() == 0)
|
|
break;
|
|
file->write(copy_buffer.data(), copy_buffer.size());
|
|
}
|
|
|
|
for (auto& change : m_changes) {
|
|
file->seek(change.key, Core::SeekMode::SetPosition);
|
|
file->write(&change.value, 1);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
HexDocument::Cell HexDocumentFile::get(size_t position)
|
|
{
|
|
auto tracked_change = m_changes.get(position);
|
|
if (tracked_change.has_value()) {
|
|
return Cell { tracked_change.value(), true };
|
|
}
|
|
|
|
if (position < m_buffer_file_pos || position >= m_buffer_file_pos + m_buffer.size()) {
|
|
m_file->seek(position, Core::SeekMode::SetPosition);
|
|
m_file->read(m_buffer.data(), m_buffer.size());
|
|
m_buffer_file_pos = position;
|
|
}
|
|
return { m_buffer[position - m_buffer_file_pos], false };
|
|
}
|
|
|
|
size_t HexDocumentFile::size() const
|
|
{
|
|
return m_file_size;
|
|
}
|
|
|
|
HexDocument::Type HexDocumentFile::type() const
|
|
{
|
|
return Type::File;
|
|
}
|
|
|
|
void HexDocumentFile::clear_changes()
|
|
{
|
|
m_changes.clear();
|
|
}
|
|
|
|
void HexDocumentFile::set_file(NonnullRefPtr<Core::File> file)
|
|
{
|
|
m_file = file;
|
|
|
|
off_t size = 0;
|
|
if (!file->seek(0, Core::SeekMode::FromEndPosition, &size)) {
|
|
m_file_size = 0;
|
|
} else {
|
|
m_file_size = size;
|
|
}
|
|
file->seek(0, Core::SeekMode::SetPosition);
|
|
|
|
clear_changes();
|
|
// make sure the next get operation triggers a read
|
|
m_buffer_file_pos = m_file_size + 1;
|
|
}
|
|
|
|
NonnullRefPtr<Core::File> HexDocumentFile::file() const
|
|
{
|
|
return m_file;
|
|
}
|