~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to libatalk/unicode/charcnv.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2009-09-09 23:43:27 UTC
  • mfrom: (8.2.5 sid)
  • Revision ID: james.westby@ubuntu.com-20090909234327-dhgxhuanxheto4x8
Tags: 2.0.4-2
* Update copyright hints.
* Lower policy compliance to 3.8.0 (uncertain about sysv script
  requirements in 3.8.1).
* Fix order of db upgrade commands in README.Debian. Closes:
  bug#533344, thanks (again) to Itai Seggev.
* Update package-relations.mk: Cleanup unversioned+versioned
  dependency mix. Improve whitespace cleanup. Rewrite and silence
  applying dependencies.
* Fix and improve README.Debian section on recompiling with OpenSSL,
  thanks to Gijs Hillenius and others.

Show diffs side-by-side

added added

removed removed

Lines of Context:
316
316
        char* o_save = outbuf;
317
317
        atalk_iconv_t descriptor;
318
318
 
319
 
        if (srclen == (size_t)-1)
320
 
                srclen = strlen(src)+1;
 
319
        /* Fixed based on Samba 3.0.6 */
 
320
        if (srclen == (size_t)-1) {
 
321
                if (from == CH_UCS2) {
 
322
                        srclen = (strlen_w((const ucs2_t *)src)+1) * 2;
 
323
                } else {
 
324
                        srclen = strlen((const char *)src)+1;
 
325
                }
 
326
        }
 
327
 
321
328
 
322
329
        lazy_initialize_conv();
323
330
 
636
643
        return convert_string_allocate(ch, CH_UCS2, src, src_len, (char**) dest);       
637
644
}
638
645
 
639
 
/**
 
646
/** -----------------------------------
640
647
 * Copy a string from a charset_t char* src to a UTF-8 destination, allocating a buffer
641
648
 *
642
649
 * @param dest always set at least to NULL 
652
659
        return convert_string_allocate(ch, CH_UTF8, src, src_len, dest);        
653
660
}
654
661
 
655
 
/**
 
662
/** -----------------------------------
656
663
 * Copy a string from a UCS2 src to a unix char * destination, allocating a buffer
657
664
 *
658
665
 * @param dest always set at least to NULL 
666
673
        return convert_string(CH_UCS2, ch, src, src_len, dest, destlen);        
667
674
}
668
675
 
669
 
 
 
676
/* --------------------------------- */
670
677
size_t ucs2_to_charset_allocate(charset_t ch, char **dest, const ucs2_t *src)
671
678
{
672
679
        size_t src_len = (strlen_w(src)) * sizeof(ucs2_t);
674
681
        return convert_string_allocate(CH_UCS2, ch, src, src_len, dest);        
675
682
}
676
683
 
677
 
/**
 
684
/** ---------------------------------
678
685
 * Copy a string from a UTF-8 src to a unix char * destination, allocating a buffer
679
686
 *
680
687
 * @param dest always set at least to NULL 
779
786
 * Flags:
780
787
 *              CONV_UNESCAPEHEX:        ':XX' will be converted to an UCS2 character
781
788
 *              CONV_IGNORE:             return the first convertable characters.
 
789
 *              CONV_FORCE:      force convertion
782
790
 * FIXME:
783
791
 *              This will *not* work if the destination charset is not multibyte, i.e. UCS2->UCS2 will fail
784
792
 *              The (un)escape scheme is not compatible to the old cap style escape. This is bad, we need it 
785
793
 *              for e.g. HFS cdroms.
786
794
 */
787
795
 
788
 
