16 /* Concatenate two strings into newly allocated buffer.
17 * You must free() them, when you don't need it anymore.
18 * Any of the arguments can be NULL meaning empty string.
19 * In case of error returns NULL.
20 * Empty string is always returned as allocated empty string. */
21 _hidden
char *_isds_astrcat(const char *first
, const char *second
) {
22 size_t first_len
, second_len
;
25 first_len
= (first
) ? strlen(first
) : 0;
26 second_len
= (second
) ? strlen(second
) : 0;
27 buf
= malloc(1 + first_len
+ second_len
);
30 if (first
) strcpy(buf
, first
);
31 if (second
) strcpy(buf
+ first_len
, second
);
37 /* Concatenate three strings into newly allocated buffer.
38 * You must free() them, when you don't need it anymore.
39 * Any of the arguments can be NULL meaning empty string.
40 * In case of error returns NULL.
41 * Empty string is always returned as allocated empty string. */
42 _hidden
char *_isds_astrcat3(const char *first
, const char *second
,
44 size_t first_len
, second_len
, third_len
;
47 first_len
= (first
) ? strlen(first
) : 0;
48 second_len
= (second
) ? strlen(second
) : 0;
49 third_len
= (third
) ? strlen(third
) : 0;
50 buf
= malloc(1 + first_len
+ second_len
+ third_len
);
70 /* Print formatted string into automatically reallocated @buffer.
71 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
73 * @format format string as for printf(3)
74 * @ap list of variadic arguments, after call will be in undefined state
75 * @Returns number of bytes printed. In case of error, -1 and NULL @buffer*/
76 _hidden
int isds_vasprintf(char **buffer
, const char *format
, va_list ap
) {
78 int length
, new_length
;
81 if (!buffer
|| !format
) {
90 length
= vsnprintf(NULL
, 0, format
, aq
) + 1;
98 new_buffer
= realloc(*buffer
, length
);
104 *buffer
= new_buffer
;
106 new_length
= vsnprintf(*buffer
, length
, format
, ap
);
107 if (new_length
>= length
) {
117 /* Print formatted string into automatically reallocated @buffer.
118 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
120 * @format format string as for printf(3)
121 * @... variadic arguments
122 * @Returns number of bytes printed. In case of error, -1 and NULL @buffer */
123 _hidden
int isds_asprintf(char **buffer
, const char *format
, ...) {
126 va_start(ap
, format
);
127 ret
= isds_vasprintf(buffer
, format
, ap
);
132 /* Converts a block from charset to charset.
133 * @from is input charset of @input block as known to iconv
134 * @to is output charset @input will be converted to @output
135 * @input is block in @from charset/encoding of length @input_length
136 * @input_length is size of @input block in bytes
137 * @output is automatically allocated block of data converted from @input. No
138 * NUL is apended. Can be NULL, if resulting size is 0. You must free it.
139 * @return size of @output in bytes. In case of error returns (size_t) -1 and
140 * deallocates @output if this function allocated it in this call. */
141 _hidden
size_t _isds_any2any(const char *from
, const char *to
,
142 const void *input
, size_t input_length
, void **output
) {
144 char *buffer
= NULL
, *new_buffer
;
145 size_t buffer_length
= 0, buffer_used
= 0;
146 char *inbuf
, *outbuf
;
147 size_t inleft
, outleft
;
149 if (output
!= NULL
) *output
= NULL
;
150 if (from
== NULL
|| to
== NULL
|| input
== NULL
|| output
== NULL
)
153 state
= iconv_open(to
, from
);
154 if (state
== (iconv_t
) -1) return (size_t) -1;
156 /* Get the initial output buffer length */
157 buffer_length
= input_length
;
159 inbuf
= (char *) input
;
160 inleft
= input_length
;
164 new_buffer
= realloc(buffer
, buffer_length
);
167 buffer_used
= (size_t) -1;
173 outbuf
= buffer
+ buffer_used
;
174 outleft
= buffer_length
- buffer_used
;
176 /* Convert chunk of data */
177 if ((size_t) -1 == iconv(state
, &inbuf
, &inleft
, &outbuf
, &outleft
) &&
180 buffer_used
= (size_t) -1;
184 /* Update positions */
185 buffer_length
+= 1024;
186 buffer_used
= outbuf
- buffer
;
191 if (buffer_used
== 0) zfree(buffer
);
196 /* Converts UTF8 string into locale encoded string.
197 * @utf string int UTF-8 terminated by zero byte
198 * @return allocated string encoded in locale specific encoding. You must free
199 * it. In case of error or NULL @utf returns NULL. */
200 _hidden
char *_isds_utf82locale(const char *utf
) {
201 char *output
, *bigger_output
;
204 if (utf
== NULL
) return NULL
;
206 length
= _isds_any2any("UTF-8", nl_langinfo(CODESET
), utf
, strlen(utf
),
208 if (length
== (size_t) -1) return NULL
;
210 bigger_output
= realloc(output
, length
+ 1);
211 if (bigger_output
== NULL
) {
214 output
= bigger_output
;
215 output
[length
] = '\0';
222 /* Encode given data into MIME Base64 encoded zero terminated string.
223 * @plain are input data (binary stream)
224 * @length is length of @plain data in bytes
225 * @return allocated string of base64 encoded plain data or NULL in case of
226 * error. You must free it. */
227 _hidden
char *_isds_b64encode(const void *plain
, const size_t length
) {
229 base64_encodestate state
;
231 char *buffer
, *new_buffer
;
234 if (length
) return NULL
;
235 /* Empty input is valid input */
239 _isds_base64_init_encodestate(&state
);
242 * (4 is padding, 1 is final new line, and 1 is string terminator) */
243 buffer
= malloc(length
* 2 + 4 + 1 + 1);
244 if (!buffer
) return NULL
;
246 /* Encode plain data */
247 code_length
= _isds_base64_encode_block(plain
, length
, (int8_t *)buffer
,
249 code_length
+= _isds_base64_encode_blockend(((int8_t*)buffer
) + code_length
,
252 /* Terminate string */
253 buffer
[code_length
++] = '\0';
255 /* Shrink the buffer */
256 new_buffer
= realloc(buffer
, code_length
);
257 if (new_buffer
) buffer
= new_buffer
;
263 /* Decode given data from MIME Base64 encoded zero terminated string to binary
264 * stream. Invalid Base64 symbols are skipped.
265 * @encoded are input data (Base64 zero terminated string)
266 * @plain are automatically reallocated output data (binary stream). You must
267 * free it. Will be freed in case of error.
268 * @return length of @plain data in bytes or (size_t) -1 in case of memory
269 * allocation failure. */
270 _hidden
size_t _isds_b64decode(const char *encoded
, void **plain
) {
272 base64_decodestate state
;
273 size_t encoded_length
;
277 if (NULL
== encoded
|| NULL
== plain
) {
278 if (NULL
!= plain
) zfree(*plain
);
279 return ((size_t) -1);
282 encoded_length
= strlen(encoded
);
283 _isds_base64_init_decodestate(&state
);
285 /* Divert empty input */
286 if (encoded_length
== 0) {
291 /* Allocate buffer */
292 buffer
= realloc(*plain
, encoded_length
);
293 if (NULL
== buffer
) {
295 return ((size_t) -1);
299 /* Decode encoded data */
300 plain_length
= _isds_base64_decode_block((const int8_t *)encoded
,
301 encoded_length
, *plain
, &state
);
302 if (plain_length
>= (size_t) -1) {
307 /* Shrink the buffer */
308 if (0 == plain_length
) {
311 buffer
= realloc(*plain
, plain_length
);
312 /* realloc() can move pointer even when shrinking */
313 if (NULL
!= buffer
) *plain
= buffer
;
320 /* Convert hexadecimal digit to integer. Return negative value if character is
321 * not valid hexadecimal digit. */
322 _hidden
int _isds_hex2i(char digit
) {
323 if (digit
>= '0' && digit
<= '9')
325 if (digit
>= 'a' && digit
<= 'f')
326 return digit
- 'a' + 10;
327 if (digit
>= 'A' && digit
<= 'F')
328 return digit
- 'A' + 10;