quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ccsidcurl.c (35884B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  *
     24  ***************************************************************************/
     25 
     26 /* CCSID API wrappers for OS/400. */
     27 
     28 #include <iconv.h>
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include <stddef.h>
     32 #include <errno.h>
     33 #include <stdarg.h>
     34 
     35 #pragma enum(int)
     36 
     37 #include "curl.h"
     38 #include "mprintf.h"
     39 #include "slist.h"
     40 #include "urldata.h"
     41 #include "url.h"
     42 #include "setopt.h"
     43 #include "getinfo.h"
     44 #include "ccsidcurl.h"
     45 
     46 #include "os400sys.h"
     47 
     48 #ifndef SIZE_MAX
     49 #define SIZE_MAX        ((size_t) ~0)   /* Is unsigned on OS/400. */
     50 #endif
     51 
     52 
     53 #define ASCII_CCSID     819     /* Use ISO-8859-1 as ASCII. */
     54 #define NOCONV_CCSID    65535   /* No conversion. */
     55 #define ICONV_ID_SIZE   32      /* Size of iconv_open() code identifier. */
     56 #define ICONV_OPEN_ERROR(t)     ((t).return_value == -1)
     57 
     58 #define ALLOC_GRANULE   8       /* Alloc. granule for curl_formadd_ccsid(). */
     59 
     60 
     61 static void
     62 makeOS400IconvCode(char buf[ICONV_ID_SIZE], unsigned int ccsid)
     63 {
     64   /**
     65   *** Convert a CCSID to the corresponding IBM iconv_open() character
     66   ***  code identifier.
     67   ***  This code is specific to the OS400 implementation of the iconv library.
     68   ***  CCSID 65535 (no conversion) is replaced by the ASCII CCSID.
     69   ***  CCSID 0 is interpreted by the OS400 as the job's CCSID.
     70   **/
     71 
     72   ccsid &= 0xFFFF;
     73 
     74   if(ccsid == NOCONV_CCSID)
     75     ccsid = ASCII_CCSID;
     76 
     77   memset(buf, 0, ICONV_ID_SIZE);
     78   curl_msprintf(buf, "IBMCCSID%05u0000000", ccsid);
     79 }
     80 
     81 
     82 static iconv_t
     83 iconv_open_CCSID(unsigned int ccsidout, unsigned int ccsidin,
     84                  unsigned int cstr)
     85 {
     86   char fromcode[ICONV_ID_SIZE];
     87   char tocode[ICONV_ID_SIZE];
     88 
     89   /**
     90   ***  Like iconv_open(), but character codes are given as CCSIDs.
     91   ***  If `cstr' is non-zero, conversion is set up to stop whenever a
     92   ***   null character is encountered.
     93   ***  See iconv_open() IBM description in "National Language Support API".
     94   **/
     95 
     96   makeOS400IconvCode(fromcode, ccsidin);
     97   makeOS400IconvCode(tocode, ccsidout);
     98   memset(tocode + 13, 0, sizeof(tocode) - 13);   /* Dest. code id format. */
     99 
    100   if(cstr)
    101     fromcode[18] = '1';                         /* Set null-terminator flag. */
    102 
    103   return iconv_open(tocode, fromcode);
    104 }
    105 
    106 
    107 static int
    108 convert(char *d, size_t dlen, int dccsid,
    109         const char *s, int slen, int sccsid)
    110 {
    111   int i;
    112   iconv_t cd;
    113   size_t lslen;
    114 
    115   /**
    116   ***  Convert `sccsid'-coded `slen'-data bytes at `s' into `dccsid'-coded
    117   ***   data stored in the `dlen'-byte buffer at `d'.
    118   ***  If `slen' < 0, source string is null-terminated.
    119   ***  CCSID 65535 (no conversion) is replaced by the ASCII CCSID.
    120   ***  Return the converted destination byte count, or -1 if error.
    121   **/
    122 
    123   if(sccsid == 65535)
    124     sccsid = ASCII_CCSID;
    125 
    126   if(dccsid == 65535)
    127     dccsid = ASCII_CCSID;
    128 
    129   if(sccsid == dccsid) {
    130     lslen = slen >= 0 ? slen : strlen(s) + 1;
    131     i = lslen < dlen ? lslen : dlen;
    132 
    133     if(s != d && i > 0)
    134       memcpy(d, s, i);
    135 
    136     return i;
    137     }
    138 
    139   if(slen < 0) {
    140     lslen = 0;
    141     cd = iconv_open_CCSID(dccsid, sccsid, 1);
    142     }
    143   else {
    144     lslen = (size_t) slen;
    145     cd = iconv_open_CCSID(dccsid, sccsid, 0);
    146     }
    147 
    148   if(ICONV_OPEN_ERROR(cd))
    149     return -1;
    150 
    151   i = dlen;
    152 
    153   if((int) iconv(cd, (char * *) &s, &lslen, &d, &dlen) < 0)
    154     i = -1;
    155   else
    156     i -= dlen;
    157 
    158   iconv_close(cd);
    159   return i;
    160 }
    161 
    162 
    163 static char *dynconvert(int dccsid, const char *s, int slen, int sccsid)
    164 {
    165   char *d;
    166   char *cp;
    167   size_t dlen;
    168   int l;
    169   static const char nullbyte = 0;
    170 
    171   /* Like convert, but the destination is allocated and returned. */
    172 
    173   dlen = (size_t) (slen < 0 ? strlen(s) : slen) + 1;
    174   dlen *= MAX_CONV_EXPANSION;           /* Allow some expansion. */
    175   d = malloc(dlen);
    176 
    177   if(!d)
    178     return (char *) NULL;
    179 
    180   l = convert(d, dlen, dccsid, s, slen, sccsid);
    181 
    182   if(l < 0) {
    183     free(d);
    184     return (char *) NULL;
    185     }
    186 
    187   if(slen < 0) {
    188     /* Need to null-terminate even when source length is given.
    189        Since destination code size is unknown, use a conversion to generate
    190        terminator. */
    191 
    192     int l2 = convert(d + l, dlen - l, dccsid, &nullbyte, -1, ASCII_CCSID);
    193 
    194     if(l2 < 0) {
    195       free(d);
    196       return (char *) NULL;
    197       }
    198 
    199     l += l2;
    200     }
    201 
    202   if((size_t) l < dlen) {
    203     cp = realloc(d, l);         /* Shorten to minimum needed. */
    204 
    205     if(cp)
    206       d = cp;
    207     }
    208 
    209   return d;
    210 }
    211 
    212 
    213 static struct curl_slist *
    214 slist_convert(int dccsid, struct curl_slist *from, int sccsid)
    215 {
    216   struct curl_slist *to = (struct curl_slist *) NULL;
    217 
    218   for(; from; from = from->next) {
    219     struct curl_slist *nl;
    220     char *cp = dynconvert(dccsid, from->data, -1, sccsid);
    221 
    222     if(!cp) {
    223       curl_slist_free_all(to);
    224       return (struct curl_slist *) NULL;
    225     }
    226     nl = Curl_slist_append_nodup(to, cp);
    227     if(!nl) {
    228       curl_slist_free_all(to);
    229       free(cp);
    230       return NULL;
    231     }
    232     to = nl;
    233   }
    234   return to;
    235 }
    236 
    237 
    238 static char *
    239 keyed_string(localkey_t key, const char *ascii, unsigned int ccsid)
    240 {
    241   int i;
    242   char *ebcdic;
    243 
    244   if(!ascii)
    245     return (char *) NULL;
    246 
    247   i = MAX_CONV_EXPANSION * (strlen(ascii) + 1);
    248 
    249   ebcdic = Curl_thread_buffer(key, i);
    250   if(!ebcdic)
    251     return ebcdic;
    252 
    253   if(convert(ebcdic, i, ccsid, ascii, -1, ASCII_CCSID) < 0)
    254     return (char *) NULL;
    255 
    256   return ebcdic;
    257 }
    258 
    259 
    260 const char *
    261 curl_to_ccsid(const char *s, unsigned int ccsid)
    262 {
    263   if(s)
    264     s = dynconvert(ccsid, s, -1, ASCII_CCSID);
    265   return s;
    266 }
    267 
    268 
    269 const char *
    270 curl_from_ccsid(const char *s, unsigned int ccsid)
    271 {
    272   if(s)
    273     s = dynconvert(ASCII_CCSID, s, -1, ccsid);
    274   return s;
    275 }
    276 
    277 
    278 char *
    279 curl_version_ccsid(unsigned int ccsid)
    280 {
    281   return keyed_string(LK_CURL_VERSION, curl_version(), ccsid);
    282 }
    283 
    284 
    285 char *
    286 curl_easy_escape_ccsid(CURL *handle, const char *string, int length,
    287                        unsigned int sccsid, unsigned int dccsid)
    288 {
    289   char *s;
    290   char *d;
    291 
    292   if(!string) {
    293     /* !checksrc! disable ERRNOVAR 1 */
    294     errno = EINVAL;
    295     return (char *) NULL;
    296     }
    297 
    298   s = dynconvert(ASCII_CCSID, string, length ? length : -1, sccsid);
    299 
    300   if(!s)
    301     return (char *) NULL;
    302 
    303   d = curl_easy_escape(handle, s, 0);
    304   free(s);
    305 
    306   if(!d)
    307     return (char *) NULL;
    308 
    309   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
    310   free(d);
    311   return s;
    312 }
    313 
    314 
    315 char *
    316 curl_easy_unescape_ccsid(CURL *handle, const char *string, int length,
    317                          int *outlength,
    318                          unsigned int sccsid, unsigned int dccsid)
    319 {
    320   char *s;
    321   char *d;
    322 
    323   if(!string) {
    324     /* !checksrc! disable ERRNOVAR 1 */
    325     errno = EINVAL;
    326     return (char *) NULL;
    327     }
    328 
    329   s = dynconvert(ASCII_CCSID, string, length ? length : -1, sccsid);
    330 
    331   if(!s)
    332     return (char *) NULL;
    333 
    334   d = curl_easy_unescape(handle, s, 0, outlength);
    335   free(s);
    336 
    337   if(!d)
    338     return (char *) NULL;
    339 
    340   s = dynconvert(dccsid, d, -1, ASCII_CCSID);
    341   free(d);
    342 
    343   if(s && outlength)
    344     *outlength = strlen(s);
    345 
    346   return s;
    347 }
    348 
    349 
    350 struct curl_slist *
    351 curl_slist_append_ccsid(struct curl_slist *list,
    352                         const char *data, unsigned int ccsid)
    353 {
    354   char *s;
    355 
    356   s = (char *) NULL;
    357 
    358   if(!data)
    359     return curl_slist_append(list, data);
    360 
    361   s = dynconvert(ASCII_CCSID, data, -1, ccsid);
    362 
    363   if(!s)
    364     return (struct curl_slist *) NULL;
    365 
    366   list = curl_slist_append(list, s);
    367   free(s);
    368   return list;
    369 }
    370 
    371 
    372 time_t
    373 curl_getdate_ccsid(const char *p, const time_t *unused, unsigned int ccsid)
    374 {
    375   char *s;
    376   time_t t;
    377 
    378   if(!p)
    379     return curl_getdate(p, unused);
    380 
    381   s = dynconvert(ASCII_CCSID, p, -1, ccsid);
    382 
    383   if(!s)
    384     return (time_t) -1;
    385 
    386   t = curl_getdate(s, unused);
    387   free(s);
    388   return t;
    389 }
    390 
    391 
    392 static int
    393 convert_version_info_string(const char **stringp,
    394                             char **bufp, int *left, unsigned int ccsid)
    395 {
    396   /* Helper for curl_version_info_ccsid(): convert a string if defined.
    397      Result is stored in the `*left'-byte buffer at `*bufp'.
    398      `*bufp' and `*left' are updated accordingly.
    399      Return 0 if ok, else -1. */
    400 
    401   if(*stringp) {
    402     int l = convert(*bufp, *left, ccsid, *stringp, -1, ASCII_CCSID);
    403 
    404     if(l <= 0)
    405       return -1;
    406 
    407     *stringp = *bufp;
    408     *bufp += l;
    409     *left -= l;
    410     }
    411 
    412   return 0;
    413 }
    414 
    415 
    416 curl_version_info_data *
    417 curl_version_info_ccsid(CURLversion stamp, unsigned int ccsid)
    418 {
    419   curl_version_info_data *p;
    420   char *cp;
    421   int n;
    422   int nproto;
    423   curl_version_info_data *id;
    424   int i;
    425   const char **cpp;
    426   static const size_t charfields[] = {
    427     offsetof(curl_version_info_data, version),
    428     offsetof(curl_version_info_data, host),
    429     offsetof(curl_version_info_data, ssl_version),
    430     offsetof(curl_version_info_data, libz_version),
    431     offsetof(curl_version_info_data, ares),
    432     offsetof(curl_version_info_data, libidn),
    433     offsetof(curl_version_info_data, libssh_version),
    434     offsetof(curl_version_info_data, brotli_version),
    435     offsetof(curl_version_info_data, nghttp2_version),
    436     offsetof(curl_version_info_data, quic_version),
    437     offsetof(curl_version_info_data, cainfo),
    438     offsetof(curl_version_info_data, capath),
    439     offsetof(curl_version_info_data, zstd_version),
    440     offsetof(curl_version_info_data, hyper_version),
    441     offsetof(curl_version_info_data, gsasl_version),
    442     offsetof(curl_version_info_data, feature_names),
    443     offsetof(curl_version_info_data, rtmp_version)
    444   };
    445 
    446   /* The assertion below is possible, because although the second operand
    447      is an enum member, the first is a #define. In that case, the OS/400 C
    448      compiler seems to compare string values after substitution. */
    449 
    450 #if CURLVERSION_NOW != CURLVERSION_ELEVENTH
    451 #error curl_version_info_data structure has changed: upgrade this procedure.
    452 #endif
    453 
    454   /* If caller has been compiled with a newer version, error. */
    455 
    456   if(stamp > CURLVERSION_NOW)
    457     return (curl_version_info_data *) NULL;
    458 
    459   p = curl_version_info(stamp);
    460 
    461   if(!p)
    462     return p;
    463 
    464   /* Measure thread space needed. */
    465 
    466   n = 0;
    467   nproto = 0;
    468 
    469   if(p->protocols) {
    470     while(p->protocols[nproto])
    471       n += strlen(p->protocols[nproto++]);
    472 
    473     n += nproto++;
    474     }
    475 
    476   for(i = 0; i < sizeof(charfields) / sizeof(charfields[0]); i++) {
    477     cpp = (const char **) ((char *) p + charfields[i]);
    478     if(*cpp)
    479       n += strlen(*cpp) + 1;
    480   }
    481 
    482   /* Allocate thread space. */
    483 
    484   n *= MAX_CONV_EXPANSION;
    485 
    486   if(nproto)
    487     n += nproto * sizeof(const char *);
    488 
    489   cp = Curl_thread_buffer(LK_VERSION_INFO_DATA, n);
    490   id = (curl_version_info_data *) Curl_thread_buffer(LK_VERSION_INFO,
    491                                                      sizeof(*id));
    492 
    493   if(!id || !cp)
    494     return (curl_version_info_data *) NULL;
    495 
    496   /* Copy data and convert strings. */
    497 
    498   memcpy((char *) id, (char *) p, sizeof(*p));
    499 
    500   if(id->protocols) {
    501     i = nproto * sizeof(id->protocols[0]);
    502 
    503     id->protocols = (const char * const *) cp;
    504     memcpy(cp, (char *) p->protocols, i);
    505     cp += i;
    506     n -= i;
    507 
    508     for(i = 0; id->protocols[i]; i++)
    509       if(convert_version_info_string(((const char * *) id->protocols) + i,
    510                                       &cp, &n, ccsid))
    511         return (curl_version_info_data *) NULL;
    512   }
    513 
    514   for(i = 0; i < sizeof(charfields) / sizeof(charfields[0]); i++) {
    515     cpp = (const char **) ((char *) p + charfields[i]);
    516     if(*cpp && convert_version_info_string(cpp, &cp, &n, ccsid))
    517       return (curl_version_info_data *) NULL;
    518   }
    519 
    520   return id;
    521 }
    522 
    523 
    524 const char *
    525 curl_easy_strerror_ccsid(CURLcode error, unsigned int ccsid)
    526 {
    527   return keyed_string(LK_EASY_STRERROR, curl_easy_strerror(error), ccsid);
    528 }
    529 
    530 
    531 const char *
    532 curl_share_strerror_ccsid(CURLSHcode error, unsigned int ccsid)
    533 {
    534   return keyed_string(LK_SHARE_STRERROR, curl_share_strerror(error), ccsid);
    535 }
    536 
    537 
    538 const char *
    539 curl_multi_strerror_ccsid(CURLMcode error, unsigned int ccsid)
    540 {
    541   return keyed_string(LK_MULTI_STRERROR, curl_multi_strerror(error), ccsid);
    542 }
    543 
    544 
    545 const char *
    546 curl_url_strerror_ccsid(CURLUcode error, unsigned int ccsid)
    547 {
    548   return keyed_string(LK_URL_STRERROR, curl_url_strerror(error), ccsid);
    549 }
    550 
    551 
    552 void
    553 curl_certinfo_free_all(struct curl_certinfo *info)
    554 {
    555   /* Free all memory used by certificate info. */
    556   if(info) {
    557     if(info->certinfo) {
    558       int i;
    559 
    560       for(i = 0; i < info->num_of_certs; i++)
    561         curl_slist_free_all(info->certinfo[i]);
    562       free((char *) info->certinfo);
    563     }
    564     free((char *) info);
    565   }
    566 }
    567 
    568 
    569 CURLcode
    570 curl_easy_getinfo_ccsid(CURL *curl, CURLINFO info, ...)
    571 {
    572   va_list arg;
    573   void *paramp;
    574   CURLcode ret;
    575   struct Curl_easy *data;
    576 
    577   /* WARNING: unlike curl_easy_getinfo(), the strings returned by this
    578      procedure have to be free'ed. */
    579 
    580   data = (struct Curl_easy *) curl;
    581   va_start(arg, info);
    582   paramp = va_arg(arg, void *);
    583   ret = Curl_getinfo(data, info, paramp);
    584 
    585   if(ret == CURLE_OK) {
    586     unsigned int ccsid;
    587     char **cpp;
    588     struct curl_slist **slp;
    589     struct curl_certinfo *cipf;
    590     struct curl_certinfo *cipt;
    591 
    592     switch((int) info & CURLINFO_TYPEMASK) {
    593 
    594     case CURLINFO_STRING:
    595       ccsid = va_arg(arg, unsigned int);
    596       cpp = (char * *) paramp;
    597 
    598       if(*cpp) {
    599         *cpp = dynconvert(ccsid, *cpp, -1, ASCII_CCSID);
    600 
    601         if(!*cpp)
    602           ret = CURLE_OUT_OF_MEMORY;
    603       }
    604 
    605       break;
    606 
    607     case CURLINFO_SLIST:
    608       ccsid = va_arg(arg, unsigned int);
    609       switch(info) {
    610       case CURLINFO_CERTINFO:
    611         cipf = *(struct curl_certinfo * *) paramp;
    612         if(cipf) {
    613           cipt = (struct curl_certinfo *) malloc(sizeof(*cipt));
    614           if(!cipt)
    615             ret = CURLE_OUT_OF_MEMORY;
    616           else {
    617             cipt->certinfo = (struct curl_slist **)
    618               calloc(cipf->num_of_certs +
    619                      1, sizeof(struct curl_slist *));
    620             if(!cipt->certinfo)
    621               ret = CURLE_OUT_OF_MEMORY;
    622             else {
    623               int i;
    624 
    625               cipt->num_of_certs = cipf->num_of_certs;
    626               for(i = 0; i < cipf->num_of_certs; i++)
    627                 if(cipf->certinfo[i])
    628                   if(!(cipt->certinfo[i] = slist_convert(ccsid,
    629                                                           cipf->certinfo[i],
    630                                                           ASCII_CCSID))) {
    631                     ret = CURLE_OUT_OF_MEMORY;
    632                     break;
    633                   }
    634               }
    635             }
    636 
    637           if(ret != CURLE_OK) {
    638             curl_certinfo_free_all(cipt);
    639             cipt = (struct curl_certinfo *) NULL;
    640           }
    641 
    642           *(struct curl_certinfo * *) paramp = cipt;
    643         }
    644 
    645         break;
    646 
    647       case CURLINFO_TLS_SESSION:
    648       case CURLINFO_TLS_SSL_PTR:
    649       case CURLINFO_SOCKET:
    650         break;
    651 
    652       default:
    653         slp = (struct curl_slist **) paramp;
    654         if(*slp) {
    655           *slp = slist_convert(ccsid, *slp, ASCII_CCSID);
    656           if(!*slp)
    657             ret = CURLE_OUT_OF_MEMORY;
    658         }
    659         break;
    660       }
    661     }
    662   }
    663 
    664   va_end(arg);
    665   return ret;
    666 }
    667 
    668 
    669 static int
    670 Curl_is_formadd_string(CURLformoption option)
    671 {
    672   switch(option) {
    673 
    674   case CURLFORM_FILENAME:
    675   case CURLFORM_CONTENTTYPE:
    676   case CURLFORM_BUFFER:
    677   case CURLFORM_FILE:
    678   case CURLFORM_FILECONTENT:
    679   case CURLFORM_COPYCONTENTS:
    680   case CURLFORM_COPYNAME:
    681     return 1;
    682   }
    683 
    684   return 0;
    685 }
    686 
    687 
    688 static void
    689 Curl_formadd_release_local(struct curl_forms *forms, int nargs, int skip)
    690 {
    691   while(nargs--)
    692     if(nargs != skip)
    693       if(Curl_is_formadd_string(forms[nargs].option))
    694         if(forms[nargs].value)
    695           free((char *) forms[nargs].value);
    696 
    697   free((char *) forms);
    698 }
    699 
    700 
    701 static int
    702 Curl_formadd_convert(struct curl_forms *forms,
    703                      int formx, int lengthx, unsigned int ccsid)
    704 {
    705   int l;
    706   char *cp;
    707   char *cp2;
    708 
    709   if(formx < 0 || !forms[formx].value)
    710     return 0;
    711 
    712   if(lengthx >= 0)
    713     l = (int) forms[lengthx].value;
    714   else
    715     l = strlen(forms[formx].value) + 1;
    716 
    717   cp = malloc(MAX_CONV_EXPANSION * l);
    718 
    719   if(!cp)
    720     return -1;
    721 
    722   l = convert(cp, MAX_CONV_EXPANSION * l, ASCII_CCSID,
    723               forms[formx].value, l, ccsid);
    724 
    725   if(l < 0) {
    726     free(cp);
    727     return -1;
    728     }
    729 
    730   cp2 = realloc(cp, l);         /* Shorten buffer to the string size. */
    731 
    732   if(cp2)
    733     cp = cp2;
    734 
    735   forms[formx].value = cp;
    736 
    737   if(lengthx >= 0)
    738     forms[lengthx].value = (char *) l;  /* Update length after conversion. */
    739 
    740   return l;
    741 }
    742 
    743 
    744 CURLFORMcode
    745 curl_formadd_ccsid(struct curl_httppost **httppost,
    746                    struct curl_httppost **last_post, ...)
    747 {
    748   va_list arg;
    749   CURLformoption option;
    750   CURLFORMcode result;
    751   struct curl_forms *forms;
    752   struct curl_forms *lforms;
    753   struct curl_forms *tforms;
    754   unsigned int lformlen;
    755   const char *value;
    756   unsigned int ccsid;
    757   int nargs;
    758   int namex;
    759   int namelengthx;
    760   int contentx;
    761   int lengthx;
    762   unsigned int contentccsid;
    763   unsigned int nameccsid;
    764 
    765   /* A single curl_formadd() call cannot be split in several calls to deal
    766      with all parameters: the original parameters are thus copied to a local
    767      curl_forms array and converted to ASCII when needed.
    768      CURLFORM_PTRNAME is processed as if it were CURLFORM_COPYNAME.
    769      CURLFORM_COPYNAME and CURLFORM_NAMELENGTH occurrence order in
    770      parameters is not defined; for this reason, the actual conversion is
    771      delayed to the end of parameter processing. The same applies to
    772      CURLFORM_COPYCONTENTS/CURLFORM_CONTENTSLENGTH, but these may appear
    773      several times in the parameter list; the problem resides here in knowing
    774      which CURLFORM_CONTENTSLENGTH applies to which CURLFORM_COPYCONTENTS and
    775      when we can be sure to have both info for conversion: end of parameter
    776      list is such a point, but CURLFORM_CONTENTTYPE is also used here as a
    777      natural separator between content data definitions; this seems to be
    778      in accordance with FormAdd() behavior. */
    779 
    780   /* Allocate the local curl_forms array. */
    781 
    782   lformlen = ALLOC_GRANULE;
    783   lforms = malloc(lformlen * sizeof(*lforms));
    784 
    785   if(!lforms)
    786     return CURL_FORMADD_MEMORY;
    787 
    788   /* Process the arguments, copying them into local array, latching conversion
    789      indexes and converting when needed. */
    790 
    791   result = CURL_FORMADD_OK;
    792   nargs = 0;
    793   contentx = -1;
    794   lengthx = -1;
    795   namex = -1;
    796   namelengthx = -1;
    797   forms = (struct curl_forms *) NULL;
    798   va_start(arg, last_post);
    799 
    800   for(;;) {
    801     /* Make sure there is still room for an item in local array. */
    802 
    803     if(nargs >= lformlen) {
    804       lformlen += ALLOC_GRANULE;
    805       tforms = realloc(lforms, lformlen * sizeof(*lforms));
    806 
    807       if(!tforms) {
    808         result = CURL_FORMADD_MEMORY;
    809         break;
    810         }
    811 
    812       lforms = tforms;
    813       }
    814 
    815     /* Get next option. */
    816 
    817     if(forms) {
    818       /* Get option from array. */
    819 
    820       option = forms->option;
    821       value = forms->value;
    822       forms++;
    823       }
    824     else {
    825       /* Get option from arguments. */
    826 
    827       option = va_arg(arg, CURLformoption);
    828 
    829       if(option == CURLFORM_END)
    830         break;
    831       }
    832 
    833     /* Dispatch by option. */
    834 
    835     switch(option) {
    836 
    837     case CURLFORM_END:
    838       forms = (struct curl_forms *) NULL;       /* Leave array mode. */
    839       continue;
    840 
    841     case CURLFORM_ARRAY:
    842       if(!forms) {
    843         forms = va_arg(arg, struct curl_forms *);
    844         continue;
    845         }
    846 
    847       result = CURL_FORMADD_ILLEGAL_ARRAY;
    848       break;
    849 
    850     case CURLFORM_COPYNAME:
    851       option = CURLFORM_PTRNAME;                /* Static for now. */
    852 
    853     case CURLFORM_PTRNAME:
    854       if(namex >= 0)
    855         result = CURL_FORMADD_OPTION_TWICE;
    856 
    857       namex = nargs;
    858 
    859       if(!forms) {
    860         value = va_arg(arg, char *);
    861         nameccsid = (unsigned int) va_arg(arg, long);
    862         }
    863       else {
    864         nameccsid = (unsigned int) forms->value;
    865         forms++;
    866         }
    867 
    868       break;
    869 
    870     case CURLFORM_COPYCONTENTS:
    871       if(contentx >= 0)
    872         result = CURL_FORMADD_OPTION_TWICE;
    873 
    874       contentx = nargs;
    875 
    876       if(!forms) {
    877         value = va_arg(arg, char *);
    878         contentccsid = (unsigned int) va_arg(arg, long);
    879         }
    880       else {
    881         contentccsid = (unsigned int) forms->value;
    882         forms++;
    883         }
    884 
    885       break;
    886 
    887     case CURLFORM_PTRCONTENTS:
    888     case CURLFORM_BUFFERPTR:
    889       if(!forms)
    890         value = va_arg(arg, char *);            /* No conversion. */
    891 
    892       break;
    893 
    894     case CURLFORM_CONTENTSLENGTH:
    895       lengthx = nargs;
    896 
    897       if(!forms)
    898         value = (char *) va_arg(arg, long);
    899 
    900       break;
    901 
    902     case CURLFORM_CONTENTLEN:
    903       lengthx = nargs;
    904 
    905       if(!forms)
    906         value = (char *) va_arg(arg, curl_off_t);
    907 
    908       break;
    909 
    910     case CURLFORM_NAMELENGTH:
    911       namelengthx = nargs;
    912 
    913       if(!forms)
    914         value = (char *) va_arg(arg, long);
    915 
    916       break;
    917 
    918     case CURLFORM_BUFFERLENGTH:
    919       if(!forms)
    920         value = (char *) va_arg(arg, long);
    921 
    922       break;
    923 
    924     case CURLFORM_CONTENTHEADER:
    925       if(!forms)
    926         value = (char *) va_arg(arg, struct curl_slist *);
    927 
    928       break;
    929 
    930     case CURLFORM_STREAM:
    931       if(!forms)
    932         value = (char *) va_arg(arg, void *);
    933 
    934       break;
    935 
    936     case CURLFORM_CONTENTTYPE:
    937       /* If a previous content has been encountered, convert it now. */
    938 
    939       if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0) {
    940         result = CURL_FORMADD_MEMORY;
    941         break;
    942         }
    943 
    944       contentx = -1;
    945       lengthx = -1;
    946       /* Fall into default. */
    947 
    948     default:
    949       /* Must be a convertible string. */
    950 
    951       if(!Curl_is_formadd_string(option)) {
    952         result = CURL_FORMADD_UNKNOWN_OPTION;
    953         break;
    954         }
    955 
    956       if(!forms) {
    957         value = va_arg(arg, char *);
    958         ccsid = (unsigned int) va_arg(arg, long);
    959         }
    960       else {
    961         ccsid = (unsigned int) forms->value;
    962         forms++;
    963         }
    964 
    965       /* Do the conversion. */
    966 
    967       lforms[nargs].value = value;
    968 
    969       if(Curl_formadd_convert(lforms, nargs, -1, ccsid) < 0) {
    970         result = CURL_FORMADD_MEMORY;
    971         break;
    972         }
    973 
    974       value = lforms[nargs].value;
    975       }
    976 
    977     if(result != CURL_FORMADD_OK)
    978       break;
    979 
    980     lforms[nargs].value = value;
    981     lforms[nargs++].option = option;
    982     }
    983 
    984   va_end(arg);
    985 
    986   /* Convert the name and the last content, now that we know their lengths. */
    987 
    988   if(result == CURL_FORMADD_OK && namex >= 0) {
    989     if(Curl_formadd_convert(lforms, namex, namelengthx, nameccsid) < 0)
    990       result = CURL_FORMADD_MEMORY;
    991     else
    992       lforms[namex].option = CURLFORM_COPYNAME;         /* Force copy. */
    993     }
    994 
    995   if(result == CURL_FORMADD_OK) {
    996     if(Curl_formadd_convert(lforms, contentx, lengthx, contentccsid) < 0)
    997       result = CURL_FORMADD_MEMORY;
    998     else
    999       contentx = -1;
   1000     }
   1001 
   1002   /* Do the formadd with our converted parameters. */
   1003 
   1004   if(result == CURL_FORMADD_OK) {
   1005     lforms[nargs].option = CURLFORM_END;
   1006     result = curl_formadd(httppost, last_post,
   1007                           CURLFORM_ARRAY, lforms, CURLFORM_END);
   1008     }
   1009 
   1010   /* Terminate. */
   1011 
   1012   Curl_formadd_release_local(lforms, nargs, contentx);
   1013   return result;
   1014 }
   1015 
   1016 
   1017 struct cfcdata {
   1018   curl_formget_callback append;
   1019   void *                arg;
   1020   unsigned int          ccsid;
   1021 };
   1022 
   1023 
   1024 static size_t
   1025 Curl_formget_callback_ccsid(void *arg, const char *buf, size_t len)
   1026 {
   1027   struct cfcdata *p;
   1028   char *b;
   1029   int l;
   1030   size_t ret;
   1031 
   1032   p = (struct cfcdata *) arg;
   1033 
   1034   if((long) len <= 0)
   1035     return (*p->append)(p->arg, buf, len);
   1036 
   1037   b = malloc(MAX_CONV_EXPANSION * len);
   1038 
   1039   if(!b)
   1040     return (size_t) -1;
   1041 
   1042   l = convert(b, MAX_CONV_EXPANSION * len, p->ccsid, buf, len, ASCII_CCSID);
   1043 
   1044   if(l < 0) {
   1045     free(b);
   1046     return (size_t) -1;
   1047     }
   1048 
   1049   ret = (*p->append)(p->arg, b, l);
   1050   free(b);
   1051   return ret == l ? len : -1;
   1052 }
   1053 
   1054 
   1055 int
   1056 curl_formget_ccsid(struct curl_httppost *form, void *arg,
   1057                    curl_formget_callback append, unsigned int ccsid)
   1058 {
   1059   struct cfcdata lcfc;
   1060 
   1061   lcfc.append = append;
   1062   lcfc.arg = arg;
   1063   lcfc.ccsid = ccsid;
   1064   return curl_formget(form, (void *) &lcfc, Curl_formget_callback_ccsid);
   1065 }
   1066 
   1067 
   1068 CURLcode
   1069 curl_easy_setopt_ccsid(CURL *easy, CURLoption tag, ...)
   1070 {
   1071   CURLcode result;
   1072   va_list arg;
   1073   char *s;
   1074   char *cp = NULL;
   1075   unsigned int ccsid;
   1076   curl_off_t pfsize;
   1077   struct Curl_easy *data = easy;
   1078 
   1079   va_start(arg, tag);
   1080 
   1081   switch(tag) {
   1082 
   1083   /* BEGIN TRANSLATABLE STRING OPTIONS */
   1084   /* Keep option symbols in alphanumeric order and retain the BEGIN/END
   1085      armor comments. */
   1086   case CURLOPT_ABSTRACT_UNIX_SOCKET:
   1087   case CURLOPT_ACCEPT_ENCODING:
   1088   case CURLOPT_ALTSVC:
   1089   case CURLOPT_AWS_SIGV4:
   1090   case CURLOPT_CAINFO:
   1091   case CURLOPT_CAPATH:
   1092   case CURLOPT_COOKIE:
   1093   case CURLOPT_COOKIEFILE:
   1094   case CURLOPT_COOKIEJAR:
   1095   case CURLOPT_COOKIELIST:
   1096   case CURLOPT_CRLFILE:
   1097   case CURLOPT_CUSTOMREQUEST:
   1098   case CURLOPT_DEFAULT_PROTOCOL:
   1099   case CURLOPT_DNS_INTERFACE:
   1100   case CURLOPT_DNS_LOCAL_IP4:
   1101   case CURLOPT_DNS_LOCAL_IP6:
   1102   case CURLOPT_DNS_SERVERS:
   1103   case CURLOPT_DOH_URL:
   1104   case CURLOPT_ECH:
   1105   case CURLOPT_EGDSOCKET:
   1106   case CURLOPT_FTPPORT:
   1107   case CURLOPT_FTP_ACCOUNT:
   1108   case CURLOPT_FTP_ALTERNATIVE_TO_USER:
   1109   case CURLOPT_HAPROXY_CLIENT_IP:
   1110   case CURLOPT_HSTS:
   1111   case CURLOPT_INTERFACE:
   1112   case CURLOPT_ISSUERCERT:
   1113   case CURLOPT_KEYPASSWD:
   1114   case CURLOPT_KRBLEVEL:
   1115   case CURLOPT_LOGIN_OPTIONS:
   1116   case CURLOPT_MAIL_AUTH:
   1117   case CURLOPT_MAIL_FROM:
   1118   case CURLOPT_NETRC_FILE:
   1119   case CURLOPT_NOPROXY:
   1120   case CURLOPT_PASSWORD:
   1121   case CURLOPT_PINNEDPUBLICKEY:
   1122   case CURLOPT_PRE_PROXY:
   1123   case CURLOPT_PROTOCOLS_STR:
   1124   case CURLOPT_PROXY:
   1125   case CURLOPT_PROXYPASSWORD:
   1126   case CURLOPT_PROXYUSERNAME:
   1127   case CURLOPT_PROXYUSERPWD:
   1128   case CURLOPT_PROXY_CAINFO:
   1129   case CURLOPT_PROXY_CAPATH:
   1130   case CURLOPT_PROXY_CRLFILE:
   1131   case CURLOPT_PROXY_ISSUERCERT:
   1132   case CURLOPT_PROXY_KEYPASSWD:
   1133   case CURLOPT_PROXY_PINNEDPUBLICKEY:
   1134   case CURLOPT_PROXY_SERVICE_NAME:
   1135   case CURLOPT_PROXY_SSLCERT:
   1136   case CURLOPT_PROXY_SSLCERTTYPE:
   1137   case CURLOPT_PROXY_SSLKEY:
   1138   case CURLOPT_PROXY_SSLKEYTYPE:
   1139   case CURLOPT_PROXY_SSL_CIPHER_LIST:
   1140   case CURLOPT_PROXY_TLS13_CIPHERS:
   1141   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
   1142   case CURLOPT_PROXY_TLSAUTH_TYPE:
   1143   case CURLOPT_PROXY_TLSAUTH_USERNAME:
   1144   case CURLOPT_RANDOM_FILE:
   1145   case CURLOPT_RANGE:
   1146   case CURLOPT_REDIR_PROTOCOLS_STR:
   1147   case CURLOPT_REFERER:
   1148   case CURLOPT_REQUEST_TARGET:
   1149   case CURLOPT_RTSP_SESSION_ID:
   1150   case CURLOPT_RTSP_STREAM_URI:
   1151   case CURLOPT_RTSP_TRANSPORT:
   1152   case CURLOPT_SASL_AUTHZID:
   1153   case CURLOPT_SERVICE_NAME:
   1154   case CURLOPT_SOCKS5_GSSAPI_SERVICE:
   1155   case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
   1156   case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
   1157   case CURLOPT_SSH_KNOWNHOSTS:
   1158   case CURLOPT_SSH_PRIVATE_KEYFILE:
   1159   case CURLOPT_SSH_PUBLIC_KEYFILE:
   1160   case CURLOPT_SSLCERT:
   1161   case CURLOPT_SSLCERTTYPE:
   1162   case CURLOPT_SSLENGINE:
   1163   case CURLOPT_SSLKEY:
   1164   case CURLOPT_SSLKEYTYPE:
   1165   case CURLOPT_SSL_CIPHER_LIST:
   1166   case CURLOPT_SSL_EC_CURVES:
   1167   case CURLOPT_SSL_SIGNATURE_ALGORITHMS:
   1168   case CURLOPT_TLS13_CIPHERS:
   1169   case CURLOPT_TLSAUTH_PASSWORD:
   1170   case CURLOPT_TLSAUTH_TYPE:
   1171   case CURLOPT_TLSAUTH_USERNAME:
   1172   case CURLOPT_UNIX_SOCKET_PATH:
   1173   case CURLOPT_URL:
   1174   case CURLOPT_USERAGENT:
   1175   case CURLOPT_USERNAME:
   1176   case CURLOPT_USERPWD:
   1177   case CURLOPT_XOAUTH2_BEARER:
   1178   /* END TRANSLATABLE STRING OPTIONS */
   1179     s = va_arg(arg, char *);
   1180     ccsid = va_arg(arg, unsigned int);
   1181 
   1182     if(s) {
   1183       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
   1184 
   1185       if(!s) {
   1186         result = CURLE_OUT_OF_MEMORY;
   1187         break;
   1188       }
   1189     }
   1190 
   1191     result = curl_easy_setopt(easy, tag, s);
   1192     free(s);
   1193     break;
   1194 
   1195   case CURLOPT_COPYPOSTFIELDS:
   1196     /* Special case: byte count may have been given by CURLOPT_POSTFIELDSIZE
   1197        prior to this call. In this case, convert the given byte count and
   1198        replace the length according to the conversion result. */
   1199     s = va_arg(arg, char *);
   1200     ccsid = va_arg(arg, unsigned int);
   1201 
   1202     pfsize = data->set.postfieldsize;
   1203 
   1204     if(!s || !pfsize || ccsid == NOCONV_CCSID || ccsid == ASCII_CCSID) {
   1205       result = curl_easy_setopt(easy, CURLOPT_COPYPOSTFIELDS, s);
   1206       break;
   1207     }
   1208 
   1209     if(pfsize == -1) {
   1210       /* Data is null-terminated. */
   1211       s = dynconvert(ASCII_CCSID, s, -1, ccsid);
   1212 
   1213       if(!s) {
   1214         result = CURLE_OUT_OF_MEMORY;
   1215         break;
   1216         }
   1217       }
   1218     else {
   1219       /* Data length specified. */
   1220       size_t len;
   1221 
   1222       if(pfsize < 0 || pfsize > SIZE_MAX) {
   1223         result = CURLE_OUT_OF_MEMORY;
   1224         break;
   1225       }
   1226 
   1227       len = pfsize;
   1228       pfsize = len * MAX_CONV_EXPANSION;
   1229 
   1230       if(pfsize > SIZE_MAX)
   1231         pfsize = SIZE_MAX;
   1232 
   1233       cp = malloc(pfsize);
   1234 
   1235       if(!cp) {
   1236         result = CURLE_OUT_OF_MEMORY;
   1237         break;
   1238       }
   1239 
   1240       pfsize = convert(cp, pfsize, ASCII_CCSID, s, len, ccsid);
   1241 
   1242       if(pfsize < 0) {
   1243         result = CURLE_OUT_OF_MEMORY;
   1244         break;
   1245       }
   1246 
   1247       data->set.postfieldsize = pfsize;         /* Replace data size. */
   1248       s = cp;
   1249     }
   1250 
   1251     result = curl_easy_setopt(easy, CURLOPT_POSTFIELDS, s);
   1252     data->set.str[STRING_COPYPOSTFIELDS] = s;   /* Give to library. */
   1253     break;
   1254 
   1255   default:
   1256     if(tag / 10000 == CURLOPTTYPE_BLOB) {
   1257       struct curl_blob *bp = va_arg(arg, struct curl_blob *);
   1258       struct curl_blob blob;
   1259 
   1260       ccsid = va_arg(arg, unsigned int);
   1261 
   1262       if(bp && bp->data && bp->len &&
   1263          ccsid != NOCONV_CCSID && ccsid != ASCII_CCSID) {
   1264         pfsize = (curl_off_t) bp->len * MAX_CONV_EXPANSION;
   1265 
   1266         if(pfsize > SIZE_MAX)
   1267           pfsize = SIZE_MAX;
   1268 
   1269         cp = malloc(pfsize);
   1270 
   1271         if(!cp) {
   1272           result = CURLE_OUT_OF_MEMORY;
   1273           break;
   1274         }
   1275 
   1276         pfsize = convert(cp, pfsize, ASCII_CCSID, bp->data, bp->len, ccsid);
   1277 
   1278         if(pfsize < 0) {
   1279           result = CURLE_OUT_OF_MEMORY;
   1280           break;
   1281         }
   1282 
   1283         blob.data = cp;
   1284         blob.len = pfsize;
   1285         blob.flags = bp->flags | CURL_BLOB_COPY;
   1286         bp = &blob;
   1287       }
   1288       result = curl_easy_setopt(easy, tag, &blob);
   1289       break;
   1290     }
   1291     FALLTHROUGH();
   1292   case CURLOPT_ERRORBUFFER:                     /* This is an output buffer. */
   1293     result = Curl_vsetopt(easy, tag, arg);
   1294     break;
   1295   }
   1296 
   1297   va_end(arg);
   1298   free(cp);
   1299   return result;
   1300 }
   1301 
   1302 
   1303 /* ILE/RPG helper functions. */
   1304 
   1305 char *
   1306 curl_form_long_value(long value)
   1307 {
   1308   /* ILE/RPG cannot cast an integer to a pointer. This procedure does it. */
   1309 
   1310   return (char *) value;
   1311 }
   1312 
   1313 
   1314 CURLcode
   1315 curl_easy_setopt_RPGnum_(CURL *easy, CURLoption tag, curl_off_t arg)
   1316 {
   1317   /* ILE/RPG procedure overloading cannot discriminate between different
   1318      size and/or signedness of format arguments. This provides a generic
   1319      wrapper that adapts size to the given tag expectation.
   1320      This procedure is not intended to be explicitly called from user code. */
   1321   if(tag / 10000 != CURLOPTTYPE_OFF_T)
   1322     return curl_easy_setopt(easy, tag, (long) arg);
   1323   return curl_easy_setopt(easy, tag, arg);
   1324 }
   1325 
   1326 
   1327 CURLcode
   1328 curl_multi_setopt_RPGnum_(CURLM *multi, CURLMoption tag, curl_off_t arg)
   1329 {
   1330   /* Likewise, for multi handle. */
   1331   if(tag / 10000 != CURLOPTTYPE_OFF_T)
   1332     return curl_multi_setopt(multi, tag, (long) arg);
   1333   return curl_multi_setopt(multi, tag, arg);
   1334 }
   1335 
   1336 
   1337 char *
   1338 curl_pushheader_bynum_cssid(struct curl_pushheaders *h,
   1339                             size_t num, unsigned int ccsid)
   1340 {
   1341   char *d = (char *) NULL;
   1342   char *s = curl_pushheader_bynum(h, num);
   1343 
   1344   if(s)
   1345     d = dynconvert(ccsid, s, -1, ASCII_CCSID);
   1346 
   1347   return d;
   1348 }
   1349 
   1350 
   1351 char *
   1352 curl_pushheader_byname_ccsid(struct curl_pushheaders *h, const char *header,
   1353                              unsigned int ccsidin, unsigned int ccsidout)
   1354 {
   1355   char *d = (char *) NULL;
   1356 
   1357   if(header) {
   1358     header = dynconvert(ASCII_CCSID, header, -1, ccsidin);
   1359 
   1360     if(header) {
   1361       char *s = curl_pushheader_byname(h, header);
   1362       free((char *) header);
   1363 
   1364       if(s)
   1365         d = dynconvert(ccsidout, s, -1, ASCII_CCSID);
   1366     }
   1367   }
   1368 
   1369   return d;
   1370 }
   1371 
   1372 static CURLcode
   1373 mime_string_call(curl_mimepart *part, const char *string, unsigned int ccsid,
   1374                  CURLcode (*mimefunc)(curl_mimepart *part, const char *string))
   1375 {
   1376   char *s = (char *) NULL;
   1377   CURLcode result;
   1378 
   1379   if(!string)
   1380     return mimefunc(part, string);
   1381   s = dynconvert(ASCII_CCSID, string, -1, ccsid);
   1382   if(!s)
   1383     return CURLE_OUT_OF_MEMORY;
   1384 
   1385   result = mimefunc(part, s);
   1386   free(s);
   1387   return result;
   1388 }
   1389 
   1390 CURLcode
   1391 curl_mime_name_ccsid(curl_mimepart *part, const char *name, unsigned int ccsid)
   1392 {
   1393   return mime_string_call(part, name, ccsid, curl_mime_name);
   1394 }
   1395 
   1396 CURLcode
   1397 curl_mime_filename_ccsid(curl_mimepart *part,
   1398                          const char *filename, unsigned int ccsid)
   1399 {
   1400   return mime_string_call(part, filename, ccsid, curl_mime_filename);
   1401 }
   1402 
   1403 CURLcode
   1404 curl_mime_type_ccsid(curl_mimepart *part,
   1405                      const char *mimetype, unsigned int ccsid)
   1406 {
   1407   return mime_string_call(part, mimetype, ccsid, curl_mime_type);
   1408 }
   1409 
   1410 CURLcode
   1411 curl_mime_encoder_ccsid(curl_mimepart *part,
   1412                        const char *encoding, unsigned int ccsid)
   1413 {
   1414   return mime_string_call(part, encoding, ccsid, curl_mime_encoder);
   1415 }
   1416 
   1417 CURLcode
   1418 curl_mime_filedata_ccsid(curl_mimepart *part,
   1419                          const char *filename, unsigned int ccsid)
   1420 {
   1421   return mime_string_call(part, filename, ccsid, curl_mime_filedata);
   1422 }
   1423 
   1424 CURLcode
   1425 curl_mime_data_ccsid(curl_mimepart *part,
   1426                      const char *data, size_t datasize, unsigned int ccsid)
   1427 {
   1428   char *s = (char *) NULL;
   1429   CURLcode result;
   1430 
   1431   if(!data)
   1432     return curl_mime_data(part, data, datasize);
   1433   s = dynconvert(ASCII_CCSID, data, datasize, ccsid);
   1434   if(!s)
   1435     return CURLE_OUT_OF_MEMORY;
   1436 
   1437   result = curl_mime_data(part, s, datasize);
   1438   free(s);
   1439   return result;
   1440 }
   1441 
   1442 CURLUcode
   1443 curl_url_get_ccsid(CURLU *handle, CURLUPart what, char **part,
   1444                    unsigned int flags, unsigned int ccsid)
   1445 {
   1446   char *s = (char *)NULL;
   1447   CURLUcode result;
   1448 
   1449   if(!part)
   1450     return CURLUE_BAD_PARTPOINTER;
   1451 
   1452   *part = (char *)NULL;
   1453   result = curl_url_get(handle, what, &s, flags);
   1454   if(result == CURLUE_OK) {
   1455     if(s) {
   1456       *part = dynconvert(ccsid, s, -1, ASCII_CCSID);
   1457       if(!*part)
   1458         result = CURLUE_OUT_OF_MEMORY;
   1459     }
   1460   }
   1461   if(s)
   1462     free(s);
   1463   return result;
   1464 }
   1465 
   1466 CURLUcode
   1467 curl_url_set_ccsid(CURLU *handle, CURLUPart what, const char *part,
   1468                    unsigned int flags, unsigned int ccsid)
   1469 {
   1470   char *s = (char *)NULL;
   1471   CURLUcode result;
   1472 
   1473   if(part) {
   1474     s = dynconvert(ASCII_CCSID, part, -1, ccsid);
   1475     if(!s)
   1476       return CURLUE_OUT_OF_MEMORY;
   1477   }
   1478   result = curl_url_set(handle, what, s, flags);
   1479   if(s)
   1480     free(s);
   1481   return result;
   1482 }
   1483 
   1484 const struct curl_easyoption *
   1485 curl_easy_option_by_name_ccsid(const char *name, unsigned int ccsid)
   1486 {
   1487   const struct curl_easyoption *option = NULL;
   1488 
   1489   if(name) {
   1490     char *s = dynconvert(ASCII_CCSID, name, -1, ccsid);
   1491 
   1492     if(s) {
   1493       option = curl_easy_option_by_name(s);
   1494       free(s);
   1495     }
   1496   }
   1497 
   1498   return option;
   1499 }
   1500 
   1501 /* Return option name in the given ccsid. */
   1502 const char *
   1503 curl_easy_option_get_name_ccsid(const struct curl_easyoption *option,
   1504                                 unsigned int ccsid)
   1505 {
   1506   char *name = NULL;
   1507 
   1508   if(option && option->name)
   1509     name = dynconvert(ccsid, option->name, -1, ASCII_CCSID);
   1510 
   1511   return (const char *) name;
   1512 }
   1513 
   1514 /* Header API CCSID support. */
   1515 CURLHcode
   1516 curl_easy_header_ccsid(CURL *easy, const char *name, size_t index,
   1517                        unsigned int origin, int request,
   1518                        struct curl_header **hout, unsigned int ccsid)
   1519 {
   1520   CURLHcode result = CURLHE_BAD_ARGUMENT;
   1521 
   1522   if(name) {
   1523     char *s = dynconvert(ASCII_CCSID, name, -1, ccsid);
   1524 
   1525     result = CURLHE_OUT_OF_MEMORY;
   1526     if(s) {
   1527       result = curl_easy_header(easy, s, index, origin, request, hout);
   1528       free(s);
   1529     }
   1530   }
   1531 
   1532   return result;
   1533 }