Line data Source code
1 : /* File: utf8stream_writer.c; Copyright and License: see below */ 2 : 3 : #include "u8/u8_trace.h" 4 : #include <string.h> 5 : #include <inttypes.h> 6 : #include <assert.h> 7 : 8 191 : static inline void utf8stream_writer_init ( utf8stream_writer_t *this_, universal_output_stream_t* out_stream ) 9 : { 10 191 : assert( out_stream != NULL ); 11 191 : (*this_).output_stream = out_stream; 12 191 : (*this_).buf_fill = 0; 13 191 : } 14 : 15 191 : static inline u8_error_t utf8stream_writer_destroy ( utf8stream_writer_t *this_ ) 16 : { 17 191 : assert( (*this_).output_stream != NULL ); 18 : 19 191 : const u8_error_t err = utf8stream_writer_flush( this_ ); 20 191 : (*this_).output_stream = NULL; 21 : 22 191 : return err; 23 : } 24 : 25 54672 : static inline u8_error_t utf8stream_writer_write_str ( utf8stream_writer_t *this_, const void *utf8_string ) 26 : { 27 54672 : assert( (*this_).output_stream != NULL ); 28 54672 : assert( utf8_string != NULL ); 29 : 30 54672 : utf8stringview_t view = UTF8STRINGVIEW_STR( utf8_string ); 31 54672 : const u8_error_t err = utf8stream_writer_write_view( this_, &view ); 32 : 33 54672 : return err; 34 : } 35 : 36 9846 : static inline u8_error_t utf8stream_writer_write_int ( utf8stream_writer_t *this_, const int64_t number ) 37 : { 38 9846 : assert( (*this_).output_stream != NULL ); 39 : 40 : char number_str[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */ 41 : /* Note: snprintf is not available on every OS */ 42 9846 : sprintf( number_str, "%" PRIi64, number ); 43 : 44 9846 : utf8stringview_t view = UTF8STRINGVIEW_STR( number_str ); 45 9846 : const u8_error_t err = utf8stream_writer_write_view( this_, &view ); 46 : 47 9846 : return err; 48 : } 49 : 50 1 : static inline u8_error_t utf8stream_writer_write_hex ( utf8stream_writer_t *this_, const int64_t number ) 51 : { 52 1 : assert( (*this_).output_stream != NULL ); 53 : 54 : char number_str[17]; /* this is sufficient for 64 bit integers */ 55 : /* Note: snprintf is not available on every OS */ 56 1 : sprintf( number_str, "%" PRIx64, number ); 57 : 58 1 : utf8stringview_t view = UTF8STRINGVIEW_STR( number_str ); 59 1 : const u8_error_t err = utf8stream_writer_write_view( this_, &view ); 60 : 61 1 : return err; 62 : } 63 : 64 3841 : static inline utf8error_t utf8stream_writer_write_char( utf8stream_writer_t *this_, const uint32_t codepoint ) 65 : { 66 3841 : assert( (*this_).output_stream != NULL ); 67 : 68 3841 : const utf8codepoint_t cp = utf8codepoint( codepoint ); 69 3841 : const utf8codepointseq_t mem_buf = utf8codepoint_get_utf8( cp ); 70 3841 : const unsigned int mem_len = utf8codepoint_get_length( cp ); 71 3841 : assert( mem_len <= sizeof(utf8codepointseq_t) ); 72 : 73 3841 : utf8stringview_t view = UTF8STRINGVIEW( (const char*) &mem_buf, mem_len ); 74 3841 : const u8_error_t err = utf8stream_writer_write_view( this_, &view ); 75 : 76 3841 : return err; 77 : } 78 : 79 68413 : static inline u8_error_t utf8stream_writer_write_view ( utf8stream_writer_t *this_, const utf8stringview_t *utf8_view ) 80 : { 81 68413 : assert( (*this_).output_stream != NULL ); 82 68413 : assert( (*this_).buf_fill <= sizeof( (*this_).buffer ) ); 83 : assert( UTF8STREAM_WRITER_MAX_BUF == sizeof( (*this_).buffer ) ); 84 68413 : assert( utf8_view != NULL ); 85 68413 : const char *start = utf8stringview_get_start( utf8_view ); 86 68413 : const size_t length = utf8stringview_get_length( utf8_view ); 87 68413 : u8_error_t err = U8_ERROR_NONE; 88 : 89 : /* is there buffer free? */ 90 68413 : if ( length <= ((size_t)UTF8STREAM_WRITER_MAX_BUF) - (*this_).buf_fill ) /* all possible constants are on the right side for compiler optimizations */ 91 : { 92 : /* store to buffer */ 93 : #if __GNUC__ >= 8 94 : #pragma GCC diagnostic push 95 : #pragma GCC diagnostic ignored "-Warray-bounds" 96 : #endif 97 65588 : memcpy( &((*this_).buffer[(*this_).buf_fill]), start, length ); 98 : #if __GNUC__ >= 8 99 : #pragma GCC diagnostic pop 100 : #endif 101 65588 : (*this_).buf_fill += length; 102 : } 103 : else 104 : { 105 : /* flush the buffer */ 106 2825 : if ( (*this_).buf_fill > 0 ) 107 : { 108 450 : err |= universal_output_stream_write( (*this_).output_stream, &((*this_).buffer), (*this_).buf_fill ); 109 450 : (*this_).buf_fill = 0; 110 : } 111 : 112 : /* is there enough buffer free now? */ 113 2825 : if ( length < UTF8STREAM_WRITER_MAX_BUF ) 114 : { 115 : /* store to buffer */ 116 357 : memcpy( &((*this_).buffer), start, length ); 117 357 : (*this_).buf_fill = length; 118 : } 119 : else 120 : { 121 : /* write immediate */ 122 2468 : err |= universal_output_stream_write( (*this_).output_stream, start, length ); 123 : } 124 : } 125 : 126 68413 : return err; 127 : } 128 : 129 21172 : static inline u8_error_t utf8stream_writer_flush ( utf8stream_writer_t *this_ ) 130 : { 131 21172 : U8_TRACE_BEGIN(); 132 21172 : assert( (*this_).output_stream != NULL ); 133 21172 : assert( (*this_).buf_fill <= sizeof( (*this_).buffer ) ); 134 21172 : u8_error_t err = U8_ERROR_NONE; 135 : 136 21172 : if ( (*this_).buf_fill > 0 ) 137 : { 138 18523 : err |= universal_output_stream_write( (*this_).output_stream, &((*this_).buffer), (*this_).buf_fill ); 139 18523 : (*this_).buf_fill = 0; 140 : } 141 : 142 21172 : err |= universal_output_stream_flush( (*this_).output_stream ); 143 : 144 21172 : U8_TRACE_END_ERR( err ); 145 21172 : return err; 146 : } 147 : 148 : 149 : /* 150 : Copyright 2021-2024 Andreas Warnke 151 : 152 : Licensed under the Apache License, Version 2.0 (the "License"); 153 : you may not use this file except in compliance with the License. 154 : You may obtain a copy of the License at 155 : 156 : http://www.apache.org/licenses/LICENSE-2.0 157 : 158 : Unless required by applicable law or agreed to in writing, software 159 : distributed under the License is distributed on an "AS IS" BASIS, 160 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 161 : See the License for the specific language governing permissions and 162 : limitations under the License. 163 : */