Line data Source code
1 : /* File: universal_memory_output_stream.c; Copyright and License: see below */ 2 : 3 : #include "u8stream/universal_memory_output_stream.h" 4 : #include "u8stream/universal_output_stream_if.h" 5 : #include "utf8stringbuf/utf8stringview.h" 6 : #include "u8/u8_trace.h" 7 : #include "u8/u8_log.h" 8 : #include <string.h> 9 : #include <assert.h> 10 : 11 : /* the vmt implementing the interface */ 12 : static const universal_output_stream_if_t universal_memory_output_stream_private_if 13 : = { 14 : .write = (u8_error_t (*)(universal_output_stream_impl_t*, const void*, size_t)) &universal_memory_output_stream_write, 15 : .flush = (u8_error_t (*)(universal_output_stream_impl_t*)) &universal_memory_output_stream_flush 16 : }; 17 : 18 1452 : void universal_memory_output_stream_init ( universal_memory_output_stream_t *this_, 19 : void* mem_buf_start, 20 : size_t mem_buf_size, 21 : universal_memory_output_stream_0term_t mode ) 22 : { 23 1452 : U8_TRACE_BEGIN(); 24 1452 : assert( mem_buf_start != NULL ); 25 : 26 1452 : (*this_).mem_buf_start = mem_buf_start; 27 1452 : (*this_).mem_buf_size = mem_buf_size; 28 1452 : (*this_).mem_buf_filled = 0; 29 1452 : (*this_).mode = mode; 30 1452 : universal_output_stream_private_init( &((*this_).output_stream), &universal_memory_output_stream_private_if, this_ ); 31 : 32 1452 : U8_TRACE_END(); 33 1452 : } 34 : 35 1449 : u8_error_t universal_memory_output_stream_destroy( universal_memory_output_stream_t *this_ ) 36 : { 37 1449 : U8_TRACE_BEGIN(); 38 : 39 1449 : const u8_error_t err = universal_memory_output_stream_flush( this_ ); 40 : 41 1449 : (*this_).mem_buf_start = NULL; 42 1449 : (*this_).mem_buf_size = 0; 43 1449 : (*this_).mem_buf_filled = 0; 44 1449 : universal_output_stream_private_destroy( &((*this_).output_stream) ); 45 : 46 1449 : U8_TRACE_END_ERR(err); 47 1449 : return err; 48 : } 49 : 50 825 : u8_error_t universal_memory_output_stream_reset ( universal_memory_output_stream_t *this_ ) 51 : { 52 825 : U8_TRACE_BEGIN(); 53 825 : assert( (*this_).mem_buf_start != NULL ); 54 825 : const u8_error_t err = U8_ERROR_NONE; 55 : 56 825 : (*this_).mem_buf_filled = 0; 57 : 58 825 : U8_TRACE_END_ERR(err); 59 825 : return err; 60 : } 61 : 62 5848 : u8_error_t universal_memory_output_stream_write ( universal_memory_output_stream_t *this_, const void *start, size_t length ) 63 : { 64 : /*U8_TRACE_BEGIN();*/ 65 5848 : assert( start != NULL ); 66 5848 : assert( (*this_).mem_buf_start != NULL ); 67 5848 : u8_error_t err = U8_ERROR_NONE; 68 : 69 5848 : const size_t space_left = ( (*this_).mem_buf_size - (*this_).mem_buf_filled ); 70 5848 : char *const buf_first_free = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_filled] ); 71 5848 : if ( length <= space_left ) 72 : { 73 5803 : memcpy( buf_first_free, start, length ); 74 5803 : (*this_).mem_buf_filled += length; 75 : } 76 : else 77 : { 78 45 : U8_TRACE_BEGIN(); 79 45 : memcpy( buf_first_free, start, space_left ); 80 45 : (*this_).mem_buf_filled += space_left; 81 45 : U8_TRACE_INFO_INT( "not all bytes could be written. missing:", length-space_left ); 82 45 : err = U8_ERROR_AT_FILE_WRITE; 83 45 : U8_TRACE_END_ERR(err); 84 : } 85 : 86 : /*U8_TRACE_END_ERR(err);*/ 87 5848 : return err; 88 : } 89 : 90 7447 : u8_error_t universal_memory_output_stream_flush( universal_memory_output_stream_t *this_ ) 91 : { 92 7447 : U8_TRACE_BEGIN(); 93 7447 : assert( (*this_).mem_buf_start != NULL ); 94 7447 : u8_error_t err = U8_ERROR_NONE; 95 : 96 7447 : switch( (*this_).mode ) 97 : { 98 2 : case UNIVERSAL_MEMORY_OUTPUT_STREAM_0TERM_BYTE: 99 : { 100 2 : err = universal_memory_output_stream_private_write_0term( this_, false ); 101 : } 102 2 : break; 103 : 104 7444 : case UNIVERSAL_MEMORY_OUTPUT_STREAM_0TERM_UTF8: 105 : { 106 7444 : err = universal_memory_output_stream_private_write_0term( this_, true ); 107 : } 108 7444 : break; 109 : 110 1 : default: 111 : case UNIVERSAL_MEMORY_OUTPUT_STREAM_0TERM_NONE: 112 : { 113 : /* no 0term to be appended */ 114 : } 115 1 : break; 116 : } 117 : 118 7447 : U8_TRACE_END_ERR(err); 119 7447 : return err; 120 : } 121 : 122 7446 : u8_error_t universal_memory_output_stream_private_write_0term ( universal_memory_output_stream_t *this_, bool utf8_mode ) 123 : { 124 7446 : U8_TRACE_BEGIN(); 125 7446 : assert( (*this_).mem_buf_start != NULL ); 126 7446 : u8_error_t err = U8_ERROR_NONE; 127 : 128 7446 : if ( (*this_).mem_buf_size == 0 ) 129 : { 130 1 : U8_LOG_ERROR( "buffer size is 0; buffer is not terminated by zero." ); 131 1 : err = U8_ERROR_CONFIG_OUT_OF_RANGE; 132 : } 133 7445 : else if ( (*this_).mem_buf_filled < (*this_).mem_buf_size ) 134 : { 135 : /* add a terminating zero at position (*this_).mem_buf_filled, */ 136 : /* but do not increase the mem_buf_filled because more bytes may be written ... */ 137 7361 : char *const term_char = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_filled] ); 138 7361 : *term_char = '\0'; 139 : } 140 : else 141 : { 142 84 : if ( utf8_mode ) 143 : { 144 : /* use a utf8stringview_t to determine the end-position of the last full unicode codepoint: */ 145 : utf8stringview_t view_on_buf; 146 83 : const utf8error_t cut = utf8stringview_init( &view_on_buf, (*this_).mem_buf_start, (*this_).mem_buf_size-1 ); 147 83 : char *const last_char 148 83 : = &( (*( (char(*)[])utf8stringview_get_start(&view_on_buf) ))[utf8stringview_get_length(&view_on_buf)] ); 149 83 : *last_char = '\0'; 150 83 : utf8stringview_destroy( &view_on_buf ); 151 83 : if ( cut == UTF8ERROR_SUCCESS ) 152 : { 153 81 : U8_TRACE_INFO( "last byte overwritten by terminating zero" ); 154 : } 155 : else 156 : { 157 2 : U8_TRACE_INFO( "multiple last bytes dropped by terminating zero" ); 158 : } 159 : } 160 : else 161 : { 162 1 : char *const last_char = &( (*( (char(*)[])(*this_).mem_buf_start ))[(*this_).mem_buf_size - 1] ); 163 1 : *last_char = '\0'; 164 1 : U8_TRACE_INFO( "last byte overwritten by terminating zero" ); 165 : } 166 84 : err = U8_ERROR_AT_FILE_WRITE; 167 : } 168 : 169 : 170 7446 : U8_TRACE_END_ERR(err); 171 7446 : return err; 172 : } 173 : 174 1448 : universal_output_stream_t* universal_memory_output_stream_get_output_stream( universal_memory_output_stream_t *this_ ) 175 : { 176 1448 : U8_TRACE_BEGIN(); 177 : 178 1448 : universal_output_stream_t* result = &((*this_).output_stream); 179 : 180 1448 : U8_TRACE_END(); 181 1448 : return result; 182 : } 183 : 184 : 185 : /* 186 : Copyright 2020-2024 Andreas Warnke 187 : 188 : Licensed under the Apache License, Version 2.0 (the "License"); 189 : you may not use this file except in compliance with the License. 190 : You may obtain a copy of the License at 191 : 192 : http://www.apache.org/licenses/LICENSE-2.0 193 : 194 : Unless required by applicable law or agreed to in writing, software 195 : distributed under the License is distributed on an "AS IS" BASIS, 196 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 197 : See the License for the specific language governing permissions and 198 : limitations under the License. 199 : */