mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
GIODevice: Add a read_all() that returns a ByteBuffer with all we can read.
Use this to implement file opening in TextEditor.
This commit is contained in:
parent
8e3d0a23d5
commit
9ad076178a
Notes:
sideshowbarker
2024-07-19 15:00:57 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/9ad076178a4
6 changed files with 58 additions and 25 deletions
|
@ -100,6 +100,7 @@ public:
|
|||
}
|
||||
|
||||
ByteBuffer to_byte_buffer() const;
|
||||
static String from_byte_buffer(const ByteBuffer&);
|
||||
|
||||
static String format(const char*, ...);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
byte* offset_pointer(int offset) { return m_data + offset; }
|
||||
const byte* offset_pointer(int offset) const { return m_data + offset; }
|
||||
|
||||
void* end_pointer() { return m_data + m_size; }
|
||||
const void* end_pointer() const { return m_data + m_size; }
|
||||
|
||||
// NOTE: trim() does not reallocate.
|
||||
|
@ -109,6 +110,7 @@ public:
|
|||
byte* offset_pointer(ssize_t offset) { return m_impl ? m_impl->offset_pointer(offset) : nullptr; }
|
||||
const byte* offset_pointer(ssize_t offset) const { return m_impl ? m_impl->offset_pointer(offset) : nullptr; }
|
||||
|
||||
void* end_pointer() { return m_impl ? m_impl->end_pointer() : nullptr; }
|
||||
const void* end_pointer() const { return m_impl ? m_impl->end_pointer() : nullptr; }
|
||||
|
||||
// NOTE: trim() does not reallocate.
|
||||
|
@ -137,6 +139,13 @@ public:
|
|||
m_impl->grow(size);
|
||||
}
|
||||
|
||||
void append(const void* data, int data_size)
|
||||
{
|
||||
int old_size = size();
|
||||
grow(size() + data_size);
|
||||
memcpy(pointer() + old_size, data, data_size);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ByteBuffer(RetainPtr<ByteBufferImpl>&& impl)
|
||||
: m_impl(move(impl))
|
||||
|
|
|
@ -92,6 +92,15 @@ ByteBuffer String::to_byte_buffer() const
|
|||
return ByteBuffer::copy(reinterpret_cast<const byte*>(characters()), length());
|
||||
}
|
||||
|
||||
String String::from_byte_buffer(const ByteBuffer& buffer)
|
||||
{
|
||||
if (buffer.is_null())
|
||||
return nullptr;
|
||||
if (buffer.is_empty())
|
||||
return empty();
|
||||
return String((const char*)buffer.pointer(), buffer.size());
|
||||
}
|
||||
|
||||
unsigned String::to_uint(bool& ok) const
|
||||
{
|
||||
unsigned value = 0;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <LibGUI/GTextEditor.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GFontDatabase.h>
|
||||
#include <LibGUI/GFile.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
@ -34,31 +35,13 @@ int main(int argc, char** argv)
|
|||
String path = "/tmp/TextEditor.save.txt";
|
||||
if (argc >= 2) {
|
||||
path = argv[1];
|
||||
StringBuilder builder;
|
||||
int fd = open(path.characters(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
GFile file(path);
|
||||
|
||||
if (!file.open(GIODevice::ReadOnly)) {
|
||||
fprintf(stderr, "Opening %s: %s\n", path.characters(), file.error_string());
|
||||
return 1;
|
||||
}
|
||||
for (;;) {
|
||||
char buffer[BUFSIZ];
|
||||
ssize_t nread = read(fd, buffer, sizeof(buffer));
|
||||
if (nread < 0) {
|
||||
perror("read");
|
||||
return 1;
|
||||
}
|
||||
if (nread == 0)
|
||||
break;
|
||||
builder.append(buffer, nread);
|
||||
}
|
||||
|
||||
int rc = close(fd);
|
||||
if (rc < 0) {
|
||||
perror("close");
|
||||
return 1;
|
||||
}
|
||||
|
||||
text_editor->set_text(builder.to_string());
|
||||
text_editor->set_text(String::from_byte_buffer(file.read_all()));
|
||||
}
|
||||
|
||||
auto new_action = GAction::create("New document", { Mod_Ctrl, Key_N }, GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/new.rgb", { 16, 16 }), [] (const GAction&) {
|
||||
|
|
|
@ -46,7 +46,7 @@ ByteBuffer GIODevice::read(int max_size)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
bool GIODevice::can_read() const
|
||||
bool GIODevice::can_read_from_fd() const
|
||||
{
|
||||
// FIXME: Can we somehow remove this once GSocket is implemented using non-blocking sockets?
|
||||
fd_set rfds;
|
||||
|
@ -68,12 +68,41 @@ bool GIODevice::can_read_line()
|
|||
return true;
|
||||
if (m_buffered_data.contains_slow('\n'))
|
||||
return true;
|
||||
if (!can_read())
|
||||
if (!can_read_from_fd())
|
||||
return false;
|
||||
populate_read_buffer();
|
||||
return m_buffered_data.contains_slow('\n');
|
||||
}
|
||||
|
||||
bool GIODevice::can_read() const
|
||||
{
|
||||
return !m_buffered_data.is_empty() || can_read_from_fd();
|
||||
}
|
||||
|
||||
ByteBuffer GIODevice::read_all()
|
||||
{
|
||||
ByteBuffer buffer;
|
||||
if (!m_buffered_data.is_empty()) {
|
||||
buffer = ByteBuffer::copy(m_buffered_data.data(), m_buffered_data.size());
|
||||
m_buffered_data.clear();
|
||||
}
|
||||
|
||||
while (can_read_from_fd()) {
|
||||
char read_buffer[4096];
|
||||
int nread = ::read(m_fd, read_buffer, sizeof(read_buffer));
|
||||
if (nread < 0) {
|
||||
set_error(nread);
|
||||
return buffer;
|
||||
}
|
||||
if (nread == 0) {
|
||||
set_eof(true);
|
||||
break;
|
||||
}
|
||||
buffer.append(read_buffer, nread);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ByteBuffer GIODevice::read_line(int max_size)
|
||||
{
|
||||
if (m_fd < 0)
|
||||
|
|
|
@ -28,6 +28,7 @@ public:
|
|||
|
||||
ByteBuffer read(int max_size);
|
||||
ByteBuffer read_line(int max_size);
|
||||
ByteBuffer read_all();
|
||||
|
||||
// FIXME: I would like this to be const but currently it needs to call populate_read_buffer().
|
||||
bool can_read_line();
|
||||
|
@ -49,6 +50,7 @@ protected:
|
|||
|
||||
private:
|
||||
bool populate_read_buffer();
|
||||
bool can_read_from_fd() const;
|
||||
|
||||
int m_fd { -1 };
|
||||
int m_error { 0 };
|
||||
|
|
Loading…
Reference in a new issue