static size_t pull_charset_flags (charset_t from_set, charset_t cap_charset, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
 
796
static size_t pull_charset_flags (charset_t from_set, charset_t cap_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
789
797
{
790
 
        size_t i_len, o_len, hlen;
791
 
        size_t retval, j = 0;
792
 
        const char* inbuf = (const char*)src;
793
 
        char* outbuf = (char*)dest;
794
 
        atalk_iconv_t descriptor;
795
 
        atalk_iconv_t descriptor_cap;
796
 
        char *s;
797
 
        char h[MAXPATHLEN];
798
 
        const char *h_buf;
799
 
 
800
 
        if (srclen == (size_t)-1)
801
 
                srclen = strlen(src)+1;
802
 
 
803
 
        lazy_initialize_conv();
804
 
 
805
 
        descriptor = conv_handles[from_set][CH_UCS2];
806
 
        descriptor_cap = conv_handles[cap_charset][CH_UCS2];
807
 
 
808
 
        if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
809
 
                return (size_t) -1;
810
 
        }
811
 
 
812
 
        i_len=srclen;
813
 
        o_len=destlen;
814
 
        
815
 
conversion_loop:
816
 
        if ( flags && (*flags & CONV_UNESCAPEHEX)) {
817
 
                if ( NULL != (s = strchr ( inbuf, ':'))) {
818
 
                        j = i_len - (s - inbuf);
819
 
                        if ( 0 == (i_len = (s - inbuf)))
820
 
                                goto unhex_char;
821
 
        }
822
 
        }
823
 
        
824
 
        retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
825
 
        if(retval==(size_t)-1) {
826
 
            if (errno == EILSEQ && flags && (*flags & CONV_IGNORE)) {
827
 
                                *flags |= CONV_REQMANGLE;
828
 
                                return destlen-o_len;
829
 
            }
830
 
            else
831
 
                return (size_t) -1;
832
 
    }
833
 
    
834
 
unhex_char:
835
 
        if (j && flags && (*flags & CONV_UNESCAPEHEX )) {
836
 
                /* we're at the start on an hex encoded ucs2 char */
837
 
                if (o_len < 2) {
838
 
                        errno = E2BIG;
839
 
                        return (size_t) -1;
840
 
                }
841
 
                if ( j >= 3 && 
842
 
                        isxdigit( *(inbuf+1)) && isxdigit( *(inbuf+2)) ) {
843
 
                        hlen = 0;
844
 
                        while ( *inbuf == ':' && j >=3 && 
845
 
                                isxdigit( *(inbuf+1)) && isxdigit( *(inbuf+2)) ) {
846
 
                                inbuf++;
847
 
                                h[hlen]   = hextoint( *inbuf ) << 4;
848
 
                                inbuf++;
849
 
                                h[hlen++] |= hextoint( *inbuf );                        
850
 
                                inbuf++;
851
 
                                j -= 3;
852
 
                        }
853
 
                        h_buf = (const char*) h;
854
 
                        if ((size_t) -1 == (retval = atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len)) ) {
855
 
                                if (errno == EILSEQ && CHECK_FLAGS(flags, CONV_IGNORE)) {
856
 
                                        *flags |= CONV_REQMANGLE;
857
 
                                        return destlen-o_len;
858
 
                                }
859
 
                                else {
860
 
                                        return retval;
861
 
                                }
862
 
                        }
863
 
                }
864
 
                else {
865
 
                        /* We have an invalid :xx sequence */
866
 
                        if (CHECK_FLAGS(flags, CONV_IGNORE)) {
867
 
                                *flags |= CONV_REQMANGLE;
868
 
                                return destlen-o_len;
869
 
                        }
870
 
                        else {
871
 
                                errno=EILSEQ;
872
 
                                return (size_t) -1;
873
 
                        }
874
 
                }
875
 
                i_len = j;
876
 
                j = 0;
877
 
                if (i_len > 0)
878
 
                        goto conversion_loop;
879
 
        }
880
 
 
881
 
 
882
 
 
883
 
        return destlen-o_len;
 
798
  const u_int16_t option = (flags ? *flags : 0);
 
799
  size_t i_len, o_len;
 
800
  size_t j = 0;
 
801
  const char* inbuf = (const char*)src;
 
802
  char* outbuf = dest;
 
803
  atalk_iconv_t descriptor;
 
804
  atalk_iconv_t descriptor_cap;
 
805
 
 
806
  if (srclen == (size_t)-1)
 
807
    srclen = strlen(src) + 1;
 
808
 
 
809
  lazy_initialize_conv();
 
810
 
 
811
  descriptor = conv_handles[from_set][CH_UCS2];
 
812
  descriptor_cap = conv_handles[cap_set][CH_UCS2];
 
813
 
 
814
  if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
 
815
    errno = EINVAL;
 
816
    return (size_t)-1;
 
817
  }
 
818
 
 
819
  i_len=srclen;
 
820
  o_len=destlen;
 
