Serenity Operating System
at master 132 lines 3.3 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/StdLibExtras.h> 8#include <Kernel/KBufferBuilder.h> 9 10namespace Kernel { 11 12inline bool KBufferBuilder::check_expand(size_t size) 13{ 14 if (!m_buffer) 15 return false; 16 if ((m_size + size) < m_buffer->capacity()) 17 return true; 18 if (Checked<size_t>::addition_would_overflow(m_size, size)) 19 return false; 20 size_t new_buffer_size = m_size + size; 21 if (Checked<size_t>::addition_would_overflow(new_buffer_size, 1 * MiB)) 22 return false; 23 auto rounded_new_buffer_size_or_error = Memory::page_round_up(new_buffer_size + 1 * MiB); 24 if (rounded_new_buffer_size_or_error.is_error()) { 25 return false; 26 } 27 auto new_buffer_or_error = KBuffer::try_create_with_size("KBufferBuilder"sv, rounded_new_buffer_size_or_error.value()); 28 if (new_buffer_or_error.is_error()) 29 return false; 30 auto new_buffer = new_buffer_or_error.release_value(); 31 memcpy(new_buffer->data(), m_buffer->data(), m_buffer->size()); 32 m_buffer = move(new_buffer); 33 return true; 34} 35 36bool KBufferBuilder::flush() 37{ 38 if (!m_buffer) 39 return false; 40 m_buffer->set_size(m_size); 41 return true; 42} 43 44OwnPtr<KBuffer> KBufferBuilder::build() 45{ 46 if (!flush()) 47 return {}; 48 49 return move(m_buffer); 50} 51 52ErrorOr<KBufferBuilder> KBufferBuilder::try_create() 53{ 54 auto buffer = TRY(KBuffer::try_create_with_size("KBufferBuilder"sv, 4 * MiB, Memory::Region::Access::ReadWrite)); 55 return KBufferBuilder { move(buffer) }; 56} 57 58KBufferBuilder::KBufferBuilder(NonnullOwnPtr<KBuffer> buffer) 59 : m_buffer(move(buffer)) 60{ 61} 62 63ErrorOr<void> KBufferBuilder::append_bytes(ReadonlyBytes bytes) 64{ 65 if (!check_expand(bytes.size())) 66 return ENOMEM; 67 memcpy(insertion_ptr(), bytes.data(), bytes.size()); 68 m_size += bytes.size(); 69 return {}; 70} 71 72ErrorOr<void> KBufferBuilder::append(StringView str) 73{ 74 if (str.is_empty()) 75 return {}; 76 if (!check_expand(str.length())) 77 return ENOMEM; 78 memcpy(insertion_ptr(), str.characters_without_null_termination(), str.length()); 79 m_size += str.length(); 80 return {}; 81} 82 83ErrorOr<void> KBufferBuilder::append(char const* characters, int length) 84{ 85 if (!length) 86 return {}; 87 if (!check_expand(length)) 88 return ENOMEM; 89 memcpy(insertion_ptr(), characters, length); 90 m_size += length; 91 return {}; 92} 93 94ErrorOr<void> KBufferBuilder::append(char ch) 95{ 96 if (!check_expand(1)) 97 return ENOMEM; 98 insertion_ptr()[0] = ch; 99 m_size += 1; 100 return {}; 101} 102 103ErrorOr<void> KBufferBuilder::append_escaped_for_json(StringView string) 104{ 105 for (auto ch : string) { 106 switch (ch) { 107 case '\b': 108 TRY(append("\\b"sv)); 109 break; 110 case '\n': 111 TRY(append("\\n"sv)); 112 break; 113 case '\t': 114 TRY(append("\\t"sv)); 115 break; 116 case '\"': 117 TRY(append("\\\""sv)); 118 break; 119 case '\\': 120 TRY(append("\\\\"sv)); 121 break; 122 default: 123 if (ch >= 0 && ch <= 0x1f) 124 TRY(appendff("\\u{:04x}", ch)); 125 else 126 TRY(append(ch)); 127 } 128 } 129 return {}; 130} 131 132}