13 char *tz_orig
; /* Copy of original TZ variable */
15 /* Concatenate two strings into newly allocated buffer.
16 * You must free() them, when you don't need it anymore.
17 * Any of the arguments can be NULL meaning empty string.
18 * In case of error returns NULL.
19 * Empty string is always returned as allocated empty string. */
20 _hidden
char *_isds_astrcat(const char *first
, const char *second
) {
21 size_t first_len
, second_len
;
24 first_len
= (first
) ? strlen(first
) : 0;
25 second_len
= (second
) ? strlen(second
) : 0;
26 buf
= malloc(1 + first_len
+ second_len
);
29 if (first
) strcpy(buf
, first
);
30 if (second
) strcpy(buf
+ first_len
, second
);
36 /* Concatenate three strings into newly allocated buffer.
37 * You must free() them, when you don't need it anymore.
38 * Any of the arguments can be NULL meaning empty string.
39 * In case of error returns NULL.
40 * Empty string is always returned as allocated empty string. */
41 _hidden
char *_isds_astrcat3(const char *first
, const char *second
,
43 size_t first_len
, second_len
, third_len
;
46 first_len
= (first
) ? strlen(first
) : 0;
47 second_len
= (second
) ? strlen(second
) : 0;
48 third_len
= (third
) ? strlen(third
) : 0;
49 buf
= malloc(1 + first_len
+ second_len
+ third_len
);
69 /* Print formatted string into automatically reallocated @buffer.
70 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
72 * @format format string as for printf(3)
73 * @ap list of variadic arguments, after call will be in undefined state
74 * @Returns number of bytes printed. In case of error, -1 and NULL @buffer*/
75 _hidden
int isds_vasprintf(char **buffer
, const char *format
, va_list ap
) {
77 int length
, new_length
;
80 if (!buffer
|| !format
) {
89 length
= vsnprintf(NULL
, 0, format
, aq
) + 1;
97 new_buffer
= realloc(*buffer
, length
);
103 *buffer
= new_buffer
;
105 new_length
= vsnprintf(*buffer
, length
, format
, ap
);
106 if (new_length
>= length
) {
116 /* Print formatted string into automatically reallocated @buffer.
117 * @buffer automatically reallocated buffer. Must be &NULL or preallocated
119 * @format format string as for printf(3)
120 * @... variadic arguments
121 * @Returns number of bytes printed. In case of error, -1 and NULL @buffer */
122 _hidden
int isds_asprintf(char **buffer
, const char *format
, ...) {
125 va_start(ap
, format
);
126 ret
= isds_vasprintf(buffer
, format
, ap
);
131 /* Converts a block from charset to charset.
132 * @from is input charset of @input block as known to iconv
133 * @to is output charset @input will be converted to @output
134 * @input is block in @from charset/encoding of length @input_length
135 * @input_length is size of @input block in bytes
136 * @output is automatically allocated block of data converted from @input. No
137 * NUL is apended. Can be NULL, if resulting size is 0. You must free it.
138 * @return size of @output in bytes. In case of error returns (size_t) -1 and
139 * deallocates @output if this function allocated it in this call. */
140 _hidden
size_t _isds_any2any(const char *from
, const char *to
,
141 const void *input
, size_t input_length
, void **output
) {
143 char *buffer
= NULL
, *new_buffer
;
144 size_t buffer_length
= 0, buffer_used
= 0;
145 char *inbuf
, *outbuf
;
146 size_t inleft
, outleft
;
148 if (output
!= NULL
) *output
= NULL
;
149 if (from
== NULL
|| to
== NULL
|| input
== NULL
|| output
== NULL
)
152 state
= iconv_open(to
, from
);
153 if (state
== (iconv_t
) -1) return (size_t) -1;
155 /* Get the initial output buffer length */
156 buffer_length
= input_length
;
158 inbuf
= (char *) input
;
159 inleft
= input_length
;
163 new_buffer
= realloc(buffer
, buffer_length
);
166 buffer_used
= (size_t) -1;
172 outbuf
= buffer
+ buffer_used
;
173 outleft
= buffer_length
- buffer_used
;
175 /* Convert chunk of data */
176 if ((size_t) -1 == iconv(state
, &inbuf
, &inleft
, &outbuf
, &outleft
) &&
179 buffer_used
= (size_t) -1;
183 /* Update positions */
184 buffer_length
+= 1024;
185 buffer_used
= outbuf
- buffer
;
190 if (buffer_used
== 0) zfree(buffer
);
195 /* Converts UTF8 string into locale encoded string.
196 * @utf string int UTF-8 terminated by zero byte
197 * @return allocated string encoded in locale specific encoding. You must free
198 * it. In case of error or NULL @utf returns NULL. */
199 _hidden
char *_isds_utf82locale(const char *utf
) {
200 char *output
, *bigger_output
;
203 if (utf
== NULL
) return NULL
;
205 length
= _isds_any2any("UTF-8", nl_langinfo(CODESET
), utf
, strlen(utf
),
207 if (length
== (size_t) -1) return NULL
;
209 bigger_output
= realloc(output
, length
+ 1);
210 if (bigger_output
== NULL
) {
213 output
= bigger_output
;
214 output
[length
] = '\0';
221 /* Encode given data into MIME Base64 encoded zero terminated string.
222 * @plain are input data (binary stream)
223 * @length is length of @plain data in bytes
224 * @return allocated string of base64 encoded plain data or NULL in case of
225 * error. You must free it. */
226 _hidden
char *_isds_b64encode(const void *plain
, const size_t length
) {
228 base64_encodestate state
;
230 char *buffer
, *new_buffer
;
233 if (length
) return NULL
;
234 /* Empty input is valid input */
238 _isds_base64_init_encodestate(&state
);
241 * (4 is padding, 1 is final new line, and 1 is string terminator) */
242 buffer
= malloc(length
* 2 + 4 + 1 + 1);
243 if (!buffer
) return NULL
;
245 /* Encode plain data */
246 code_length
= _isds_base64_encode_block(plain
, length
, (int8_t *)buffer
,
248 code_length
+= _isds_base64_encode_blockend(((int8_t*)buffer
) + code_length
,
251 /* Terminate string */
252 buffer
[code_length
++] = '\0';
254 /* Shrink the buffer */
255 new_buffer
= realloc(buffer
, code_length
);
256 if (new_buffer
) buffer
= new_buffer
;
262 /* Decode given data from MIME Base64 encoded zero terminated string to binary
263 * stream. Invalid Base64 symbols are skipped.
264 * @encoded are input data (Base64 zero terminated string)
265 * @plain are automatically reallocated output data (binary stream). You must
266 * free it. Will be freed in case of error.
267 * @return length of @plain data in bytes or (size_t) -1 in case of memory
268 * allocation failure. */
269 _hidden
size_t _isds_b64decode(const char *encoded
, void **plain
) {
271 base64_decodestate state
;
272 size_t encoded_length
;
276 if (!encoded
|| !plain
) {
277 if (plain
&& *plain
) zfree(*plain
);
278 return ((size_t) -1);
281 encoded_length
= strlen(encoded
);
282 _isds_base64_init_decodestate(&state
);
284 /* Divert empty input */
285 if (encoded_length
== 0) {
290 /* Allocate buffer */
291 buffer
= realloc(*plain
, encoded_length
);
294 return ((size_t) -1);
298 /* Decode encoded data */
299 plain_length
= _isds_base64_decode_block((const int8_t *)encoded
,
300 encoded_length
, *plain
, &state
);
301 if (plain_length
< 0 || plain_length
>= (size_t) -1) {
306 /* Shrink the buffer */
307 buffer
= realloc(*plain
, plain_length
);
308 if (!buffer
) *plain
= buffer
;
309 /* realloc(, 0) can return NULL or pointer designed to free() */
310 if (plain_length
== 0) zfree(*plain
);
316 /* Convert hexadecimal digit to integer. Return negative value if character is
317 * not valid hexadecimal digit. */
318 _hidden
int _isds_hex2i(char digit
) {
319 if (digit
>= '0' && digit
<= '9')
321 if (digit
>= 'a' && digit
<= 'f')
322 return digit
- 'a' + 10;
323 if (digit
>= 'A' && digit
<= 'F')
324 return digit
- 'A' + 10;
329 /* Switches time zone to UTC.
330 * XXX: This is not reentrant and not thread-safe */
331 static void _isds_switch_tz_to_utc(void) {
336 tz_orig
= strdup(tz
);
338 PANIC("Can not back original time zone up");
343 if (setenv("TZ", "", 1))
344 PANIC("Can not change time zone to UTC temporarily");
350 /* Switches time zone to original value.
351 * XXX: This is not reentrant and not thread-safe */
352 static void _isds_switch_tz_to_native(void) {
354 if (setenv("TZ", tz_orig
, 1))
355 PANIC("Can not restore time zone by setting TZ variable");
360 PANIC("Can not restore time zone by unsetting TZ variable");
366 /* Convert UTC broken time to time_t.
367 * @broken_utc it time in UTC in broken format. Despite its content is not
368 * touched, it'sw not-const because underlying POSIX function has non-const
370 * @return (time_t) -1 in case of error */
371 _hidden
time_t _isds_timegm(struct tm
*broken_utc
) {
374 _isds_switch_tz_to_utc();
375 time
= mktime(broken_utc
);
376 _isds_switch_tz_to_native();