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 188 : static inline void utf8stream_writer_init ( utf8stream_writer_t *this_, universal_output_stream_t* out_stream )
9 : {
10 188 : assert( out_stream != NULL );
11 188 : (*this_).output_stream = out_stream;
12 188 : (*this_).buf_fill = 0;
13 188 : }
14 :
15 188 : static inline u8_error_t utf8stream_writer_destroy ( utf8stream_writer_t *this_ )
16 : {
17 188 : assert( (*this_).output_stream != NULL );
18 :
19 188 : const u8_error_t err = utf8stream_writer_flush( this_ );
20 188 : (*this_).output_stream = NULL;
21 :
22 188 : return err;
23 : }
24 :
25 31867 : static inline u8_error_t utf8stream_writer_write_str ( utf8stream_writer_t *this_, const void *utf8_string )
26 : {
27 31867 : assert( (*this_).output_stream != NULL );
28 31867 : assert( utf8_string != NULL );
29 :
30 31867 : utf8stringview_t view = UTF8STRINGVIEW_STR( utf8_string );
31 31867 : const u8_error_t err = utf8stream_writer_write_view( this_, &view );
32 :
33 31867 : return err;
34 : }
35 :
36 6267 : static inline u8_error_t utf8stream_writer_write_int ( utf8stream_writer_t *this_, const int64_t number )
37 : {
38 6267 : 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 6267 : sprintf( number_str, "%" PRIi64, number );
43 :
44 6267 : utf8stringview_t view = UTF8STRINGVIEW_STR( number_str );
45 6267 : const u8_error_t err = utf8stream_writer_write_view( this_, &view );
46 :
47 6267 : 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 42029 : static inline u8_error_t utf8stream_writer_write_view ( utf8stream_writer_t *this_, const utf8stringview_t *utf8_view )
80 : {
81 42029 : assert( (*this_).output_stream != NULL );
82 42029 : assert( (*this_).buf_fill <= sizeof( (*this_).buffer ) );
83 : assert( UTF8STREAM_WRITER_MAX_BUF == sizeof( (*this_).buffer ) );
84 42029 : assert( utf8_view != NULL );
85 42029 : const char *start = utf8stringview_get_start( utf8_view );
86 42029 : const size_t length = utf8stringview_get_length( utf8_view );
87 42029 : u8_error_t err = U8_ERROR_NONE;
88 :
89 : /* is there buffer free? */
90 42029 : 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 40109 : memcpy( &((*this_).buffer[(*this_).buf_fill]), start, length );
98 : #if __GNUC__ >= 8
99 : #pragma GCC diagnostic pop
100 : #endif
101 40109 : (*this_).buf_fill += length;
102 : }
103 : else
104 : {
105 : /* flush the buffer */
106 1920 : if ( (*this_).buf_fill > 0 )
107 : {
108 452 : err |= universal_output_stream_write( (*this_).output_stream, &((*this_).buffer), (*this_).buf_fill );
109 452 : (*this_).buf_fill = 0;
110 : }
111 :
112 : /* is there enough buffer free now? */
113 1920 : if ( length < UTF8STREAM_WRITER_MAX_BUF )
114 : {
115 : /* store to buffer */
116 358 : memcpy( &((*this_).buffer), start, length );
117 358 : (*this_).buf_fill = length;
118 : }
119 : else
120 : {
121 : /* write immediate */
122 1562 : err |= universal_output_stream_write( (*this_).output_stream, start, length );
123 : }
124 : }
125 :
126 42029 : return err;
127 : }
128 :
129 12871 : static inline u8_error_t utf8stream_writer_flush ( utf8stream_writer_t *this_ )
130 : {
131 12871 : U8_TRACE_BEGIN();
132 12871 : assert( (*this_).output_stream != NULL );
133 12871 : assert( (*this_).buf_fill <= sizeof( (*this_).buffer ) );
134 12871 : u8_error_t err = U8_ERROR_NONE;
135 :
136 12871 : if ( (*this_).buf_fill > 0 )
137 : {
138 11150 : err |= universal_output_stream_write( (*this_).output_stream, &((*this_).buffer), (*this_).buf_fill );
139 11150 : (*this_).buf_fill = 0;
140 : }
141 :
142 12871 : err |= universal_output_stream_flush( (*this_).output_stream );
143 :
144 12871 : U8_TRACE_END_ERR( err );
145 12871 : return err;
146 : }
147 :
148 :
149 : /*
150 : Copyright 2021-2025 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 : */
|