821
 
 
822
  while (i_len > 0) {
 
823
    if ((option & CONV_UNESCAPEHEX)) {
 
824
      for (j = 0; j < i_len; ++j) {
 
825
        if (inbuf[j] == ':') break;
 
826
      }
 
827
      j = i_len - j;
 
828
      i_len -= j;
 
829
    }
 
830
 
 
831
    if (i_len > 0 &&
 
832
        atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) {
 
833
      if (errno == EILSEQ || errno == EINVAL) {
 
834
        errno = EILSEQ;
 
835
        if ((option & CONV_IGNORE)) {
 
836
            *flags |= CONV_REQMANGLE;
 
837
            return destlen - o_len;
 
838
        }
 
839
        if ((option & CONV__EILSEQ)) {
 
840
            if (o_len < 2) {
 
841
                errno = E2BIG;
 
842
                goto end;
 
843
            }
 
844
            *((ucs2_t *)outbuf) = (ucs2_t) IGNORE_CHAR; /**inbuf */
 
845
            inbuf++;
 
846
            i_len--;
 
847
            outbuf += 2;
 
848
            o_len -= 2;
 
849
            /* FIXME reset stat ? */
 
850
            continue;
 
851
        }
 
852
      }
 
853
      goto end;
 
854
    }
 
855
 
 
856
    if (j) {
 
857
      /* we're at the start on an hex encoded ucs2 char */
 
858
      char h[MAXPATHLEN];
 
859
      size_t hlen = 0;
 
860
 
 
861
      i_len = j, j = 0;
 
862
      while (i_len >= 3 && inbuf[0] == ':' &&
 
863
             isxdigit(inbuf[1]) && isxdigit(inbuf[2])) {
 
864
        h[hlen++] = (hextoint(inbuf[1]) << 4) | hextoint(inbuf[2]);
 
865
        inbuf += 3;
 
866
        i_len -= 3;
 
867
      }
 
868
      if (hlen) {
 
869
        const char *h_buf = h;
 
870
        if (atalk_iconv(descriptor_cap, &h_buf, &hlen, &outbuf, &o_len) == (size_t)-1) {
 
871
          i_len += hlen * 3;
 
872
          inbuf -= hlen * 3;
 
873
          if (errno == EILSEQ && (option & CONV_IGNORE)) {
 
874
            *flags |= CONV_REQMANGLE;
 
875
            return destlen - o_len;
 
876
          }
 
877
          goto end;
 
878
        }
 
879
      } else {
 
880
        /* We have an invalid :xx sequence */
 
881
        errno = EILSEQ;
 
882
        if ((option & CONV_IGNORE)) {
 
883
          *flags |= CONV_REQMANGLE;
 
884
          return destlen - o_len;
 
885
        }
 
886
        goto end;
 
887
      }
 
888
    }
 
889
  }
 
890
 end:
 
891
  return (i_len + j == 0 || (option & CONV_FORCE)) ? destlen - o_len : (size_t)-1;
884
892
}
885
893
 
886
894
/* 
888
896
 * Flags:
889
897
 *              CONV_ESCAPEDOTS: escape leading dots
890
898
 *              CONV_ESCAPEHEX:  unconvertable characters and '/' will be escaped to :XX
891
 
 *              CONV_IGNORE:     unconvertable characters will be replaced with '_'
 
899
 *              CONV_IGNORE:     return the first convertable characters.
 
900
 *              CONV__EILSEQ:    unconvertable characters will be replaced with '_'
 
901
 *              CONV_FORCE:      force convertion
892
902
 * FIXME:
893
903
 *              CONV_IGNORE and CONV_ESCAPEHEX can't work together. Should we check this ?
894
904
 *              This will *not* work if the destination charset is not multibyte, i.e. UCS2->UCS2 will fail
899
909
 
900
910
static size_t push_charset_flags (charset_t to_set, charset_t cap_set, char* src, size_t srclen, char* dest, size_t destlen, u_int16_t *flags)
901
911
{
902
 
    size_t i_len, o_len, i;
903
 
    size_t retval, j = 0;
904
 
    const char* inbuf = (const char*)src;
905
 
    char* outbuf = (char*)dest;
906
 
    atalk_iconv_t descriptor;
907
 
    char *o_save;
908
 
    char *buf, *buf_save;
909
 
    size_t buflen;
910
 
    
911
 
    lazy_initialize_conv();
912
 
    
913
 
    descriptor = conv_handles[CH_UCS2][to_set];
914
 
    
915
 
    if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
916
 
        return (size_t) -1;
917
 
    }
918
 
    
919
 
    i_len=srclen;
920
 
    o_len=destlen;
921
 
    o_save=outbuf;
922
 
    
923
 
    if ( SVAL(inbuf,0) == 0x002e && flags && (*flags & CONV_ESCAPEDOTS)) { /* 0x002e = . */
