"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/util.c" (30 Jan 2021, 63924 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "util.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    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
   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
   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
  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 
  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 */
  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 */
  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 
  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 
  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 
  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
  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 
  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
  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
  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 
  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 
  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 
  806 static int valid_d_char(char c)
  807 {
  808     return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
  809 }
  810 
  811 static int valid_a_char(char c)
  812 {
  813     return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') || 
  814            (c >= 'A' && c <= 'Z') || (c == '_');
  815 }
  816 
  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 */
  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
  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 
  882 char *iso_1_dirid(const char *src, int relaxed)
  883 {
  884     return iso_dirid(src, 8, relaxed);
  885 }
  886 
  887 char *iso_2_dirid(const char *src)
  888 {
  889     return iso_dirid(src, 31, 0);
  890 }
  891 
  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 
  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  */
 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  */
 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 */
 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 */
 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 
 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 
 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 
 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  */
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 */
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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
 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
 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
 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
 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 
 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 
 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  */
 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 
 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 
 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  */
 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 
 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 
 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 
 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 
 2038 int iso_init_locale(int flag)
 2039 {
 2040     setlocale(LC_CTYPE, "");
 2041     return 1;
 2042 }
 2043 
 2044 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 2308 uint16_t iso_ntohs(uint16_t v)
 2309 {
 2310     return iso_read_msb((uint8_t *) &v, 2);
 2311 }
 2312 
 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 */
 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 
 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 
 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 */
 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
 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 */
 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 */
 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 */
 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