1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2007 Mario Danic
4  * Copyright (c) 2009 - 2019 Thomas Schmitt
5  *
6  * This file is part of the libisofs project; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * or later as published by the Free Software Foundation.
9  * See COPYING file for details.
10  */
11 
12 #ifdef HAVE_CONFIG_H
13 #include "../config.h"
14 #endif
15 
16 #include "util.h"
17 #include "libisofs.h"
18 #include "messages.h"
19 #include "joliet.h"
20 #include "node.h"
21 
22 #include <stdlib.h>
23 #include <wchar.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <iconv.h>
30 #include <locale.h>
31 #include <langinfo.h>
32 
33 #include <unistd.h>
34 
35 /* if we don't have eaccess, we check file access by opening it */
36 #ifndef HAVE_EACCESS
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #endif
41 
42 
43 /* Produce possibly inflationary error messages directly to stderr */
44 static int iso_iconv_debug = 0;
45 
46 
47 struct iso_iconv_handle {
48     int status;  /* bit0= open , bit1= identical mapping */
49     iconv_t descr;
50 };
51 
52 
53 /*
54    @param flag    bit0= shortcut by identical mapping is not allowed
55 */
56 static
iso_iconv_open(struct iso_iconv_handle * handle,char * tocode,char * fromcode,int flag)57 int iso_iconv_open(struct iso_iconv_handle *handle,
58                    char *tocode, char *fromcode, int flag)
59 {
60     handle->status = 0;
61     handle->descr = (iconv_t) -1;
62 
63     if (strcmp(tocode, fromcode) == 0 && !(flag & 1)) {
64         handle->status = 1 | 2;
65         return 1;
66     }
67     handle->descr = iconv_open(tocode, fromcode);
68     if (handle->descr == (iconv_t) -1) {
69         if (strlen(tocode) + strlen(fromcode) <= 160 && iso_iconv_debug)
70             fprintf(stderr,
71            "libisofs_DEBUG: iconv_open(\"%s\", \"%s\") failed: errno= %d %s\n",
72                     tocode, fromcode, errno, strerror(errno));
73         return 0;
74     }
75     handle->status = 1;
76     return 1;
77 }
78 
79 
80 static
iso_iconv(struct iso_iconv_handle * handle,char ** inbuf,size_t * inbytesleft,char ** outbuf,size_t * outbytesleft,int flag)81 size_t iso_iconv(struct iso_iconv_handle *handle,
82                  char **inbuf, size_t *inbytesleft,
83                  char **outbuf, size_t *outbytesleft, int flag)
84 {
85     size_t ret;
86 /* The build system might indicate iconv(,const char **inbuf,) by
87    defining ICONV_CONST const
88 */
89 #ifndef ICONV_CONST
90 #define ICONV_CONST
91 #endif
92     ICONV_CONST char **local_inbuf;
93 
94     local_inbuf = (ICONV_CONST char **) inbuf;
95 
96     if (!(handle->status & 1)) {
97         if (iso_iconv_debug)
98             fprintf(stderr,
99           "libisofs_DEBUG: iso_iconv(): iso_iconv_handle not in open state\n");
100         return (size_t) -1;
101     }
102     if (handle->status & 2) {
103         if (inbuf == NULL || outbuf == NULL) {
104 null_buf:;
105             if (iso_iconv_debug)
106                 fprintf(stderr,
107 "libisofs_DEBUG: iso_iconv(): NULL buffers not allowed in shortcut mapping\n");
108             return (size_t) -1;
109         }
110         if (*inbuf == NULL || *outbuf == NULL)
111             goto null_buf;
112         while (*inbytesleft > 0 && *outbytesleft > 0) {
113              *((*outbuf)++) = *((*inbuf)++);
114              (*inbytesleft)--;
115              (*outbytesleft)--;
116         }
117         if (*inbytesleft > 0 && *outbytesleft <= 0)
118             return (size_t) -1;
119         return (size_t) 0;
120     }
121     ret = iconv(handle->descr, local_inbuf, inbytesleft, outbuf, outbytesleft);
122     if (ret == (size_t) -1) {
123         if (iso_iconv_debug)
124             fprintf(stderr, "libisofs_DEBUG: iconv() failed: errno= %d %s\n",
125                           errno, strerror(errno));
126         return (size_t) -1;
127     }
128     return ret;
129 }
130 
131 
132 static
iso_iconv_close(struct iso_iconv_handle * handle,int flag)133 int iso_iconv_close(struct iso_iconv_handle *handle, int flag)
134 {
135     int ret;
136 
137     if (!(handle->status & 1)) {
138         if (iso_iconv_debug)
139             fprintf(stderr,
140     "libisofs_DEBUG: iso_iconv_close(): iso_iconv_handle not in open state\n");
141         return -1;
142     }
143     handle->status &= ~1;
144     if (handle->status & 2)
145         return 0;
146 
147     ret = iconv_close(handle->descr);
148     if (ret == -1) {
149         if (iso_iconv_debug)
150             fprintf(stderr,
151                     "libisofs_DEBUG: iconv_close() failed: errno= %d %s\n",
152                     errno, strerror(errno));
153         return -1;
154     }
155     return ret;
156 }
157 
158 
int_pow(int base,int power)159 int int_pow(int base, int power)
160 {
161     int result = 1;
162     while (--power >= 0) {
163         result *= base;
164     }
165     return result;
166 }
167 
168 /* This static variable can override the locale's charset by its getter
169    function which should be used whenever the local character set name
170    is to be inquired. I.e. instead of calling nl_langinfo(CODESET) directly.
171    If the variable is empty then it forwards nl_langinfo(CODESET).
172 */
173 static char libisofs_local_charset[4096]= {""};
174 
175 /* API function */
iso_set_local_charset(char * name,int flag)176 int iso_set_local_charset(char *name, int flag)
177 {
178     if(strlen(name) >= sizeof(libisofs_local_charset))
179         return(0);
180     strcpy(libisofs_local_charset, name);
181     return 1;
182 }
183 
184 /* API function */
iso_get_local_charset(int flag)185 char *iso_get_local_charset(int flag)
186 {
187    if(libisofs_local_charset[0])
188      return libisofs_local_charset;
189    return nl_langinfo(CODESET);
190 }
191 
strconv(const char * str,const char * icharset,const char * ocharset,char ** output)192 int strconv(const char *str, const char *icharset, const char *ocharset,
193             char **output)
194 {
195     size_t inbytes;
196     size_t outbytes;
197     size_t n;
198     struct iso_iconv_handle conv;
199     int conv_ret;
200 
201     char *out = NULL;
202     char *src;
203     char *ret;
204     int retval;
205 
206     inbytes = strlen(str);
207     outbytes = (inbytes + 1) * MB_LEN_MAX;
208     out = calloc(outbytes, 1);
209     if (out == NULL) {
210         retval = ISO_OUT_OF_MEM;
211         goto ex;
212     }
213 
214     conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
215     if (conv_ret <= 0) {
216         retval = ISO_CHARSET_CONV_ERROR;
217         goto ex;
218     }
219     src = (char *)str;
220     ret = (char *)out;
221     n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
222     if (n == (size_t) -1) {
223         /* error */
224         iso_iconv_close(&conv, 0);
225         retval = ISO_CHARSET_CONV_ERROR;
226         goto ex;
227     }
228     *ret = '\0';
229     iso_iconv_close(&conv, 0);
230 
231     *output = malloc(ret - out + 1);
232     if (*output == NULL) {
233         retval = ISO_OUT_OF_MEM;
234         goto ex;
235     }
236     memcpy(*output, out, ret - out + 1);
237     retval = ISO_SUCCESS;
238 ex:;
239     if (out != NULL)
240         free(out);
241     return retval;
242 }
243 
strnconvl(const char * str,const char * icharset,const char * ocharset,size_t len,char ** output,size_t * out_len)244 int strnconvl(const char *str, const char *icharset, const char *ocharset,
245               size_t len, char **output, size_t *out_len)
246 {
247     size_t inbytes;
248     size_t outbytes;
249     size_t n;
250     struct iso_iconv_handle conv;
251     int conv_ret;
252     char *out = NULL;
253     char *src;
254     char *ret;
255     int retval;
256 
257     inbytes = len;
258     outbytes = (inbytes + 1) * MB_LEN_MAX;
259     out = calloc(outbytes, 1);
260     if (out == NULL) {
261         retval = ISO_OUT_OF_MEM;
262         goto ex;
263     }
264     conv_ret = iso_iconv_open(&conv, (char *) ocharset, (char *) icharset, 0);
265     if (conv_ret <= 0) {
266         retval = ISO_CHARSET_CONV_ERROR;
267         goto ex;
268     }
269     src = (char *)str;
270     ret = (char *)out;
271     n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
272     if (n == (size_t) -1) {
273         /* error */
274         iso_iconv_close(&conv, 0);
275         retval = ISO_CHARSET_CONV_ERROR;
276         goto ex;
277     }
278     *ret = '\0';
279     iso_iconv_close(&conv, 0);
280 
281     *out_len = ret - out;
282     *output = malloc(*out_len + 1);
283     if (*output == NULL) {
284         retval = ISO_OUT_OF_MEM;
285         goto ex;
286     }
287     memcpy(*output, out, ret - out + 1);
288     retval = ISO_SUCCESS;
289 ex:;
290     if (out != NULL)
291         free(out);
292     return retval;
293 }
294 
strnconv(const char * str,const char * icharset,const char * ocharset,size_t len,char ** output)295 int strnconv(const char *str, const char *icharset, const char *ocharset,
296              size_t len, char **output)
297 {
298     size_t l;
299 
300     return strnconvl(str, icharset, ocharset, len, output, &l);
301 }
302 
303 
304 /**
305  * Convert a str in a specified codeset to WCHAR_T.
306  * The result must be free() when no more needed
307  *
308  * @return
309  *      1 success, < 0 error
310  */
311 static
str2wchar(const char * icharset,const char * input,wchar_t ** output)312 int str2wchar(const char *icharset, const char *input, wchar_t **output)
313 {
314     struct iso_iconv_handle conv;
315     int conv_ret;
316 
317     /* That while loop smells like a potential show stopper */
318     size_t loop_counter = 0, loop_limit = 3;
319 
320     size_t inbytes;
321     size_t outbytes;
322     char *ret;
323     char *src;
324     wchar_t *wstr;
325     size_t n;
326 
327     if (icharset == NULL || input == NULL || output == NULL) {
328         return ISO_NULL_POINTER;
329     }
330 
331     conv_ret = iso_iconv_open(&conv, "WCHAR_T", (char *) icharset, 0);
332     if (conv_ret <= 0) {
333         return ISO_CHARSET_CONV_ERROR;
334     }
335 
336     inbytes = strlen(input);
337     loop_limit = inbytes + 3;
338     outbytes = (inbytes + 1) * sizeof(wchar_t);
339 
340     /* we are sure that numchars <= inbytes */
341     wstr = malloc(outbytes);
342     if (wstr == NULL) {
343         return ISO_OUT_OF_MEM;
344     }
345     ret = (char *)wstr;
346     src = (char *)input;
347 
348     n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
349     while (n == (size_t) -1) {
350 
351         if (errno == E2BIG) {
352             /* error, should never occur */
353             goto conv_error;
354         } else {
355             wchar_t *wret;
356 
357             /*
358              * Invalid input string charset.
359              * This can happen if input is in fact encoded in a charset
360              * different than icharset.
361              * We can't do anything better than replace by "_" and continue.
362              */
363             inbytes--;
364             src++;
365 
366             wret = (wchar_t*) ret;
367             *wret++ = (wchar_t) '_';
368             ret = (char *) wret;
369             outbytes -= sizeof(wchar_t);
370 
371             if (!inbytes)
372                 break;
373 
374             /* Just to appease my remorse about unclear loop ends */
375             loop_counter++;
376             if (loop_counter > loop_limit)
377                 goto conv_error;
378             n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
379         }
380     }
381     iso_iconv_close(&conv, 0);
382     *( (wchar_t *)ret )='\0';
383     *output = wstr;
384     return ISO_SUCCESS;
385 
386 conv_error:;
387     iso_iconv_close(&conv, 0);
388     free(wstr);
389     return ISO_CHARSET_CONV_ERROR;
390 }
391 
str2ascii(const char * icharset,const char * input,char ** output)392 int str2ascii(const char *icharset, const char *input, char **output)
393 {
394     int result;
395     wchar_t *wsrc_ = NULL;
396     char *ret = NULL;
397     char *ret_ = NULL;
398     char *src;
399     struct iso_iconv_handle conv;
400     int conv_ret;
401     int direct_conv = 0;
402 
403     /* That while loop smells like a potential show stopper */
404     size_t loop_counter = 0, loop_limit = 3;
405 
406     /* Fallback in case that iconv() is too demanding for system */
407     unsigned char *cpt;
408 
409     size_t numchars;
410     size_t outbytes;
411     size_t inbytes;
412     size_t n;
413 
414 
415     if (icharset == NULL || input == NULL || output == NULL) {
416         return ISO_NULL_POINTER;
417     }
418 
419     /* First try the traditional way via intermediate character set WCHAR_T.
420      * Up to August 2011 this was the only way. But it will not work if
421      * there is no character set "WCHAR_T". E.g. on Solaris.
422      */
423     /* convert the string to a wide character string. Note: outbytes
424      * is in fact the number of characters in the string and doesn't
425      * include the last NULL character.
426      */
427     conv_ret = 0;
428     result = str2wchar(icharset, input, &wsrc_);
429     if (result == (int) ISO_SUCCESS) {
430         src = (char *)wsrc_;
431         numchars = wcslen(wsrc_);
432 
433         inbytes = numchars * sizeof(wchar_t);
434         loop_limit = inbytes + 3;
435 
436         ret_ = malloc(numchars + 1);
437         if (ret_ == NULL) {
438             free(wsrc_);
439             return ISO_OUT_OF_MEM;
440         }
441         outbytes = numchars;
442         ret = ret_;
443 
444         /* initialize iconv */
445         conv_ret = iso_iconv_open(&conv, "ASCII", "WCHAR_T", 0);
446         if (conv_ret <= 0) {
447             free(wsrc_);
448             wsrc_ = NULL;
449             free(ret_);
450             ret = ret_ = NULL;
451         }
452     } else if (result != (int) ISO_CHARSET_CONV_ERROR)
453         return result;
454 
455     /* If this did not succeed : Try the untraditional direct conversion.
456     */
457     if (conv_ret <= 0) {
458         conv_ret = iso_iconv_open(&conv, "ASCII", (char *) icharset, 0);
459         if (conv_ret <= 0)
460             goto fallback;
461         direct_conv = 1;
462         src = (char *) input;
463         inbytes = strlen(input);
464         loop_limit = inbytes + 3;
465         outbytes = (inbytes + 1) * sizeof(uint16_t);
466         ret_ = malloc(outbytes);
467         if (ret_ == NULL)
468             return ISO_OUT_OF_MEM;
469         ret = ret_;
470     }
471 
472     n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
473     while (n == (size_t) -1) {
474         /* The destination buffer is too small. Stops here. */
475         if (errno == E2BIG)
476             break;
477 
478         /* An incomplete multi bytes sequence was found. We
479          * can't do anything here. That's quite unlikely. */
480         if (errno == EINVAL)
481             break;
482 
483         /* The last possible error is an invalid multi bytes
484          * sequence. Just replace the character with a "_".
485          * Probably the character doesn't exist in ascii like
486          * "é, è, à, ç, ..." in French. */
487         *ret++ = '_';
488         outbytes--;
489 
490         if (!outbytes)
491             break;
492 
493         /* There was an error with one character but some other remain
494          * to be converted. That's probably a multibyte character.
495          * See above comment. */
496         if (direct_conv) {
497             src++;
498             inbytes--;
499         } else {
500             src += sizeof(wchar_t);
501             inbytes -= sizeof(wchar_t);
502         }
503 
504         if (!inbytes)
505             break;
506 
507         /* Just to appease my remorse about unclear loop ends */
508         loop_counter++;
509         if (loop_counter > loop_limit)
510             break;
511         n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
512     }
513     iso_iconv_close(&conv, 0);
514     *ret = 0;
515     if (wsrc_ != NULL)
516         free(wsrc_);
517 
518     *output = ret_;
519     return ISO_SUCCESS;
520 
521 fallback:;
522     /* Assume to have a single byte charset with ASCII as core.
523        Anything suspicious will be mapped to '_'.
524      */
525     *output = strdup(input);
526     for (cpt = (unsigned char *) *output; *cpt; cpt++) {
527         if (*cpt < 32 || *cpt > 126)
528             *cpt = '_';
529     }
530     return ISO_SUCCESS;
531 }
532 
533 static
set_ucsbe(uint16_t * ucs,char c)534 void set_ucsbe(uint16_t *ucs, char c)
535 {
536     char *v = (char*)ucs;
537     v[0] = (char)0;
538     v[1] = c;
539 }
540 
541 /**
542  * @return
543  *      -1, 0, 1 if *ucs <, == or > than c
544  */
545 static
cmp_ucsbe(const uint16_t * ucs,char c)546 int cmp_ucsbe(const uint16_t *ucs, char c)
547 {
548     char *v = (char*)ucs;
549     if (v[0] != 0) {
550         return 1;
551     } else if (v[1] == c) {
552         return 0;
553     } else {
554         return (uint8_t)c > (uint8_t)v[1] ? -1 : 1;
555     }
556 }
557 
str2ucs(const char * icharset,const char * input,uint16_t ** output)558 int str2ucs(const char *icharset, const char *input, uint16_t **output)
559 {
560     int result;
561     wchar_t *wsrc_ = NULL;
562     char *src;
563     char *ret = NULL;
564     char *ret_ = NULL;
565     struct iso_iconv_handle conv;
566     int conv_ret = 0;
567     int direct_conv = 0;
568 
569     /* That while loop smells like a potential show stopper */
570     size_t loop_counter = 0, loop_limit = 3;
571 
572     size_t numchars;
573     size_t outbytes;
574     size_t inbytes;
575     size_t n;
576 
577     if (icharset == NULL || input == NULL || output == NULL) {
578         return ISO_NULL_POINTER;
579     }
580 
581     /* convert the string to a wide character string. Note: outbytes
582      * is in fact the number of characters in the string and doesn't
583      * include the last NULL character.
584      */
585     /* First try the traditional way via intermediate character set WCHAR_T.
586      * Up to August 2011 this was the only way. But it will not work if
587      * there is no character set "WCHAR_T". E.g. on Solaris.
588      */
589     conv_ret = 0;
590     result = str2wchar(icharset, input, &wsrc_);
591     if (result == (int) ISO_SUCCESS) {
592         src = (char *)wsrc_;
593         numchars = wcslen(wsrc_);
594 
595         inbytes = numchars * sizeof(wchar_t);
596         loop_limit = inbytes + 3;
597 
598         ret_ = malloc((numchars+1) * sizeof(uint16_t));
599         if (ret_ == NULL) {
600             free(wsrc_);
601             return ISO_OUT_OF_MEM;
602         }
603         outbytes = numchars * sizeof(uint16_t);
604         ret = ret_;
605 
606         /* initialize iconv */
607         conv_ret = iso_iconv_open(&conv, "UCS-2BE", "WCHAR_T", 0);
608         if (conv_ret <= 0) {
609             free(wsrc_);
610             wsrc_ = NULL;
611             free(ret_);
612             ret = ret_ = NULL;
613         }
614     } else if (result != (int) ISO_CHARSET_CONV_ERROR)
615         return result;
616 
617     /* If this did not succeed : Try the untraditional direct conversion.
618     */
619     if (conv_ret <= 0) {
620         conv_ret = iso_iconv_open(&conv, "UCS-2BE", (char *) icharset, 0);
621         if (conv_ret <= 0) {
622             return ISO_CHARSET_CONV_ERROR;
623         }
624         direct_conv = 1;
625         src = (char *) input;
626         inbytes = strlen(input);
627         loop_limit = inbytes + 3;
628         outbytes = (inbytes + 1) * sizeof(uint16_t);
629         ret_ = malloc(outbytes);
630         if (ret_ == NULL)
631             return ISO_OUT_OF_MEM;
632         ret = ret_;
633     }
634 
635     n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
636     while (n == (size_t) -1) {
637         /* The destination buffer is too small. Stops here. */
638         if (errno == E2BIG)
639             break;
640 
641         /* An incomplete multi bytes sequence was found. We
642          * can't do anything here. That's quite unlikely. */
643         if (errno == EINVAL)
644             break;
645 
646         /* The last possible error is an invalid multi bytes
647          * sequence. Just replace the character with a "_".
648          * Probably the character doesn't exist in UCS */
649         set_ucsbe((uint16_t*) ret, '_');
650         ret += sizeof(uint16_t);
651         outbytes -= sizeof(uint16_t);
652 
653         if (!outbytes)
654             break;
655 
656         /* There was an error with one character but some other remain
657          * to be converted. That's probably a multibyte character.
658          * See above comment. */
659         if (direct_conv) {
660             src++;
661             inbytes--;
662         } else {
663             src += sizeof(wchar_t);
664             inbytes -= sizeof(wchar_t);
665         }
666 
667         if (!inbytes)
668             break;
669 
670         /* Just to appease my remorse about unclear loop ends */
671         loop_counter++;
672         if (loop_counter > loop_limit)
673             break;
674         n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
675     }
676     iso_iconv_close(&conv, 0);
677 
678     /* close the ucs string */
679     set_ucsbe((uint16_t*) ret, '\0');
680     if (wsrc_ != NULL)
681         free(wsrc_);
682 
683     *output = (uint16_t*)ret_;
684     return ISO_SUCCESS;
685 }
686 
str2utf16be(const char * icharset,const char * input,uint16_t ** output)687 int str2utf16be(const char *icharset, const char *input, uint16_t **output)
688 {
689     int result;
690     wchar_t *wsrc_ = NULL;
691     char *src;
692     char *ret = NULL;
693     char *ret_ = NULL;
694     struct iso_iconv_handle conv;
695     int conv_ret = 0;
696     int direct_conv = 0;
697     size_t loop_counter = 0, loop_limit = 3;
698     size_t numchars;
699     size_t outbytes;
700     size_t inbytes;
701     size_t n;
702 
703     if (icharset == NULL || input == NULL || output == NULL) {
704         return ISO_NULL_POINTER;
705     }
706 
707     /*
708       Try the direct conversion.
709     */
710     conv_ret = iso_iconv_open(&conv, "UTF-16BE", (char *) icharset, 0);
711     if (conv_ret > 0) {
712         direct_conv = 1;
713         src = (char *) input;
714         inbytes = strlen(input);
715         loop_limit = inbytes + 3;
716         outbytes = (2 * inbytes + 1) * sizeof(uint16_t);
717         ret_ = malloc(outbytes);
718         if (ret_ == NULL)
719             return ISO_OUT_OF_MEM;
720         ret = ret_;
721     }  else {
722         /* Try via intermediate character set WCHAR_T.
723         */
724         result = str2wchar(icharset, input, &wsrc_);
725         if (result == (int) ISO_SUCCESS) {
726             src = (char *)wsrc_;
727             numchars = wcslen(wsrc_);
728 
729             inbytes = numchars * sizeof(wchar_t);
730             loop_limit = inbytes + 3;
731 
732             ret_ = malloc((2 * numchars+1) * sizeof(uint16_t));
733             if (ret_ == NULL) {
734                 free(wsrc_);
735                 return ISO_OUT_OF_MEM;
736             }
737             outbytes = 2 * numchars * sizeof(uint16_t);
738             ret = ret_;
739 
740             /* initialize iconv */
741             conv_ret = iso_iconv_open(&conv, "UTF-16BE", "WCHAR_T", 0);
742             if (conv_ret <= 0) {
743                 free(wsrc_);
744                 free(ret_);
745             }
746         } else if (result != (int) ISO_CHARSET_CONV_ERROR)
747             return result;
748     }
749 
750     if (conv_ret <= 0) {
751         return ISO_CHARSET_CONV_ERROR;
752     }
753 
754     n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
755     while (n == (size_t) -1) {
756         /* The destination buffer is too small. Stops here. */
757         if (errno == E2BIG)
758             break;
759 
760         /* An incomplete multi bytes sequence was found. We
761          * can't do anything here. That's quite unlikely. */
762         if (errno == EINVAL)
763             break;
764 
765         /* The last possible error is an invalid multi bytes
766          * sequence. Just replace the character with a "_".
767          * Probably the character doesn't exist in UCS */
768         set_ucsbe((uint16_t*) ret, '_');
769         ret += sizeof(uint16_t);
770         outbytes -= sizeof(uint16_t);
771 
772         if (!outbytes)
773             break;
774 
775         /* There was an error with one character but some other remain
776          * to be converted. That's probably a multibyte character.
777          * See above comment. */
778         if (direct_conv) {
779             src++;
780             inbytes--;
781         } else {
782             src += sizeof(wchar_t);
783             inbytes -= sizeof(wchar_t);
784         }
785 
786         if (!inbytes)
787             break;
788 
789         /* Just to appease my remorse about unclear loop ends */
790         loop_counter++;
791         if (loop_counter > loop_limit)
792             break;
793         n = iso_iconv(&conv, &src, &inbytes, &ret, &outbytes, 0);
794     }
795     iso_iconv_close(&conv, 0);
796 
797     /* close the UTF-16 string */
798     set_ucsbe((uint16_t*) ret, '\0');
799     if (wsrc_ != NULL)
800         free(wsrc_);
801 
802     *output = (uint16_t*)ret_;
803     return ISO_SUCCESS;
804 }
805 
valid_d_char(char c)806 static int valid_d_char(char c)
807 {
808     return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
809 }
810 
valid_a_char(char c)811 static int valid_a_char(char c)
812 {
813     return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') ||
814            (c >= 'A' && c <= 'Z') || (c == '_');
815 }
816 
valid_j_char(uint16_t c)817 static int valid_j_char(uint16_t c)
818 {
819     return cmp_ucsbe(&c, ' ') != -1 && cmp_ucsbe(&c, '*') && cmp_ucsbe(&c, '/')
820         && cmp_ucsbe(&c, ':') && cmp_ucsbe(&c, ';') && cmp_ucsbe(&c, '?')
821         && cmp_ucsbe(&c, '\\');
822 }
823 
824 /* @param relaxed bit0+1  0= strict ECMA-119
825                           1= additionally allow lowercase (else map to upper)
826                           2= allow all 8-bit characters
827                   bit2    allow all 7-bit characters (but map to upper if
828                           not bit0+1 == 2)
829 */
map_fileid_char(char c,int relaxed)830 static char map_fileid_char(char c, int relaxed)
831 {
832     char upper;
833 
834     if (c == '/')  /* Allowing slashes would cause lots of confusion */
835         return '_';
836     if ((relaxed & 3) == 2)
837         return c;
838     if (valid_d_char(c))
839         return c;
840     if ((relaxed & 4) && (c & 0x7f) == c && (c < 'a' || c > 'z'))
841         return c;
842     upper= toupper(c);
843     if (valid_d_char(upper)) {
844         if (relaxed & 3) {
845             /* lower chars are allowed */
846             return c;
847         }
848         return upper;
849     }
850     return '_';
851 }
852 
853 static
iso_dirid(const char * src,int size,int relaxed)854 char *iso_dirid(const char *src, int size, int relaxed)
855 {
856     size_t len, i;
857     char name[32];
858 
859     len = strlen(src);
860     if ((int) len > size) {
861         len = size;
862     }
863     for (i = 0; i < len; i++) {
864 
865 #ifdef Libisofs_old_ecma119_nameS
866 
867         char c= toupper(src[i]);
868         name[i] = valid_d_char(c) ? c : '_';
869 
870 #else /* Libisofs_old_ecma119_nameS */
871 
872         name[i] = map_fileid_char(src[i], relaxed);
873 
874 #endif /* ! Libisofs_old_ecma119_nameS */
875 
876     }
877 
878     name[len] = '\0';
879     return strdup(name);
880 }
881 
iso_1_dirid(const char * src,int relaxed)882 char *iso_1_dirid(const char *src, int relaxed)
883 {
884     return iso_dirid(src, 8, relaxed);
885 }
886 
iso_2_dirid(const char * src)887 char *iso_2_dirid(const char *src)
888 {
889     return iso_dirid(src, 31, 0);
890 }
891 
iso_1_fileid(const char * src,int relaxed,int force_dots)892 char *iso_1_fileid(const char *src, int relaxed, int force_dots)
893 {
894     char *dot; /* Position of the last dot in the filename, will be used
895                 * to calculate lname and lext. */
896     int lname, lext, pos, i;
897     char dest[13]; /*  13 = 8 (name) + 1 (.) + 3 (ext) + 1 (\0) */
898 
899     if (src == NULL) {
900         return NULL;
901     }
902     dot = strrchr(src, '.');
903     if (dot == src && strlen(src) > 4)
904         dot = NULL;      /* Use the long extension instead of the empty name */
905     lext = dot ? strlen(dot + 1) : 0;
906     lname = strlen(src) - lext - (dot ? 1 : 0);
907 
908     /* If we can't build a filename, return NULL. */
909     if (lname == 0 && lext == 0) {
910         return NULL;
911     }
912 
913     pos = 0;
914 
915     /* Convert up to 8 characters of the filename. */
916     for (i = 0; i < lname && i < 8; i++) {
917 
918 #ifdef Libisofs_old_ecma119_nameS
919 
920         char c= toupper(src[i]);
921 
922         dest[pos++] = valid_d_char(c) ? c : '_';
923 
924 #else /* Libisofs_old_ecma119_nameS */
925 
926         if (dot == NULL && src[i] == '.')
927             dest[pos++] = '_'; /* make sure that ignored dots do not appear */
928         else
929             dest[pos++] = map_fileid_char(src[i], relaxed);
930 
931 #endif /* ! Libisofs_old_ecma119_nameS */
932 
933     }
934 
935     /* This dot is mandatory, even if there is no extension. */
936     if (force_dots || lext > 0)
937         dest[pos++] = '.';
938 
939     /* Convert up to 3 characters of the extension, if any. */
940     for (i = 0; i < lext && i < 3; i++) {
941 
942 #ifdef Libisofs_old_ecma119_nameS
943 
944         char c= toupper(src[lname + 1 + i]);
945 
946         dest[pos++] = valid_d_char(c) ? c : '_';
947 
948 #else /* Libisofs_old_ecma119_nameS */
949 
950         dest[pos++] = map_fileid_char(src[lname + 1 + i], relaxed);
951 
952 #endif /* ! Libisofs_old_ecma119_nameS */
953 
954     }
955 
956     dest[pos] = '\0';
957     return strdup(dest);
958 }
959 
iso_2_fileid(const char * src)960 char *iso_2_fileid(const char *src)
961 {
962     char *dot;
963     int lname, lext, lnname, lnext, pos, i;
964     char dest[32]; /* 32 = 30 (name + ext) + 1 (.) + 1 (\0) */
965 
966     if (src == NULL) {
967         return NULL;
968     }
969 
970     dot = strrchr(src, '.');
971 
972     /*
973      * Since the maximum length can be divided freely over the name and
974      * extension, we need to calculate their new lengths (lnname and
975      * lnext). If the original filename is too long, we start by trimming
976      * the extension, but keep a minimum extension length of 3.
977      */
978     if (dot == NULL || *(dot + 1) == '\0') {
979         lname = strlen(src);
980         lnname = (lname > 30) ? 30 : lname;
981         lext = lnext = 0;
982     } else {
983         lext = strlen(dot + 1);
984         lname = strlen(src) - lext - 1;
985         lnext = (strlen(src) > 31 && lext > 3) ? (lname < 27 ? 30 - lname : 3)
986                 : lext;
987         lnname = (strlen(src) > 31) ? 30 - lnext : lname;
988     }
989 
990     if (lnname == 0 && lnext == 0) {
991         return NULL;
992     }
993 
994     pos = 0;
995 
996     /* Convert up to lnname characters of the filename. */
997     for (i = 0; i < lnname; i++) {
998         char c= toupper(src[i]);
999 
1000         dest[pos++] = valid_d_char(c) ? c : '_';
1001     }
1002     dest[pos++] = '.';
1003 
1004     /* Convert up to lnext characters of the extension, if any. */
1005     for (i = 0; i < lnext; i++) {
1006         char c= toupper(src[lname + 1 + i]);
1007 
1008         dest[pos++] = valid_d_char(c) ? c : '_';
1009     }
1010     dest[pos] = '\0';
1011     return strdup(dest);
1012 }
1013 
1014 /**
1015  * Create a dir name suitable for an ISO image with relaxed constraints.
1016  *
1017  * @param size
1018  *     Max len for the name
1019  * @param relaxed
1020  *     bit0+1: 0 only allow d-characters,
1021  *             1 allow also lowe case chars,
1022  *             2 allow all 8-bit characters,
1023  *     bit2:   allow 7-bit characters (but map lowercase to uppercase if
1024  *             not bit0+1 == 2)
1025  */
iso_r_dirid(const char * src,int size,int relaxed)1026 char *iso_r_dirid(const char *src, int size, int relaxed)
1027 {
1028     size_t len, i;
1029     char *dest;
1030 
1031     len = strlen(src);
1032     if ((int) len > size) {
1033         len = size;
1034     }
1035     dest = malloc(len + 1);
1036     if (dest == NULL)
1037         return NULL;
1038     for (i = 0; i < len; i++) {
1039 
1040 #ifdef Libisofs_old_ecma119_nameS
1041 
1042         char c= src[i];
1043         if (relaxed == 2) {
1044             /* all chars are allowed */
1045             dest[i] = c;
1046         } else if (valid_d_char(c)) {
1047             /* it is a valid char */
1048             dest[i] = c;
1049         } else {
1050             c= toupper(src[i]);
1051             if (valid_d_char(c)) {
1052                 if (relaxed) {
1053                     /* lower chars are allowed */
1054                     dest[i] = src[i];
1055                 } else {
1056                     dest[i] = c;
1057                 }
1058             } else {
1059                 dest[i] = '_';
1060             }
1061         }
1062 
1063 #else /* Libisofs_old_ecma119_nameS */
1064 
1065         dest[i] = map_fileid_char(src[i], relaxed);
1066 
1067 #endif /* ! Libisofs_old_ecma119_nameS */
1068 
1069     }
1070 
1071     dest[len] = '\0';
1072     return dest;
1073 }
1074 
1075 /**
1076  * Create a file name suitable for an ISO image with level > 1 and
1077  * with relaxed constraints.
1078  *
1079  * @param len
1080  *     Max len for the name, without taken the "." into account.
1081  * @param relaxed
1082  *     bit0+1: 0 only allow d-characters,
1083  *             1 allow also lowe case chars,
1084  *             2 allow all 8-bit characters,
1085  *     bit2:   allow 7-bit characters (but map lowercase to uppercase if
1086  *             not bit0+1 == 2)
1087  * @param forcedot
1088  *     Whether to ensure that "." is added
1089  */
iso_r_fileid(const char * src,size_t len,int relaxed,int forcedot)1090 char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot)
1091 {
1092     char *dot, *retval = NULL;
1093     int lname, lext, lnname, lnext, pos, i;
1094     char *dest = NULL;
1095 
1096     dest = calloc(len + 1 + 1, 1);
1097     if (dest == NULL)
1098         goto ex;
1099 
1100     if (src == NULL) {
1101         goto ex;
1102     }
1103 
1104     dot = strrchr(src, '.');
1105 
1106     /*
1107      * Since the maximum length can be divided freely over the name and
1108      * extension, we need to calculate their new lengths (lnname and
1109      * lnext). If the original filename is too long, we start by trimming
1110      * the extension, but keep a minimum extension length of 3.
1111      */
1112     if (dot == NULL || *(dot + 1) == '\0') {
1113         lname = strlen(src);
1114         lnname = (lname > (int) len) ? (int) len : lname;
1115         lext = lnext = 0;
1116     } else {
1117         lext = strlen(dot + 1);
1118         lname = strlen(src) - lext - 1;
1119         lnext = (strlen(src) > len + 1 && lext > 3) ?
1120                 (lname < (int) len - 3 ? (int) len - lname : 3)
1121                 : lext;
1122         lnname = (strlen(src) > len + 1) ? (int) len - lnext : lname;
1123     }
1124 
1125     if (lnname == 0 && lnext == 0) {
1126         goto ex;
1127     }
1128 
1129     pos = 0;
1130 
1131     /* Convert up to lnname characters of the filename. */
1132     for (i = 0; i < lnname; i++) {
1133 
1134 #ifdef Libisofs_old_ecma119_nameS
1135 
1136         char c= src[i];
1137         if (relaxed == 2) {
1138             /* all chars are allowed */
1139             dest[pos++] = c;
1140         } else if (valid_d_char(c)) {
1141             /* it is a valid char */
1142             dest[pos++] = c;
1143         } else {
1144             c= toupper(src[i]);
1145             if (valid_d_char(c)) {
1146                 if (relaxed) {
1147                     /* lower chars are allowed */
1148                     dest[pos++] = src[i];
1149                 } else {
1150                     dest[pos++] = c;
1151                 }
1152             } else {
1153                 dest[pos++] = '_';
1154             }
1155         }
1156 
1157 #else /* Libisofs_old_ecma119_nameS */
1158 
1159         dest[pos++] = map_fileid_char(src[i], relaxed);
1160 
1161 #endif /* ! Libisofs_old_ecma119_nameS */
1162 
1163     }
1164     if (lnext > 0 || forcedot) {
1165         dest[pos++] = '.';
1166     }
1167 
1168     /* Convert up to lnext characters of the extension, if any. */
1169     for (i = lname + 1; i < lname + 1 + lnext; i++) {
1170 
1171 #ifdef Libisofs_old_ecma119_nameS
1172 
1173         char c= src[i];
1174         if (relaxed == 2) {
1175             /* all chars are allowed */
1176             dest[pos++] = c;
1177         } else if (valid_d_char(c)) {
1178             /* it is a valid char */
1179             dest[pos++] = c;
1180         } else {
1181             c= toupper(src[i]);
1182             if (valid_d_char(c)) {
1183                 if (relaxed) {
1184                     /* lower chars are allowed */
1185                     dest[pos++] = src[i];
1186                 } else {
1187                     dest[pos++] = c;
1188                 }
1189             } else {
1190                 dest[pos++] = '_';
1191             }
1192         }
1193 
1194 #else /* Libisofs_old_ecma119_nameS */
1195 
1196         dest[pos++] = map_fileid_char(src[i], relaxed);
1197 
1198 #endif /* ! Libisofs_old_ecma119_nameS */
1199 
1200     }
1201     dest[pos] = '\0';
1202 
1203     retval = strdup(dest);
1204 
1205 ex:;
1206     if (dest != NULL)
1207         free(dest);
1208     return retval;
1209 }
1210 
1211 /*
1212    bit0= no_force_dots
1213    bit1= allow 103 characters rather than 64
1214 */
iso_j_file_id(const uint16_t * src,int flag)1215 uint16_t *iso_j_file_id(const uint16_t *src, int flag)
1216 {
1217     uint16_t *dot, *retval = NULL;
1218     size_t lname, lext, lnname, lnext, pos, i, maxchar = 64;
1219     uint16_t *dest = NULL, c;
1220 
1221     LIBISO_ALLOC_MEM_VOID(dest, uint16_t, LIBISO_JOLIET_NAME_MAX);
1222                                /* was: 66 = 64 (name + ext) + 1 (.) + 1 (\0) */
1223 
1224     if (src == NULL) {
1225         goto ex;
1226     }
1227     if (flag & 2)
1228         maxchar = 103;
1229 
1230     dot = ucsrchr(src, '.');
1231 
1232     /*
1233      * Since the maximum length can be divided freely over the name and
1234      * extension, we need to calculate their new lengths (lnname and
1235      * lnext). If the original filename is too long, we start by trimming
1236      * the extension, but keep a minimum extension length of 3.
1237      */
1238     if (dot == NULL || cmp_ucsbe(dot + 1, '\0') == 0) {
1239         lname = ucslen(src);
1240         lnname = (lname > maxchar) ? maxchar : lname;
1241         lext = lnext = 0;
1242     } else {
1243         lext = ucslen(dot + 1);
1244         lname = ucslen(src) - lext - 1;
1245         lnext = (ucslen(src) > maxchar + 1 && lext > 3)
1246                 ? (lname < maxchar - 3 ? maxchar - lname : 3)
1247                 : lext;
1248         lnname = (ucslen(src) > maxchar + 1) ? maxchar - lnext : lname;
1249     }
1250 
1251     if (lnname == 0 && lnext == 0) {
1252         goto ex;
1253     }
1254 
1255     pos = 0;
1256 
1257     /* Convert up to lnname characters of the filename. */
1258     for (i = 0; i < lnname; i++) {
1259         c = src[i];
1260         if (valid_j_char(c)) {
1261             dest[pos++] = c;
1262         } else {
1263             set_ucsbe(dest + pos, '_');
1264             pos++;
1265         }
1266     }
1267     if (pos > 0)
1268         iso_handle_split_utf16(dest + (pos - 1));
1269 
1270     if ((flag & 1) && lnext <= 0)
1271         goto is_done;
1272 
1273     set_ucsbe(dest + pos, '.');
1274     pos++;
1275 
1276     /* Convert up to lnext characters of the extension, if any. */
1277     for (i = 0; i < lnext; i++) {
1278         uint16_t c = src[lname + 1 + i];
1279         if (valid_j_char(c)) {
1280             dest[pos++] = c;
1281         } else {
1282             set_ucsbe(dest + pos, '_');
1283             pos++;
1284         }
1285     }
1286     iso_handle_split_utf16(dest + (pos - 1));
1287 
1288 is_done:;
1289     set_ucsbe(dest + pos, '\0');
1290     retval = ucsdup(dest);
1291 ex:;
1292     LIBISO_FREE_MEM(dest);
1293     return retval;
1294 }
1295 
1296 /* @param flag bit1= allow 103 characters rather than 64
1297 */
iso_j_dir_id(const uint16_t * src,int flag)1298 uint16_t *iso_j_dir_id(const uint16_t *src, int flag)
1299 {
1300     size_t len, i, maxchar = 64;
1301     uint16_t *dest = NULL, *retval = NULL;
1302                                                     /* was: 65 = 64 + 1 (\0) */
1303     LIBISO_ALLOC_MEM_VOID(dest, uint16_t, LIBISO_JOLIET_NAME_MAX);
1304 
1305     if (src == NULL) {
1306         goto ex;
1307     }
1308     if (flag & 2)
1309         maxchar = 103;
1310 
1311     len = ucslen(src);
1312     if (len > maxchar) {
1313         len = maxchar;
1314     }
1315     for (i = 0; i < len; i++) {
1316         uint16_t c = src[i];
1317         if (valid_j_char(c)) {
1318             dest[i] = c;
1319         } else {
1320             set_ucsbe(dest + i, '_');
1321         }
1322     }
1323     iso_handle_split_utf16(dest + (len - 1));
1324     set_ucsbe(dest + len, '\0');
1325     retval = ucsdup(dest);
1326 ex:
1327     LIBISO_FREE_MEM(dest);
1328     return retval;
1329 }
1330 
ucslen(const uint16_t * str)1331 size_t ucslen(const uint16_t *str)
1332 {
1333     size_t i;
1334 
1335     for (i = 0; str[i]; i++)
1336         ;
1337     return i;
1338 }
1339 
ucsrchr(const uint16_t * str,char c)1340 uint16_t *ucsrchr(const uint16_t *str, char c)
1341 {
1342     size_t len = ucslen(str);
1343 
1344     while (len-- > 0) {
1345         if (cmp_ucsbe(str + len, c) == 0) {
1346             return (uint16_t*)(str + len);
1347         }
1348     }
1349     return NULL;
1350 }
1351 
ucsdup(const uint16_t * str)1352 uint16_t *ucsdup(const uint16_t *str)
1353 {
1354     uint16_t *ret;
1355     size_t len = ucslen(str);
1356 
1357     ret = malloc(2 * (len + 1));
1358     if (ret == NULL)
1359         return NULL;
1360     if (ret != NULL) {
1361         memcpy(ret, str, 2 * (len + 1));
1362     }
1363     return ret;
1364 }
1365 
1366 /**
1367  * Although each character is 2 bytes, we actually compare byte-by-byte
1368  * because the words are big-endian. Comparing possibly swapped words
1369  * would make the sorting order depend on the machine byte order.
1370  */
ucscmp(const uint16_t * s1,const uint16_t * s2)1371 int ucscmp(const uint16_t *s1, const uint16_t *s2)
1372 {
1373     const uint8_t *s = (const uint8_t*)s1;
1374     const uint8_t *t = (const uint8_t*)s2;
1375     size_t len1 = ucslen(s1);
1376     size_t len2 = ucslen(s2);
1377     size_t i, len = MIN(len1, len2) * 2;
1378 
1379     for (i = 0; i < len; i++) {
1380         if (s[i] < t[i]) {
1381             return -1;
1382         } else if (s[i] > t[i]) {
1383             return 1;
1384         }
1385     }
1386 
1387     if (len1 < len2)
1388         return -1;
1389     else if (len1 > len2)
1390         return 1;
1391     return 0;
1392 }
1393 
ucscpy(uint16_t * dest,const uint16_t * src)1394 uint16_t *ucscpy(uint16_t *dest, const uint16_t *src)
1395 {
1396     size_t n = ucslen(src) + 1;
1397     memcpy(dest, src, n*2);
1398     return dest;
1399 }
1400 
ucsncpy(uint16_t * dest,const uint16_t * src,size_t n)1401 uint16_t *ucsncpy(uint16_t *dest, const uint16_t *src, size_t n)
1402 {
1403     n = MIN(n, ucslen(src) + 1);
1404     memcpy(dest, src, n*2);
1405     if (n >= 2)
1406         iso_handle_split_utf16(dest + (n - 2));
1407     return dest;
1408 }
1409 
str2d_char(const char * icharset,const char * input,char ** output)1410 int str2d_char(const char *icharset, const char *input, char **output)
1411 {
1412     int ret;
1413     char *ascii;
1414     size_t len, i;
1415 
1416     if (output == NULL) {
1417         return ISO_OUT_OF_MEM;
1418     }
1419 
1420     /** allow NULL input */
1421     if (input == NULL) {
1422         *output = NULL;
1423         return 0;
1424     }
1425 
1426     /* this checks for NULL parameters */
1427     ret = str2ascii(icharset, input, &ascii);
1428     if (ret < 0) {
1429         *output = NULL;
1430         return ret;
1431     }
1432 
1433     len = strlen(ascii);
1434 
1435     for (i = 0; i < len; ++i) {
1436         char c= toupper(ascii[i]);
1437         ascii[i] = valid_d_char(c) ? c : '_';
1438     }
1439 
1440     *output = ascii;
1441     return ISO_SUCCESS;
1442 }
1443 
str2a_char(const char * icharset,const char * input,char ** output)1444 int str2a_char(const char *icharset, const char *input, char **output)
1445 {
1446     int ret;
1447     char *ascii;
1448     size_t len, i;
1449 
1450     if (output == NULL) {
1451         return ISO_OUT_OF_MEM;
1452     }
1453 
1454     /** allow NULL input */
1455     if (input == NULL) {
1456         *output = NULL;
1457         return 0;
1458     }
1459 
1460     /* this checks for NULL parameters */
1461     ret = str2ascii(icharset, input, &ascii);
1462     if (ret < 0) {
1463         *output = NULL;
1464         return ret;
1465     }
1466 
1467     len = strlen(ascii);
1468 
1469     for (i = 0; i < len; ++i) {
1470         char c= toupper(ascii[i]);
1471         ascii[i] = valid_a_char(c) ? c : '_';
1472     }
1473 
1474     *output = ascii;
1475     return ISO_SUCCESS;
1476 }
1477 
iso_lsb(uint8_t * buf,uint32_t num,int bytes)1478 void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
1479 {
1480     int i;
1481 
1482     for (i = 0; i < bytes; ++i)
1483         buf[i] = (num >> (8 * i)) & 0xff;
1484 }
1485 
iso_lsb64(uint8_t * buf,uint64_t num)1486 void iso_lsb64(uint8_t *buf, uint64_t num)
1487 {
1488     int i;
1489 
1490     for (i = 0; i < 8; ++i)
1491         buf[i] = (num >> (8 * i)) & 0xff;
1492 }
1493 
iso_msb(uint8_t * buf,uint32_t num,int bytes)1494 void iso_msb(uint8_t *buf, uint32_t num, int bytes)
1495 {
1496     int i;
1497 
1498     for (i = 0; i < bytes; ++i)
1499         buf[bytes - 1 - i] = (num >> (8 * i)) & 0xff;
1500 }
1501 
iso_bb(uint8_t * buf,uint32_t num,int bytes)1502 void iso_bb(uint8_t *buf, uint32_t num, int bytes)
1503 {
1504     iso_lsb(buf, num, bytes);
1505     iso_msb(buf+bytes, num, bytes);
1506 }
1507 
1508 /* An alternative to iso_lsb() which advances the write pointer
1509 */
iso_lsb_to_buf(char ** wpt,uint32_t value,int bytes,int flag)1510 int iso_lsb_to_buf(char **wpt, uint32_t value, int bytes, int flag)
1511 {
1512     int b, bits;
1513 
1514     bits = bytes * 8;
1515     for (b = 0; b < bits; b += 8)
1516         *((unsigned char *) ((*wpt)++)) = (value >> b) & 0xff;
1517     return (1);
1518 }
1519 
iso_read_lsb(const uint8_t * buf,int bytes)1520 uint32_t iso_read_lsb(const uint8_t *buf, int bytes)
1521 {
1522     int i;
1523     uint32_t ret = 0;
1524 
1525     for (i=0; i<bytes; i++) {
1526         ret += ((uint32_t) buf[i]) << (i*8);
1527     }
1528     return ret;
1529 }
1530 
iso_read_msb(const uint8_t * buf,int bytes)1531 uint32_t iso_read_msb(const uint8_t *buf, int bytes)
1532 {
1533     int i;
1534     uint32_t ret = 0;
1535 
1536     for (i=0; i<bytes; i++) {
1537         ret += ((uint32_t) buf[bytes-i-1]) << (i*8);
1538     }
1539     return ret;
1540 }
1541 
iso_read_bb(const uint8_t * buf,int bytes,int * error)1542 uint32_t iso_read_bb(const uint8_t *buf, int bytes, int *error)
1543 {
1544     uint32_t v1 = iso_read_lsb(buf, bytes);
1545 
1546     if (error) {
1547         uint32_t v2 = iso_read_msb(buf + bytes, bytes);
1548         if (v1 != v2)
1549             *error = 1;
1550     }
1551     return v1;
1552 }
1553 
iso_read_lsb64(const uint8_t * buf)1554 uint64_t iso_read_lsb64(const uint8_t *buf)
1555 {
1556     int i;
1557     uint64_t ret = 0;
1558 
1559     for (i=0; i < 8; i++)
1560         ret += ((uint64_t) buf[i]) << (i * 8);
1561     return ret;
1562 }
1563 
iso_read_msb64(const uint8_t * buf)1564 uint64_t iso_read_msb64(const uint8_t *buf)
1565 {
1566     int i;
1567     uint64_t ret = 0;
1568 
1569     for (i=0; i < 8; i++)
1570         ret += ((uint64_t) buf[7 - i]) << (i * 8);
1571     return ret;
1572 }
1573 
iso_datetime_7(unsigned char * buf,time_t t,int always_gmt)1574 void iso_datetime_7(unsigned char *buf, time_t t, int always_gmt)
1575 {
1576     static int tzsetup = 0;
1577     int tzoffset;
1578     struct tm tm;
1579 
1580     if (!tzsetup) {
1581         tzset();
1582         tzsetup = 1;
1583     }
1584 
1585     memset(&tm, 0, sizeof(tm));
1586     tm.tm_isdst = -1;  /* some OSes change tm_isdst only if it is -1 */
1587     localtime_r(&t, &tm);
1588 
1589 #ifdef HAVE_TM_GMTOFF
1590     tzoffset = tm.tm_gmtoff / 60 / 15;
1591 #else
1592     if (tm.tm_isdst < 0)
1593         tm.tm_isdst = 0;
1594 #ifndef Libburnia_timezonE
1595 #define Libburnia_timezonE timezone
1596 #endif
1597  #if Libburnia_timezonE == 0
1598     always_gmt = 1;
1599  #endif
1600     tzoffset = ( - Libburnia_timezonE / 60 / 15 ) + 4 * tm.tm_isdst;
1601 #endif /* ! HAVE_TM_GMTOFF */
1602 
1603     if (tzoffset > 52 || tzoffset < -48 || always_gmt) {
1604         /* absurd timezone offset, represent time in GMT */
1605         gmtime_r(&t, &tm);
1606         tzoffset = 0;
1607     }
1608 
1609     if (tm.tm_year < 0) {
1610         tm.tm_year = 0;
1611         tm.tm_mon = 0;
1612         tm.tm_mday = 1;
1613         tm.tm_hour = 0;
1614         tm.tm_min = 0;
1615         tm.tm_sec = 0;
1616     } else if (tm.tm_year > 255) {
1617         tm.tm_year = 255;
1618         tm.tm_mon = 11;
1619         tm.tm_mday = 31;
1620         tm.tm_hour = 23;
1621         tm.tm_min = 59;
1622         tm.tm_sec = 59;
1623     }
1624     buf[0] = tm.tm_year;
1625     buf[1] = tm.tm_mon + 1;
1626     buf[2] = tm.tm_mday;
1627     buf[3] = tm.tm_hour;
1628     buf[4] = tm.tm_min;
1629     buf[5] = tm.tm_sec;
1630     buf[6] = tzoffset;
1631 }
1632 
iso_datetime_17(unsigned char * buf,time_t t,int always_gmt)1633 void iso_datetime_17(unsigned char *buf, time_t t, int always_gmt)
1634 {
1635     static int tzsetup = 0;
1636     static int tzoffset;
1637     struct tm tm;
1638 
1639     if (t == (time_t) - 1) {
1640         /* unspecified time */
1641         memset(buf, '0', 16);
1642         buf[16] = 0;
1643         return;
1644     }
1645 
1646     if (!tzsetup) {
1647         tzset();
1648         tzsetup = 1;
1649     }
1650 
1651     memset(&tm, 0, sizeof(tm));
1652     tm.tm_isdst = -1;  /* some OSes change tm_isdst only if it is -1 */
1653     localtime_r(&t, &tm);
1654 
1655     localtime_r(&t, &tm);
1656 
1657 #ifdef HAVE_TM_GMTOFF
1658     tzoffset = tm.tm_gmtoff / 60 / 15;
1659 #else
1660     if (tm.tm_isdst < 0)
1661         tm.tm_isdst = 0;
1662 #ifndef Libburnia_timezonE
1663 #define Libburnia_timezonE timezone
1664 #endif
1665  #if Libburnia_timezonE == 0
1666     always_gmt = 1;
1667  #endif
1668     tzoffset = ( - Libburnia_timezonE / 60 / 15 ) + 4 * tm.tm_isdst;
1669 #endif /* ! HAVE_TM_GMTOFF */
1670 
1671     if (tzoffset > 52 || tzoffset < -48 || always_gmt) {
1672         /* absurd timezone offset, represent time in GMT */
1673         gmtime_r(&t, &tm);
1674         tzoffset = 0;
1675     }
1676 
1677     if (tm.tm_year <= -1900) {
1678         strcpy((char *) buf, "00010101000000");
1679     } else if (tm.tm_year >= 8100) {
1680         strcpy((char *) buf, "99991231235959");
1681     } else {
1682         sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
1683         sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
1684         sprintf((char*)&buf[6], "%02d", tm.tm_mday);
1685         sprintf((char*)&buf[8], "%02d", tm.tm_hour);
1686         sprintf((char*)&buf[10], "%02d", tm.tm_min);
1687         sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
1688     }
1689     memcpy(&buf[14], "00", 2);
1690     buf[16] = tzoffset;
1691 
1692 }
1693 
1694 #ifndef HAVE_TIMEGM
1695 
1696 /* putenv is SVr4, POSIX.1-2001, 4.3BSD , setenv is 4.3BSD, POSIX.1-2001.
1697    So putenv is more widely available.
1698    Also, setenv spoils eventual putenv expectation of applications because
1699    putenv installs the original string which then may be altered from
1700    its owner. setenv installs a copy that may not be altered.
1701    Both are slow.
1702    Thus first try with a naive implementation that assumes no leap seconds.
1703    If it fails a test with gmtime() then use the slow function with mktime().
1704 */
1705 #define Libisofs_use_putenV yes
1706 
1707 static
env_timegm(struct tm * tm)1708 time_t env_timegm(struct tm *tm)
1709 {
1710     time_t ret;
1711     char *tz;
1712 
1713 #ifdef Libisofs_use_putenV
1714 
1715     static char unset_name[] = {"TZ"};
1716 
1717     tz = getenv("TZ");
1718     putenv("TZ=");
1719     tzset();
1720     ret = mktime(tm);
1721     if (tz != NULL) {
1722         /* tz is a pointer to the value part in a string of form "TZ="value */
1723         putenv(tz - 3);
1724     } else
1725         putenv(unset_name); /* not daring to submit constant */
1726     tzset();
1727 
1728 #else /* Libisofs_use_putenV */
1729 
1730     tz = getenv("TZ");
1731     setenv("TZ", "", 1);
1732     tzset();
1733     ret = mktime(tm);
1734     if (tz)
1735         setenv("TZ", tz, 1);
1736     else
1737         unsetenv("TZ");
1738     tzset();
1739 
1740 #endif /* ! Libisofs_use_putenV */
1741 
1742     return ret;
1743 }
1744 
1745 static
ts_is_leapyear(int tm_year)1746 int ts_is_leapyear(int tm_year) /* years since 1900 */
1747 {
1748   return ((tm_year % 4) == 0 && ((tm_year % 100) != 0 ||
1749                                  (tm_year % 400) == 100));
1750 }
1751 
1752 /* Fast implementation without leap seconds.
1753    Inspired by but not copied from code by Kungliga Tekniska Hgskolan
1754    (Royal Institute of Technology, Stockholm, Sweden),
1755    which was modified by Andrew Tridgell for Samba4.
1756    I claim own copyright 2011 Thomas Schmitt <scdbackup@gmx.net>.
1757 */
1758 static
ts_timegm(struct tm * tm)1759 time_t ts_timegm(struct tm *tm)
1760 {
1761     time_t ret;
1762     static int month_length_normal[12] =
1763                 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1764     static int month_length_leap[12] =
1765                 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1766     int *month_length_pt;
1767     int years, i;
1768 
1769     ret = 0;
1770 
1771     years = tm->tm_year - 70; /* Years since 1970 */
1772     if (years < 0)
1773         return ret;
1774     for (i = 0; i < years; i++) {
1775         ret += 365 * 86400;
1776         if (ts_is_leapyear(70 + i))
1777             ret += 86400;
1778     }
1779     if (ts_is_leapyear(tm->tm_year))
1780         month_length_pt = month_length_leap;
1781     else
1782         month_length_pt = month_length_normal;
1783     for (i = 0; i < tm->tm_mon; i++)
1784         ret += month_length_pt[i] * 86400;
1785     ret += (tm->tm_mday - 1) * 86400;
1786     ret += tm->tm_hour * 3600;
1787     ret += tm->tm_min * 60;
1788     ret += tm->tm_sec;
1789     return ret;
1790 }
1791 
1792 static
timegm(struct tm * tm)1793 time_t timegm(struct tm *tm)
1794 {
1795     time_t raw_t, ret;
1796     struct tm *test_tm, input_tm_copy;
1797 
1798     /* Beware of ill effects if tm is result of gmtime() or alike */
1799     memcpy(&input_tm_copy, tm, sizeof(struct tm));
1800 
1801     /* Try without leapseconds (which are rarely implemented, as it seems) */
1802     raw_t = ts_timegm(tm);
1803     if (raw_t == 0)
1804         return raw_t;
1805 
1806     /* Check whether this translates back to the input values */
1807     test_tm = gmtime(&raw_t);
1808     if (input_tm_copy.tm_sec == test_tm->tm_sec &&
1809         input_tm_copy.tm_min == test_tm->tm_min &&
1810         input_tm_copy.tm_hour == test_tm->tm_hour &&
1811         input_tm_copy.tm_mday == test_tm->tm_mday &&
1812         input_tm_copy.tm_mon == test_tm->tm_mon &&
1813         input_tm_copy.tm_year == test_tm->tm_year) {
1814         ret = raw_t;
1815     } else {
1816         /* Mismatch. Use slow method around mktime() */
1817         ret = env_timegm(&input_tm_copy);
1818     }
1819     return ret;
1820 }
1821 
1822 
1823 #endif /* ! HAVE_TIMEGM */
1824 
1825 
iso_datetime_read_7(const uint8_t * buf)1826 time_t iso_datetime_read_7(const uint8_t *buf)
1827 {
1828     struct tm tm;
1829 
1830     tm.tm_year = buf[0];
1831     tm.tm_mon = buf[1] - 1;
1832     tm.tm_mday = buf[2];
1833     tm.tm_hour = buf[3];
1834     tm.tm_min = buf[4];
1835     tm.tm_sec = buf[5];
1836     tm.tm_isdst = 0;
1837 
1838     return timegm(&tm) - ((int8_t)buf[6]) * 60 * 15;
1839 }
1840 
iso_datetime_read_17(const uint8_t * buf)1841 time_t iso_datetime_read_17(const uint8_t *buf)
1842 {
1843     struct tm tm;
1844 
1845     sscanf((char*)&buf[0], "%4d", &tm.tm_year);
1846     sscanf((char*)&buf[4], "%2d", &tm.tm_mon);
1847     sscanf((char*)&buf[6], "%2d", &tm.tm_mday);
1848     sscanf((char*)&buf[8], "%2d", &tm.tm_hour);
1849     sscanf((char*)&buf[10], "%2d", &tm.tm_min);
1850     sscanf((char*)&buf[12], "%2d", &tm.tm_sec);
1851     tm.tm_year -= 1900;
1852     tm.tm_mon -= 1;
1853     tm.tm_isdst = 0;
1854 
1855     return timegm(&tm) - ((int8_t)buf[16]) * 60 * 15;
1856 }
1857 
1858 /**
1859  * Check whether the caller process has read access to the given local file.
1860  *
1861  * @return
1862  *     1 on success (i.e, the process has read access), < 0 on error
1863  *     (including ISO_FILE_ACCESS_DENIED on access denied to the specified file
1864  *     or any directory on the path).
1865  */
iso_eaccess(const char * path)1866 int iso_eaccess(const char *path)
1867 {
1868     int access;
1869 
1870     /* use non standard eaccess when available, open() otherwise */
1871 #ifdef HAVE_EACCESS
1872     access = !eaccess(path, R_OK);
1873 #else
1874     int fd = open(path, O_RDONLY);
1875     if (fd != -1) {
1876         close(fd);
1877         access = 1;
1878     } else {
1879         access = 0;
1880     }
1881 #endif
1882 
1883     if (!access) {
1884         int err;
1885 
1886         /* error, choose an appropriate return code */
1887         switch (errno) {
1888         case EACCES:
1889             err = ISO_FILE_ACCESS_DENIED;
1890             break;
1891         case ENOTDIR:
1892         case ENAMETOOLONG:
1893         case ELOOP:
1894             err = ISO_FILE_BAD_PATH;
1895             break;
1896         case ENOENT:
1897             err = ISO_FILE_DOESNT_EXIST;
1898             break;
1899         case EFAULT:
1900         case ENOMEM:
1901             err = ISO_OUT_OF_MEM;
1902             break;
1903         default:
1904             err = ISO_FILE_ERROR;
1905             break;
1906         }
1907         return err;
1908     }
1909     return ISO_SUCCESS;
1910 }
1911 
iso_util_strcopy(const char * buf,size_t len)1912 char *iso_util_strcopy(const char *buf, size_t len)
1913 {
1914     char *str;
1915 
1916     str = calloc(len + 1, 1);
1917     if (str == NULL) {
1918         return NULL;
1919     }
1920     strncpy(str, buf, len);
1921     str[len] = '\0';
1922     return str;
1923 }
1924 
iso_util_strcopy_untail(const char * buf,size_t len_in)1925 char *iso_util_strcopy_untail(const char *buf, size_t len_in)
1926 {
1927     char *str;
1928     int len;
1929 
1930     str = iso_util_strcopy(buf, len_in);
1931     if (str == NULL) {
1932         return NULL;
1933     }
1934     /* remove trailing spaces */
1935     for (len = len_in - 1; len >= 0; --len) {
1936         if (str[len] != ' ')
1937     break;
1938         str[len] = 0;
1939     }
1940     return str;
1941 }
1942 
1943 /**
1944  * Copy up to \p max characters from \p src to \p dest. If \p src has less than
1945  * \p max characters, we pad dest with " " characters.
1946  */
strncpy_pad(char * dest,const char * src,size_t max)1947 void strncpy_pad(char *dest, const char *src, size_t max)
1948 {
1949     size_t len, i;
1950 
1951     if (src != NULL) {
1952         len = MIN(strlen(src), max);
1953         for (i = 0; i < len; ++i)
1954             dest[i] = src[i];
1955     } else {
1956         len = 0;
1957     }
1958 
1959     for (i = len; i < max; ++i)
1960         dest[i] = ' ';
1961 }
1962 
ucs2str(const char * buf,size_t len)1963 char *ucs2str(const char *buf, size_t len)
1964 {
1965     size_t outbytes, inbytes;
1966     char *str, *src, *out = NULL, *retval = NULL;
1967     struct iso_iconv_handle conv;
1968     int conv_ret;
1969     size_t n;
1970 
1971     inbytes = len;
1972 
1973     outbytes = (inbytes+1) * MB_LEN_MAX;
1974 
1975     /* ensure enough space */
1976     out = calloc(outbytes, 1);
1977     if (out == NULL)
1978         return NULL;
1979 
1980     /* convert to local charset */
1981     conv_ret = iso_iconv_open(&conv, iso_get_local_charset(0), "UCS-2BE", 0);
1982     if (conv_ret <= 0) {
1983         goto ex;
1984     }
1985     src = (char *)buf;
1986     str = (char *)out;
1987 
1988     n = iso_iconv(&conv, &src, &inbytes, &str, &outbytes, 0);
1989     iso_iconv_close(&conv, 0);
1990     if (n == (size_t) -1) {
1991         /* error */
1992         goto ex;
1993     }
1994     *str = '\0';
1995 
1996     /* remove trailing spaces */
1997     for (len = strlen(out) - 1; out[len] == ' ' && len > 0; --len)
1998         out[len] = '\0';
1999 
2000     retval = strdup(out);
2001 
2002 ex:;
2003     if (out != NULL)
2004         free(out);
2005     return retval;
2006 }
2007 
iso_lib_version(int * major,int * minor,int * micro)2008 void iso_lib_version(int *major, int *minor, int *micro)
2009 {
2010 
2011     *major = iso_lib_header_version_major;
2012     *minor = iso_lib_header_version_minor;
2013     *micro = iso_lib_header_version_micro;
2014 
2015 /* No more: values from version.h generated from version.h.in and
2016             macro values defined in configure.ac
2017 
2018     *major = LIBISOFS_MAJOR_VERSION;
2019     *minor = LIBISOFS_MINOR_VERSION;
2020     *micro = LIBISOFS_MICRO_VERSION;
2021 */
2022 }
2023 
iso_lib_is_compatible(int major,int minor,int micro)2024 int iso_lib_is_compatible(int major, int minor, int micro)
2025 {
2026     int cmajor, cminor, cmicro;
2027 
2028     /* for now, the rule is that library is compatible if requested
2029      * version is lower */
2030     iso_lib_version(&cmajor, &cminor, &cmicro);
2031 
2032     return cmajor > major
2033            || (cmajor == major
2034                && (cminor > minor
2035                    || (cminor == minor && cmicro >= micro)));
2036 }
2037 
iso_init_locale(int flag)2038 int iso_init_locale(int flag)
2039 {
2040     setlocale(LC_CTYPE, "");
2041     return 1;
2042 }
2043 
2044 
iso_util_encode_len_bytes(uint32_t data,char * buffer,int data_len,int * result_len,int flag)2045 int iso_util_encode_len_bytes(uint32_t data, char *buffer, int data_len,
2046                               int *result_len, int flag)
2047 {
2048     uint32_t x;
2049     int i, l;
2050     char *wpt = buffer;
2051 
2052     if (data_len <= 0) {
2053         x = data;
2054         for (i = 0; i < 4 && x != 0; i++)
2055             x = x >> 8;
2056         l = i;
2057         if (l == 0)
2058             l = 1;
2059     } else
2060         l = data_len;
2061     *((unsigned char *) (wpt++)) = l;
2062     for (i = 0; i < l; i++)
2063         *((unsigned char *) (wpt++)) = data >> (8 * (l - i - 1));
2064     *result_len = l + 1;
2065     return ISO_SUCCESS;
2066 }
2067 
2068 
iso_util_decode_len_bytes(uint32_t * data,char * buffer,int * data_len,int buffer_len,int flag)2069 int iso_util_decode_len_bytes(uint32_t *data, char *buffer, int *data_len,
2070                               int buffer_len, int flag)
2071 {
2072     int i;
2073 
2074     *data = 0;
2075     *data_len = ((unsigned char *) buffer)[0];
2076     if (*data_len > buffer_len - 1)
2077         *data_len = buffer_len - 1;
2078     for (i = 1; i <= *data_len; i++)
2079         *data = (*data << 8) | ((unsigned char *) buffer)[i];
2080     return ISO_SUCCESS;
2081 }
2082 
2083 
iso_util_dec_to_uint32(char * dec,uint32_t * value,int flag)2084 int iso_util_dec_to_uint32(char *dec, uint32_t *value, int flag)
2085 {
2086     double num;
2087 
2088     sscanf(dec, "%lf", &num);
2089     if (num < 0 || num > 4294967295.0)
2090         return 0;
2091     *value = num;
2092     return 1;
2093 }
2094 
2095 
iso_util_bin_to_hex(char * target,uint8_t * bytes,int num_bytes,int flag)2096 int iso_util_bin_to_hex(char *target, uint8_t *bytes, int num_bytes, int flag)
2097 {
2098     int i;
2099 
2100     for (i = 0; i < num_bytes; i++)
2101         sprintf(target + 2 * i, "%-2.2x", bytes[i]);
2102     target[2 * num_bytes] = 0;
2103     return 1;
2104 }
2105 
2106 
iso_util_hex_to_bin(char * hex,char * bin,int bin_size,int * bin_count,int flag)2107 int iso_util_hex_to_bin(char *hex, char *bin, int bin_size, int *bin_count,
2108                         int flag)
2109 {
2110     static char *allowed = {"0123456789ABCDEFabcdef"};
2111     char b[3];
2112     int i;
2113     unsigned int u;
2114 
2115     b[2] = 0;
2116     *bin_count = 0;
2117     for (i = 0; i < bin_size; i++) {
2118         b[0] = hex[2 * i];
2119         b[1] = hex[2 * i + 1];
2120         if (strchr(allowed, b[0]) == NULL || strchr(allowed, b[1]) == NULL)
2121     break;
2122         sscanf(b, "%x", &u);
2123         ((unsigned char *) bin)[i] = u;
2124         (*bin_count)++;
2125     }
2126     return (*bin_count > 0);
2127 }
2128 
2129 
iso_util_tag_magic(int tag_type,char ** tag_magic,int * len,int flag)2130 int iso_util_tag_magic(int tag_type, char **tag_magic, int *len, int flag)
2131 {
2132     static char *magic[] = {"",
2133         "libisofs_checksum_tag_v1",
2134         "libisofs_sb_checksum_tag_v1",
2135         "libisofs_tree_checksum_tag_v1",
2136         "libisofs_rlsb32_checksum_tag_v1"};
2137     static int magic_len[]= {0, 24, 27, 29, 31};
2138     static int magic_max = 4;
2139 
2140     *tag_magic = NULL;
2141     *len = 0;
2142     if (tag_type < 0 || tag_type > magic_max)
2143         return ISO_WRONG_ARG_VALUE;
2144     *tag_magic = magic[tag_type];
2145     *len = magic_len[tag_type];
2146     return magic_max;
2147 }
2148 
2149 
iso_util_decode_md5_tag(char data[2048],int * tag_type,uint32_t * pos,uint32_t * range_start,uint32_t * range_size,uint32_t * next_tag,char md5[16],int flag)2150 int iso_util_decode_md5_tag(char data[2048], int *tag_type, uint32_t *pos,
2151                             uint32_t *range_start, uint32_t *range_size,
2152                             uint32_t *next_tag, char md5[16], int flag)
2153 {
2154     int ret, bin_count, i, mode, magic_first = 1, magic_last = 4;
2155     int magic_len = 0;
2156     char *cpt, self_md5[16], tag_md5[16], *tag_magic;
2157     void *ctx = NULL;
2158 
2159     *next_tag = 0;
2160     mode = flag & 255;
2161     if (mode > magic_last)
2162         return ISO_WRONG_ARG_VALUE;
2163     if (mode > 0)
2164         magic_first = magic_last = mode;
2165     for (i = magic_first; i <= magic_last; i++) {
2166         iso_util_tag_magic(i, &tag_magic, &magic_len, 0);
2167         if (strncmp(data, tag_magic, magic_len) == 0)
2168     break;
2169     }
2170     if (i > magic_last )
2171         return 0;
2172     *tag_type = i;
2173     cpt = data + magic_len + 1;
2174     if (strncmp(cpt, "pos=", 4) != 0)
2175         return 0;
2176     cpt+= 4;
2177     ret = iso_util_dec_to_uint32(cpt, pos, 0);
2178     if (ret <= 0)
2179         return 0;
2180     cpt = strstr(cpt, "range_start=");
2181     if (cpt == NULL)
2182         return(0);
2183     ret = iso_util_dec_to_uint32(cpt + 12, range_start, 0);
2184     if (ret <= 0)
2185         return 0;
2186     cpt = strstr(cpt, "range_size=");
2187     if (cpt == NULL)
2188         return(0);
2189     ret = iso_util_dec_to_uint32(cpt + 11, range_size, 0);
2190     if (ret <= 0)
2191         return 0;
2192     if (*tag_type == 2 || *tag_type == 3) {
2193         cpt = strstr(cpt, "next=");
2194         if (cpt == NULL)
2195             return(0);
2196         ret = iso_util_dec_to_uint32(cpt + 5, next_tag, 0);
2197         if (ret <= 0)
2198             return 0;
2199     } else if (*tag_type == 4) {
2200         cpt = strstr(cpt, "session_start=");
2201         if (cpt == NULL)
2202             return(0);
2203         ret = iso_util_dec_to_uint32(cpt + 14, next_tag, 0);
2204         if (ret <= 0)
2205             return 0;
2206     }
2207     cpt = strstr(cpt, "md5=");
2208     if (cpt == NULL)
2209         return(0);
2210     ret = iso_util_hex_to_bin(cpt + 4, md5, 16, &bin_count, 0);
2211     if (ret <= 0 || bin_count != 16)
2212         return 0;
2213 
2214     cpt += 4 + 32;
2215     ret = iso_md5_start(&ctx);
2216     if (ret < 0)
2217         return ret;
2218     iso_md5_compute(ctx, data , cpt - data);
2219     iso_md5_end(&ctx, tag_md5);
2220     cpt = strstr(cpt, "self=");
2221     if (cpt == NULL)
2222         return(0);
2223     ret = iso_util_hex_to_bin(cpt + 5, self_md5, 16, &bin_count, 0);
2224     if (ret <= 0 || bin_count != 16)
2225         return 0;
2226     for(i= 0; i < 16; i++)
2227       if(self_md5[i] != tag_md5[i])
2228         return ISO_MD5_AREA_CORRUPTED;
2229     if (*(cpt + 5 + 32) != '\n')
2230         return 0;
2231     return(1);
2232 }
2233 
2234 
iso_util_eval_md5_tag(char * block,int desired,uint32_t lba,void * ctx,uint32_t ctx_start_lba,int * tag_type,uint32_t * next_tag,int flag)2235 int iso_util_eval_md5_tag(char *block, int desired, uint32_t lba,
2236                           void *ctx, uint32_t ctx_start_lba,
2237                           int *tag_type, uint32_t *next_tag, int flag)
2238 {
2239     int decode_ret, ret;
2240     char md5[16], cloned_md5[16];
2241     uint32_t pos, range_start, range_size;
2242     void *cloned_ctx = NULL;
2243 
2244     *tag_type = 0;
2245     decode_ret = iso_util_decode_md5_tag(block, tag_type, &pos,
2246                                   &range_start, &range_size, next_tag, md5, 0);
2247     if (decode_ret != 1 && decode_ret != (int) ISO_MD5_AREA_CORRUPTED)
2248         return 0;
2249     if (*tag_type > 30)
2250         goto unexpected_type;
2251 
2252     if (decode_ret == (int) ISO_MD5_AREA_CORRUPTED) {
2253         ret = decode_ret;
2254         goto ex;
2255     } else if (!((1 << *tag_type) & desired)) {
2256 unexpected_type:;
2257         iso_msg_submit(-1, ISO_MD5_TAG_UNEXPECTED, 0, NULL);
2258         ret = 0;
2259         goto ex;
2260     } else if (pos != lba) {
2261         if (*tag_type == 2) { /* Superblock tag */
2262             if (lba < 32) {
2263                 /* Check whether this is a copied superblock */
2264                 range_start -= (off_t) pos - (off_t) lba;
2265                 if (range_start != ctx_start_lba) {
2266 
2267                     /* >>> check for matching MD5 ? */;
2268 
2269                     ret = ISO_MD5_TAG_MISPLACED;
2270                 } else
2271                     ret = ISO_MD5_TAG_COPIED;
2272                 goto ex;
2273             }
2274         }
2275         ret = ISO_MD5_TAG_MISPLACED;
2276         goto ex;
2277     } else if (range_start != ctx_start_lba) {
2278         ret = ISO_MD5_TAG_MISPLACED;
2279         goto ex;
2280     }
2281     ret = iso_md5_clone(ctx, &cloned_ctx);
2282     if (ret < 0)
2283         goto ex;
2284     iso_md5_end(&cloned_ctx, cloned_md5);
2285     if (! iso_md5_match(cloned_md5, md5)) {
2286         ret = ISO_MD5_TAG_MISMATCH;
2287         goto ex;
2288     }
2289     ret = 1;
2290 ex:;
2291     if (ret < 0)
2292         iso_msg_submit(-1, ret, 0, NULL);
2293     return ret;
2294 }
2295 
2296 
iso_alloc_mem(size_t size,size_t count,int flag)2297 void *iso_alloc_mem(size_t size, size_t count, int flag)
2298 {
2299     void *pt;
2300 
2301     pt = calloc(size, count);
2302     if(pt == NULL)
2303 	iso_msg_submit(-1, ISO_OUT_OF_MEM, 0, "Out of virtual memory");
2304     return pt;
2305 }
2306 
2307 
iso_ntohs(uint16_t v)2308 uint16_t iso_ntohs(uint16_t v)
2309 {
2310     return iso_read_msb((uint8_t *) &v, 2);
2311 }
2312 
iso_htons(uint16_t v)2313 uint16_t iso_htons(uint16_t v)
2314 {
2315     uint16_t ret;
2316 
2317     iso_msb((uint8_t *) &ret, (uint32_t) v, 2);
2318 
2319     return ret;
2320 }
2321 
2322 
2323 /* If an UTF-16 surrogate pair was split : Change to UTF-16 '_'.
2324    (UCS-2 is promised to reserve 0xd800 to 0xdbff for UTF-16).
2325 */
iso_handle_split_utf16(uint16_t * utf_word)2326 void iso_handle_split_utf16(uint16_t *utf_word)
2327 {
2328     unsigned char *hb;
2329 
2330     hb = (unsigned char *) utf_word;
2331     if ((hb[0] & 0xfc) == 0xd8)
2332         set_ucsbe(utf_word, '_');
2333 }
2334 
2335 
iso_clone_mem(char * in,char ** out,size_t size)2336 int iso_clone_mem(char *in, char **out, size_t size)
2337 {
2338     if (in == NULL) {
2339         *out = NULL;
2340         return 1;
2341     }
2342     if (size == 0)
2343         size = strlen(in) + 1;
2344     *out = calloc(1, size);
2345     if (*out == NULL)
2346         return ISO_OUT_OF_MEM;
2347     memcpy(*out, in, size);
2348     return ISO_SUCCESS;
2349 }
2350 
2351 
iso_clone_mgtd_mem(char * in,char ** out,size_t size)2352 int iso_clone_mgtd_mem(char *in, char **out, size_t size)
2353 {
2354     if (*out != NULL)
2355         free(*out);
2356     return iso_clone_mem(in, out, size);
2357 }
2358 
2359 
2360 /** Convert a text into a number of type double and multiply it by unit code
2361     [kmgt] (2^10 to 2^40) or [s] (2048) or [d] (512).
2362     (Also accepts capital letters.)
2363     @param text Input like "42", "223062s", "3m" or "-1g"
2364     @param flag Bitfield for control purposes:
2365                 bit0= return -1 rather than 0 on failure
2366                 bit1= if scaled then compute the last byte of the last unit
2367     @return The derived value
2368 */
iso_scanf_io_size(char * text,int flag)2369 off_t iso_scanf_io_size(char *text, int flag)
2370 {
2371     int c;
2372     off_t ret = 0, fac = 1;
2373     char *rpt;
2374 
2375     for (rpt = text; *rpt >= '0' && *rpt <= '9'; rpt++)
2376         ret = ret * 10 + (*rpt - '0');
2377     if (rpt == text)
2378         return (off_t) (flag & 1 ? -1 : 0);
2379     c = *rpt;
2380     if (c=='k' || c=='K')
2381         fac = 1024;
2382     else if (c=='m' || c=='M')
2383         fac = 1024 * 1024;
2384     else if (c=='g' || c=='G')
2385         fac = 1024 * 1024 * 1024;
2386     else if (c=='t' || c=='T')
2387         fac = ((off_t) 1024) * 1024 * 1024 * 1024;
2388     else if (c=='s' || c=='S')
2389         fac = 2048;
2390     else if (c=='d' || c=='D')
2391         fac = 512;
2392     ret *= fac;
2393     if (flag & 2)
2394         ret += fac - 1;
2395     return ret;
2396 }
2397 
2398 
2399 /* Find backward from idx the start byte of a possible UTF-8 character.
2400      https://en.wikipedia.org/wiki/UTF-8#Description
2401 */
2402 static
find_utf8_start(char * name,int idx,int flag)2403 int find_utf8_start(char *name, int idx, int flag)
2404 {
2405     unsigned char *uname, uch;
2406     int i;
2407 
2408     uname= (unsigned char *) name;
2409     if ((uname[idx] & 0xc0) != 0x80)
2410         return idx;                                /* not an UTF-8 tail byte */
2411     for (i = 0; i < 5 && idx - 1 - i >= 0; i++) {                                                                           /* up to deprecated 6-byte codes */
2412         uch = uname[idx - 1 - i];
2413         if ((uch & 0xe0) == 0xc0 || (uch & 0xf0) == 0xe0 ||
2414             (uch & 0xf8) == 0xf0 || (uch & 0xfc) == 0xf8 ||
2415             (uch & 0xfe) == 0xfc)
2416             return (idx - 1 - i);                  /* UTF-8 start byte found */
2417         if ((uch & 0xc0) != 0x80)
2418           return idx;                 /* not an UTF-8 tail byte, so no UTF-8 */
2419     }
2420     return idx;                                      /* no UTF-8 start found */
2421 }
2422 
2423 /* @param flag bit0= do not issue warning message
2424 */
iso_truncate_rr_name(int truncate_mode,int truncate_length,char * name,int flag)2425 int iso_truncate_rr_name(int truncate_mode, int truncate_length,
2426                          char *name, int flag)
2427 {
2428     int neck, goal, ret, l, i;
2429     static int hash_size = 32;
2430     void *ctx = NULL;
2431     char hashval[16];
2432 
2433     l = strlen(name);
2434     if (l <= truncate_length)
2435         return ISO_SUCCESS;
2436     if (truncate_mode == 0)
2437         return ISO_RR_NAME_TOO_LONG;
2438 
2439     /* Compute hash */
2440     ret = iso_md5_start(&ctx);
2441     if (ret < 0)
2442         goto ex;
2443     ret = iso_md5_compute(ctx, name, l > 4095 ? 4095 : l);
2444     if (ret < 0)
2445         goto ex;
2446     ret = iso_md5_end(&ctx, hashval);
2447     if (ret < 0)
2448         goto ex;
2449 
2450     if (!(flag & 1))
2451         iso_msg_submit(-1, ISO_RR_NAME_TRUNCATED, 0,
2452                      "File name had to be truncated and MD5 marked: %s", name);
2453 
2454     /* Avoid to produce incomplete UTF-8 characters */
2455     goal = truncate_length - hash_size - 1;
2456     neck = find_utf8_start(name, goal, 0);
2457     for (; neck < goal; neck++)
2458         name[neck] = '_';
2459 
2460     /* Write colon and hash text over end of truncated name */
2461     name[goal] = ':';
2462     goal++;
2463     for (i = 0; goal < truncate_length - 1 && i < hash_size / 2; goal += 2) {
2464         sprintf(name + goal, "%2.2x", *((unsigned char *) (hashval + i)));
2465         i++;
2466     }
2467     name[truncate_length] = 0;
2468 
2469     ret = ISO_SUCCESS;
2470 ex:;
2471     if (ctx != NULL)
2472         iso_md5_end(&ctx, hashval);
2473     return ret;
2474 }
2475 
2476 /* API */
iso_truncate_leaf_name(int mode,int length,char * name,int flag)2477 int iso_truncate_leaf_name(int mode, int length, char *name, int flag)
2478 {
2479     int ret;
2480 
2481     if (mode < 0 || mode > 1)
2482         return ISO_WRONG_ARG_VALUE;
2483     if (length < 64 || length > LIBISOFS_NODE_NAME_MAX)
2484         return ISO_WRONG_ARG_VALUE;
2485     ret = iso_truncate_rr_name(mode, length, name, 1);
2486     return ret;
2487 }
2488 
2489 /* API */
2490 /* @param flag bit0= *now contains the time to be set as nowtime override
2491                bit1= disable the nowtime override
2492    @return 1= *now is not overridden , 2= *now is overridden
2493 */
iso_nowtime(time_t * now,int flag)2494 int iso_nowtime(time_t *now, int flag)
2495 {
2496     static int now_time_overridden = 0;
2497     static time_t now_time_override = 0;
2498 
2499     if (flag & 1) {
2500         now_time_overridden = 1;
2501         now_time_override = *now;
2502     }
2503     if (flag & 2) {
2504         now_time_overridden = 0;
2505     }
2506     *now = time(NULL);
2507     if (!now_time_overridden)
2508         return 1;
2509     *now = now_time_override;
2510     return 2;
2511 }
2512 
2513