924
 
        if (o_len < 3) {
925
 
            errno = E2BIG;
926
 
            return (size_t) -1;
927
 
        }
928
 
        o_save[0] = ':';
929
 
        o_save[1] = '2';
930
 
        o_save[2] = 'e';
931
 
        o_len -= 3;
932
 
        inbuf += 2;
933
 
        i_len -= 2;
934
 
        outbuf = o_save + 3;
935
 
        if (flags) *flags |= CONV_REQESCAPE;
936
 
    }
937
 
        
938
 
conversion_loop:
939
 
    if ( flags && (*flags & CONV_ESCAPEHEX)) {
940
 
        for ( i = 0; i < i_len; i+=2) {
941
 
            if ( SVAL((inbuf+i),0) == 0x002f) { /* 0x002f = / */
942
 
                j = i_len - i;
943
 
                if ( 0 == ( i_len = i))
944
 
                    goto escape_slash;
945
 
                break;
946
 
            } else if ( SVAL(inbuf+i,0) == 0x003a) { /* 0x003a = : */
947
 
                errno = EILSEQ;
948
 
                return (size_t) -1;
949
 
            }
950
 
        }
951
 
    }
952
 
    
953
 
    retval = atalk_iconv(descriptor,  &inbuf, &i_len, &outbuf, &o_len);
