Browse Source

GIODevice: Add a read_all() that returns a ByteBuffer with all we can read.

Use this to implement file opening in TextEditor.
Andreas Kling 6 years ago
parent
commit
9ad076178a
6 changed files with 57 additions and 24 deletions
  1. 1 0
      AK/AKString.h
  2. 9 0
      AK/ByteBuffer.h
  3. 9 0
      AK/String.cpp
  4. 5 22
      Applications/TextEditor/main.cpp
  5. 31 2
      LibGUI/GIODevice.cpp
  6. 2 0
      LibGUI/GIODevice.h

+ 1 - 0
AK/AKString.h

@@ -100,6 +100,7 @@ public:
     }
 
     ByteBuffer to_byte_buffer() const;
+    static String from_byte_buffer(const ByteBuffer&);
 
     static String format(const char*, ...);
 

+ 9 - 0
AK/ByteBuffer.h

@@ -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))

+ 9 - 0
AK/String.cpp

@@ -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;

+ 5 - 22
Applications/TextEditor/main.cpp

@@ -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");
-            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);
-        }
+        GFile file(path);
 
-        int rc = close(fd);
-        if (rc < 0) {
-            perror("close");
+        if (!file.open(GIODevice::ReadOnly)) {
+            fprintf(stderr, "Opening %s: %s\n", path.characters(), file.error_string());
             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&) {

+ 31 - 2
LibGUI/GIODevice.cpp

@@ -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)

+ 2 - 0
LibGUI/GIODevice.h

@@ -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 };