sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

os2iconv.c (7070B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 
     22 /*
     23    Implementation iconv via OS/2 conversion objects API.
     24 
     25    Andrey Vasilkin.
     26 */
     27 
     28 #define ICONV_THREAD_SAFE 1
     29 
     30 #include "geniconv.h"
     31 #define _ULS_CALLCONV_
     32 #define CALLCONV _System
     33 #include <uconv.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #ifdef ICONV_THREAD_SAFE
     38 #define INCL_DOSSEMAPHORES
     39 #define INCL_DOSERRORS
     40 #include <os2.h>
     41 #endif
     42 #include "os2cp.h"
     43 
     44 #if !defined(min)
     45 #define min(a, b) (((a) < (b)) ? (a) : (b))
     46 #endif
     47 
     48 #define MAX_CP_NAME_LEN 64
     49 
     50 typedef struct iuconv_obj {
     51   UconvObject	uo_tocode;
     52   UconvObject	uo_fromcode;
     53   int		buf_len;
     54   UniChar	*buf;
     55 #ifdef ICONV_THREAD_SAFE
     56   HMTX		hMtx;
     57 #endif
     58 } iuconv_obj;
     59 
     60 
     61 static int _createUconvObj(const char *code, UconvObject *uobj)
     62 {
     63     UniChar uc_code[MAX_CP_NAME_LEN];
     64     int i;
     65     const char *ch = code;
     66 
     67     if (code == NULL)
     68         uc_code[0] = 0;
     69     else {
     70         for (i = 0; i < MAX_CP_NAME_LEN; i++) {
     71             uc_code[i] = (unsigned short)*ch;
     72             if (! (*ch))
     73                 break;
     74             ch++;
     75         }
     76     }
     77 
     78     return UniCreateUconvObject(uc_code, uobj);
     79 }
     80 
     81 static int uconv_open(const char *code, UconvObject *uobj)
     82 {
     83     int rc;
     84 
     85     if (!stricmp(code, "UTF-16")) {
     86         *uobj = NULL;
     87         return ULS_SUCCESS;
     88     }
     89 
     90     rc = _createUconvObj(code, uobj);
     91     if (rc != ULS_SUCCESS) {
     92         unsigned long cp = os2cpFromName((char *)code);
     93         char cp_name[16];
     94 
     95         if (cp != 0 && _snprintf(cp_name, sizeof(cp_name), "IBM-%u", cp) > 0)
     96             rc = _createUconvObj(cp_name, uobj);
     97     }
     98 
     99     return rc;
    100 }
    101 
    102 
    103 extern iconv_t _System os2_iconv_open(const char* tocode, const char* fromcode)
    104 {
    105     UconvObject uo_tocode;
    106     UconvObject uo_fromcode;
    107     int rc;
    108     iuconv_obj *iuobj;
    109 
    110     if (tocode == NULL)
    111         tocode = "";
    112 
    113     if (fromcode == NULL)
    114         fromcode = "";
    115 
    116     if (stricmp(tocode, fromcode) != 0) {
    117         rc = uconv_open(fromcode, &uo_fromcode);
    118         if (rc != ULS_SUCCESS) {
    119             errno = EINVAL;
    120             return (iconv_t)(-1);
    121         }
    122 
    123         rc = uconv_open(tocode, &uo_tocode);
    124         if (rc != ULS_SUCCESS) {
    125             UniFreeUconvObject(uo_fromcode);
    126             errno = EINVAL;
    127             return (iconv_t)(-1);
    128         }
    129     } else {
    130         uo_tocode = NULL;
    131         uo_fromcode = NULL;
    132     }
    133 
    134     iuobj = (iuconv_obj *) malloc(sizeof(iuconv_obj));
    135     iuobj->uo_tocode = uo_tocode;
    136     iuobj->uo_fromcode = uo_fromcode;
    137     iuobj->buf_len = 0;
    138     iuobj->buf = NULL;
    139 #ifdef ICONV_THREAD_SAFE
    140     DosCreateMutexSem(NULL, &iuobj->hMtx, 0, FALSE);
    141 #endif
    142 
    143     return iuobj;
    144 }
    145 
    146 extern size_t _System os2_iconv(iconv_t cd, char* * inbuf,
    147                                 size_t *inbytesleft,
    148                                 char* * outbuf, size_t *outbytesleft)
    149 {
    150     UconvObject uo_tocode = ((iuconv_obj *)(cd))->uo_tocode;
    151     UconvObject uo_fromcode = ((iuconv_obj *)(cd))->uo_fromcode;
    152     size_t nonIdenticalConv = 0;
    153     UniChar *uc_buf;
    154     size_t uc_buf_len;
    155     UniChar **uc_str;
    156     size_t *uc_str_len;
    157     int rc;
    158     size_t ret = (size_t)(-1);
    159 
    160     if (uo_tocode == NULL && uo_fromcode == NULL) {
    161         uc_buf_len = min(*inbytesleft, *outbytesleft);
    162         memcpy(*outbuf, *inbuf, uc_buf_len);
    163         *inbytesleft -= uc_buf_len;
    164         *outbytesleft -= uc_buf_len;
    165         outbuf += uc_buf_len;
    166         inbuf += uc_buf_len;
    167         return uc_buf_len;
    168     }
    169 
    170 #ifdef ICONV_THREAD_SAFE
    171     DosRequestMutexSem(((iuconv_obj *)(cd))->hMtx, SEM_INDEFINITE_WAIT);
    172 #endif
    173 
    174     if (uo_tocode && uo_fromcode &&
    175         (((iuconv_obj *)cd)->buf_len >> 1) < *inbytesleft) {
    176         if (((iuconv_obj *)cd)->buf != NULL)
    177             free(((iuconv_obj *)cd)->buf);
    178         ((iuconv_obj *)cd)->buf_len = *inbytesleft << 1;
    179         ((iuconv_obj *)cd)->buf = (UniChar *)malloc(((iuconv_obj *)cd)->buf_len);
    180     }
    181 
    182     if (uo_fromcode) {
    183         if (uo_tocode) {
    184             uc_buf = ((iuconv_obj *)cd)->buf;
    185             uc_buf_len = ((iuconv_obj *)cd)->buf_len;
    186             uc_str = &uc_buf;
    187         } else {
    188             uc_str = (UniChar **)outbuf;
    189             uc_buf_len = *outbytesleft;
    190         }
    191         uc_buf_len = uc_buf_len >> 1;
    192         uc_str_len = &uc_buf_len;
    193         rc = UniUconvToUcs(uo_fromcode, (void **)inbuf, inbytesleft,
    194                            uc_str, uc_str_len, &nonIdenticalConv);
    195         uc_buf_len = uc_buf_len << 1;
    196         if (!uo_tocode)
    197             *outbytesleft = uc_buf_len;
    198 
    199         if (rc != ULS_SUCCESS) {
    200             errno = EILSEQ;
    201             goto done;
    202         } else if (*inbytesleft && !*uc_str_len) {
    203             errno = E2BIG;
    204             goto done;
    205         }
    206 
    207         if (!uo_tocode)
    208             return nonIdenticalConv;
    209 
    210         uc_buf = ((iuconv_obj *)cd)->buf;
    211         uc_buf_len = ((iuconv_obj *)cd)->buf_len - uc_buf_len;
    212         uc_str = &uc_buf;
    213         uc_str_len = &uc_buf_len;
    214     } else {
    215         uc_str = (UniChar **)inbuf;
    216         uc_str_len = inbytesleft;
    217     }
    218 
    219     *uc_str_len = *uc_str_len>>1;
    220     rc = UniUconvFromUcs(uo_tocode, uc_str, uc_str_len, (void **)outbuf,
    221                          outbytesleft, &nonIdenticalConv);
    222     if (rc != ULS_SUCCESS) {
    223         switch (rc) {
    224         case ULS_BUFFERFULL:
    225             errno = E2BIG;
    226             break;
    227         case ULS_ILLEGALSEQUENCE:
    228             errno = EILSEQ;
    229             break;
    230         case ULS_INVALID:
    231             errno = EINVAL;
    232             break;
    233         }
    234         goto done;
    235     } else if (*uc_str_len && !*outbytesleft) {
    236         errno = E2BIG;
    237         goto done;
    238     }
    239 
    240     ret = nonIdenticalConv;
    241 
    242 done:
    243 
    244 #ifdef ICONV_THREAD_SAFE
    245     DosReleaseMutexSem(((iuconv_obj *)cd)->hMtx);
    246 #endif
    247     return ret;
    248 }
    249 
    250 int _System os2_iconv_close(iconv_t cd)
    251 {
    252     if (!cd) return 0;
    253 
    254 #ifdef ICONV_THREAD_SAFE
    255     DosCloseMutexSem(((iuconv_obj *)cd)->hMtx);
    256 #endif
    257     if (((iuconv_obj *)cd)->uo_tocode != NULL)
    258         UniFreeUconvObject(((iuconv_obj *)cd)->uo_tocode);
    259     if (((iuconv_obj *)cd)->uo_fromcode != NULL)
    260         UniFreeUconvObject(((iuconv_obj *)cd)->uo_fromcode);
    261 
    262     if (((iuconv_obj *)cd)->buf != NULL)
    263         free(((iuconv_obj *)cd)->buf);
    264 
    265     free(cd);
    266 
    267     return 0;
    268 }
    269 
    270 /* vi: set ts=4 sw=4 expandtab: */