954
 
    if (retval==(size_t)-1) {
955
 
        if (errno == EILSEQ && CHECK_FLAGS(flags, CONV_IGNORE)) {
956
 
            *flags |= CONV_REQMANGLE;
957
 
            return destlen -o_len;
958
 
        }
959
 
        else if ( errno == EILSEQ && flags && (*flags & CONV_ESCAPEHEX)) {
960
 
            if (o_len < 3) {
961
 
                errno = E2BIG;
962
 
                return (size_t) -1;
 
912
  const u_int16_t option = (flags ? *flags : 0);
 
913
  size_t i_len, o_len, i;
 
914
  size_t j = 0;
 
915
  const char* inbuf = (const char*)src;
 
916
  char* outbuf = (char*)dest;
 
917
  atalk_iconv_t descriptor;
 
918
  atalk_iconv_t descriptor_cap;
 
919
 
 
920
  lazy_initialize_conv();
 
921
 
 
922
  descriptor = conv_handles[CH_UCS2][to_set];
 
923
  descriptor_cap = conv_handles[CH_UCS2][cap_set];
 
924
 
 
925
  if (descriptor == (atalk_iconv_t)-1 || descriptor == (atalk_iconv_t)0) {
 
926
    errno = EINVAL;
 
927
    return (size_t) -1;
 
928
  }
 
929
 
 
930
  i_len=srclen;
 
931
  o_len=destlen;
 
932
 
 
933
  if ((option & CONV_ESCAPEDOTS) &&
 
934
      i_len >= 2 && SVAL(inbuf, 0) == 0x002e) { /* 0x002e = . */
 
935
    if (o_len < 3) {
 
936
      errno = E2BIG;
 
937
      goto end;
 
938
    }
 
939
    *outbuf++ = ':';
 
940
    *outbuf++ = '2';
 
941
    *outbuf++ = 'e';
 
942
    o_len -= 3;
 
943
    inbuf += 2;
 
944
    i_len -= 2;
 
945
    *flags |= CONV_REQESCAPE;
 
946
  }
 
947
 
 
948
  while (i_len >= 2) {
 
949
    if ((option & CONV_ESCAPEHEX)) {
 
950
      for (i = 0; i < i_len; i += 2) {
 
951
        ucs2_t c = SVAL(inbuf, i);
 
952
        if (c == 0x002f) { /* 0x002f = / */
 
953
          j = i_len - i;
 
954
          i_len = i;
 
955
          break;
 
956
        } else if (c == 0x003a) { /* 0x003a = : */
 
957
          errno = EILSEQ;
 
958
          goto end;
 
959
        }
 
960
      }
 
961
    }
 
962
    while (i_len > 0 &&
 
963
           atalk_iconv(descriptor, &inbuf, &i_len, &outbuf, &o_len) == (size_t)-1) {
 
964
      if (errno == EILSEQ) {
 
965
        if ((option & CONV_IGNORE)) {
 
966
          *flags |= CONV_REQMANGLE;
 
967
          return destlen - o_len;
 
968
        }
 
969
        if ((option & CONV_ESCAPEHEX)) {
 
970
          const size_t bufsiz = o_len / 3 + 1;
 
971
          char *buf = malloc(bufsiz);
 
972
          size_t buflen;
 
973
 
 
974
          if (!buf) 
 
975
              goto end;
 
976
          i = i_len;
 
977
          for (buflen = 1; buflen <= bufsiz; ++buflen) {
 
978
            char *b = buf;
 
979
            size_t o = buflen;
 
980
            if (atalk_iconv(descriptor_cap, &inbuf, &i, &b, &o) != (size_t)-1) {
 
981
              buflen -= o;
 
982
              break;
 
983
            } else if (errno != E2BIG) {
 
984
              SAFE_FREE(buf);
 
985
              goto end;
 
986
            } else if (o < buflen) {
 
987
              buflen -= o;
 
988
              break;
963
989
            }
964
 
            if ((size_t) -1 == (buflen = convert_string_allocate_internal(CH_UCS2, cap_set, inbuf, 2, &buf)) ) 
965
 
                return buflen;
966
 
            buf_save = buf;
967
 
            while (buflen > 0) {
968
 
                if ( o_len < 3) {
969
 
                        errno = E2BIG;
970
 
                        return (size_t) -1;
971
 
                }
972
 
                *outbuf++ = ':';
973
 
                *outbuf++ = hexdig[ ( *buf & 0xf0 ) >> 4 ];
974
 
                *outbuf++ = hexdig[ *buf & 0x0f ];
975
 
                buf++;
976
 
                buflen--;
977
 
                o_len -= 3;
978
 
            }
979
 
            SAFE_FREE(buf_save);
980
 
            buflen = 0;
981
 
            i_len -= 2;
982
 
            inbuf += 2;
983
 
            if (flags) *flags |= CONV_REQESCAPE;
984
 
            if ( i_len > 0)
985
 
                goto conversion_loop;
 
990
          }
 
991
          if (o_len < buflen * 3) {
 
992
            SAFE_FREE(buf);
 
993
            errno = E2BIG;
 
994
            goto end;
 
995
          }
 
996
          o_len -= buflen * 3;
 
997
          i_len = i;
 
998
          for (i = 0; i < buflen; ++i) {
 
999
            *outbuf++ = ':';
 
1000
            *outbuf++ = hexdig[(buf[i] >> 4) & 0x0f];
 
1001
            *outbuf++ = hexdig[buf[i] & 0x0f];
 
1002
          }
 
1003
          SAFE_FREE(buf);
 
1004
          *flags |= CONV_REQESCAPE;
 
1005
          continue;
986
1006
        }
987
 
        else
988
 
           return (size_t)(-1); 
989
 
    }
990
 
        
991
 
escape_slash:
992
 
    if (j && flags && (*flags & CONV_ESCAPEHEX)) {
993
 
        if (o_len < 3) {
994
 
            errno = E2BIG;
995
 
            return (size_t) -1;
996
 
        }
997
 
        o_save[destlen -o_len]   = ':';
998
 
        o_save[destlen -o_len+1] = '2';
999
 
        o_save[destlen -o_len+2] = 'f';
1000
 
        inbuf  += 2;
1001
 
        i_len   = j-2;
1002
 
        o_len  -= 3;
1003
 
        outbuf += 3;
1004
 
        j = 0;
1005
 
        if ( i_len > 0)
1006
 
                goto conversion_loop;
1007
 
    }
1008
 
    return destlen -o_len;
 
1007
      }
 
1008
      goto end;
 
1009
    }
 
1010
 
 
1011
    if (j) {
 
1012
      i_len = j, j = 0;
 
1013
      if (o_len < 3) {
 
1014
        errno = E2BIG;
 
1015
        goto end;
 
1016
      }
 
1017
      *outbuf++ = ':';
 
1018
      *outbuf++ = '2';
 
1019
      *outbuf++ = 'f';
 
1020
      o_len -= 3;
 
1021
      inbuf += 2;
 
1022
      i_len -= 2;
 
1023
    }
 
1024
  }
 
1025
  if (i_len > 0) errno = EINVAL;
 
1026
 end:
 
1027
  return (i_len + j == 0 || (option & CONV_FORCE)) ? destlen - o_len : (size_t)-1;
1009
1028
}
1010
1029
 
1011
1030
/*