|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef LIB_SYSLOG_CPP_HOST_ENCODER_H_ | 
|  | #define LIB_SYSLOG_CPP_HOST_ENCODER_H_ | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <lib/syslog/cpp/log_level.h> | 
|  | #include <lib/syslog/cpp/macros.h> | 
|  |  | 
|  | #include <cstring> | 
|  |  | 
|  | // This file contains shared implementations for writing string logs between the legacy backend and | 
|  | // the host backend | 
|  |  | 
|  | namespace fuchsia_logging::internal { | 
|  | struct MsgHeader { | 
|  | fuchsia_logging::RawLogSeverity severity; | 
|  | char* offset; | 
|  | LogBuffer* buffer; | 
|  | bool first_tag; | 
|  | char* user_tag; | 
|  | bool has_msg; | 
|  | bool first_kv; | 
|  | bool terminated; | 
|  | size_t RemainingSpace() { | 
|  | auto end = (reinterpret_cast<const char*>(this) + sizeof(LogBuffer)); | 
|  | auto avail = static_cast<size_t>(end - offset - | 
|  | 2);  // Allocate an extra byte for a NULL terminator at the end | 
|  | return avail; | 
|  | } | 
|  |  | 
|  | void NullTerminate() { | 
|  | if (!terminated) { | 
|  | terminated = true; | 
|  | *(offset++) = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | const char* c_str() { | 
|  | NullTerminate(); | 
|  | return reinterpret_cast<const char*>(buffer->data()); | 
|  | } | 
|  |  | 
|  | void WriteChar(const char value) { | 
|  | if (!RemainingSpace()) { | 
|  | [[maybe_unused]] zx::result<> result = FlushToGlobalLogger(*buffer); | 
|  | offset = reinterpret_cast<char*>(buffer->data()); | 
|  | WriteString("CONTINUATION: "); | 
|  | } | 
|  | assert((offset + 1) < (reinterpret_cast<const char*>(this) + sizeof(LogBuffer))); | 
|  | *offset = value; | 
|  | offset++; | 
|  | } | 
|  |  | 
|  | void WriteString(std::string_view value) { | 
|  | size_t total_chars = value.size(); | 
|  | size_t written_chars = 0; | 
|  | while (written_chars < total_chars) { | 
|  | size_t written = WriteStringInternal( | 
|  | std::string_view(value.data() + written_chars, value.size() - written_chars)); | 
|  | written_chars += written; | 
|  | if (written_chars < total_chars) { | 
|  | FlushAndReset(); | 
|  | WriteStringInternal("CONTINUATION: "); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void FlushAndReset() { | 
|  | [[maybe_unused]] zx::result<> result = FlushToGlobalLogger(*buffer); | 
|  | offset = reinterpret_cast<char*>(buffer->data()); | 
|  | } | 
|  |  | 
|  | // Writes a string to the buffer and returns the | 
|  | // number of bytes written. Returns 0 only if | 
|  | // the length of the string is 0, or if we're | 
|  | // exactly at the end of the buffer and need a reset. | 
|  | size_t WriteStringInternal(std::string_view value) { | 
|  | size_t len = value.size(); | 
|  | auto remaining = RemainingSpace(); | 
|  | if (len > remaining) { | 
|  | len = remaining; | 
|  | } | 
|  | assert((offset + len) < (reinterpret_cast<const char*>(this) + sizeof(LogBuffer))); | 
|  | memcpy(offset, value.data(), len); | 
|  | offset += len; | 
|  | return len; | 
|  | } | 
|  |  | 
|  | void Init(LogBuffer* log_buffer, fuchsia_logging::RawLogSeverity log_severity) { | 
|  | this->severity = log_severity; | 
|  | user_tag = nullptr; | 
|  | offset = reinterpret_cast<char*>(log_buffer->data()); | 
|  | first_tag = true; | 
|  | has_msg = false; | 
|  | first_kv = true; | 
|  | terminated = false; | 
|  | } | 
|  |  | 
|  | static MsgHeader* CreatePtr(LogBuffer* log_buffer) { | 
|  | return reinterpret_cast<MsgHeader*>(log_buffer->record_state()); | 
|  | } | 
|  | }; | 
|  |  | 
|  | #ifndef __Fuchsia__ | 
|  | const std::string GetNameForLogSeverity(fuchsia_logging::RawLogSeverity severity); | 
|  | #endif | 
|  |  | 
|  | static_assert(sizeof(MsgHeader) <= LogBuffer::record_state_size(), | 
|  | "message header must be no larger than record_state"); | 
|  | }  // namespace fuchsia_logging::internal | 
|  |  | 
|  | #endif  // LIB_SYSLOG_CPP_HOST_ENCODER_H_ |