17 /* Concatenate two strings into newly allocated buffer.
18 * You must free() them, when you don't need it anymore.
19 * Any of the arguments can be NULL meaning empty string.
20 * In case of error returns NULL.
21 * Empty string is always returned as allocated empty string. */
22 _hidden
char *_isds_astrcat(const char *first
, const char *second
) {
23 size_t first_len
, second_len
;
26 first_len
= (first
) ? strlen(first
) : 0;
27 second_len
= (second
) ? strlen(second
) : 0;
28 buf
= malloc(1 + first_len
+ second_len
);
31 if (first
) strcpy(buf
, first
);
32 if (second
) strcpy(buf
+ first_len
, second
);
38 /* Concatenate three strings into newly allocated buffer.
39 * You must free() them, when you don't need it anymore.
40 * Any of the arguments can be NULL meaning empty string.
41 * In case of error returns NULL.
42 * Empty string is always returned as allocated empty string. */
43 _hidden
char *_isds_astrcat3(const char *first
, const char *second
,
45 size_t first_len
, second_len
, third_len
;
48 first_len
= (first
) ? strlen(first
) : 0;
49 second_len
= (second
) ? strlen(second
) : 0;
50 third_len
= (third
) ? strlen(third
) : 0;
51 buf
= malloc(1 + first_len
+ second_len
+ third_len
);
71 /* Print formatted string into automatically reallocated @buffer.
72 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
74 * @format format string as for printf(3)
75 * @ap list of variadic arguments, after call will be in undefined state
76 * @Returns number of bytes printed. In case of error, -1 and NULL @buffer*/
77 _hidden
int isds_vasprintf(char **buffer
, const char *format
, va_list ap
) {
79 int length
, new_length
;
82 if (!buffer
|| !format
) {
91 length
= vsnprintf(NULL
, 0, format
, aq
) + 1;
99 new_buffer
= realloc(*buffer
, length
);
105 *buffer
= new_buffer
;
107 new_length
= vsnprintf(*buffer
, length
, format
, ap
);
108 if (new_length
>= length
) {
118 /* Print formatted string into automatically reallocated @buffer.
119 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
121 * @format format string as for printf(3)
122 * @... variadic arguments
123 * @Returns number of bytes printed. In case of error, -1 and NULL @buffer */
124 _hidden
int isds_asprintf(char **buffer
, const char *format
, ...) {
127 va_start(ap
, format
);
128 ret
= isds_vasprintf(buffer
, format
, ap
);
133 /* Converts a block from charset to charset.
134 * @from is input charset of @input block as known to iconv
135 * @to is output charset @input will be converted to @output
136 * @input is block in @from charset/encoding of length @input_length
137 * @input_length is size of @input block in bytes
138 * @output is automatically allocated block of data converted from @input. No
139 * NUL is apended. Can be NULL, if resulting size is 0. You must free it.
140 * @return size of @output in bytes. In case of error returns (size_t) -1 and
141 * deallocates @output if this function allocated it in this call. */
142 _hidden
size_t _isds_any2any(const char *from
, const char *to
,
143 const void *input
, size_t input_length
, void **output
) {
145 char *buffer
= NULL
, *new_buffer
;
146 size_t buffer_length
= 0, buffer_used
= 0;
147 char *inbuf
, *outbuf
;
148 size_t inleft
, outleft
;
150 if (output
!= NULL
) *output
= NULL
;
151 if (from
== NULL
|| to
== NULL
|| input
== NULL
|| output
== NULL
)
154 state
= iconv_open(to
, from
);
155 if (state
== (iconv_t
) -1) return (size_t) -1;
157 /* Get the initial output buffer length */
158 buffer_length
= input_length
;
160 inbuf
= (char *) input
;
161 inleft
= input_length
;
165 new_buffer
= realloc(buffer
, buffer_length
);
168 buffer_used
= (size_t) -1;
174 outbuf
= buffer
+ buffer_used
;
175 outleft
= buffer_length
- buffer_used
;
177 /* Convert chunk of data */
178 if ((size_t) -1 == iconv(state
, &inbuf
, &inleft
, &outbuf
, &outleft
) &&
181 buffer_used
= (size_t) -1;
185 /* Update positions */
186 buffer_length
+= 1024;
187 buffer_used
= outbuf
- buffer
;
192 if (buffer_used
== 0) zfree(buffer
);
197 /* Converts UTF8 string into locale encoded string.
198 * @utf string int UTF-8 terminated by zero byte
199 * @return allocated string encoded in locale specific encoding. You must free
200 * it. In case of error or NULL @utf returns NULL. */
201 _hidden
char *_isds_utf82locale(const char *utf
) {
202 char *output
, *bigger_output
;
205 if (utf
== NULL
) return NULL
;
207 length
= _isds_any2any("UTF-8", nl_langinfo(CODESET
), utf
, strlen(utf
),
209 if (length
== (size_t) -1) return NULL
;
211 bigger_output
= realloc(output
, length
+ 1);
212 if (bigger_output
== NULL
) {
215 output
= bigger_output
;
216 output
[length
] = '\0';
223 /* Encode given data into MIME Base64 encoded zero terminated string.
224 * @plain are input data (binary stream)
225 * @length is length of @plain data in bytes
226 * @return allocated string of base64 encoded plain data or NULL in case of
227 * error. You must free it. */
228 _hidden
char *_isds_b64encode(const void *plain
, const size_t length
) {
230 base64_encodestate state
;
232 char *buffer
, *new_buffer
;
235 if (length
) return NULL
;
236 /* Empty input is valid input */
240 _isds_base64_init_encodestate(&state
);
243 * (4 is padding, 1 is final new line, and 1 is string terminator) */
244 buffer
= malloc(length
* 2 + 4 + 1 + 1);
245 if (!buffer
) return NULL
;
247 /* Encode plain data */
248 code_length
= _isds_base64_encode_block(plain
, length
, (int8_t *)buffer
,
250 code_length
+= _isds_base64_encode_blockend(((int8_t*)buffer
) + code_length
,
253 /* Terminate string */
254 buffer
[code_length
++] = '\0';
256 /* Shrink the buffer */
257 new_buffer
= realloc(buffer
, code_length
);
258 if (new_buffer
) buffer
= new_buffer
;
264 /* Decode given data from MIME Base64 encoded zero terminated string to binary
265 * stream. Invalid Base64 symbols are skipped.
266 * @encoded are input data (Base64 zero terminated string)
267 * @plain are automatically reallocated output data (binary stream). You must
268 * free it. Will be freed in case of error.
269 * @return length of @plain data in bytes or (size_t) -1 in case of memory
270 * allocation failure. */
271 _hidden
size_t _isds_b64decode(const char *encoded
, void **plain
) {
273 base64_decodestate state
;
274 size_t encoded_length
;
278 if (NULL
== encoded
|| NULL
== plain
) {
279 if (NULL
!= plain
) zfree(*plain
);
280 return ((size_t) -1);
283 encoded_length
= strlen(encoded
);
284 _isds_base64_init_decodestate(&state
);
286 /* Divert empty input */
287 if (encoded_length
== 0) {
292 /* Allocate buffer */
293 buffer
= realloc(*plain
, encoded_length
);
294 if (NULL
== buffer
) {
296 return ((size_t) -1);
300 /* Decode encoded data */
301 plain_length
= _isds_base64_decode_block((const int8_t *)encoded
,
302 encoded_length
, *plain
, &state
);
303 if (plain_length
>= (size_t) -1) {
308 /* Shrink the buffer */
309 if (0 == plain_length
) {
312 buffer
= realloc(*plain
, plain_length
);
313 /* realloc() can move pointer even when shrinking */
314 if (NULL
!= buffer
) *plain
= buffer
;
321 /* Convert hexadecimal digit to integer. Return negative value if character is
322 * not valid hexadecimal digit. */
323 _hidden
int _isds_hex2i(char digit
) {
324 if (digit
>= '0' && digit
<= '9')
326 if (digit
>= 'a' && digit
<= 'f')
327 return digit
- 'a' + 10;
328 if (digit
>= 'A' && digit
<= 'F')
329 return digit
- 'A' + 10;
334 /* Convert size_t to int. */
335 _hidden
int _isds_sizet2int(size_t val
) {
336 return (val
<= INT_MAX
) ? (int) val
: -1;