Patrick Monnerat | 17951ea | 2014-03-04 16:42:19 +0100 | [diff] [blame] | 1 | /** |
| 2 | *** iconv_open(), iconv(), iconv_close() wrappers for the OS/400. |
| 3 | *** |
| 4 | *** See Copyright for the status of this software. |
| 5 | *** |
| 6 | *** Author: Patrick Monnerat <pm@datasphere.ch>, DATASPHERE S.A. |
| 7 | **/ |
| 8 | |
| 9 | #include <errno.h> |
| 10 | #include <stdio.h> |
| 11 | #include <stdlib.h> |
| 12 | |
| 13 | #include "/QIBM/include/iconv.h" /* Force system definition. */ |
| 14 | |
| 15 | #define USE_SYSTEM_ICONV |
| 16 | #include "iconv.h" /* Use local definitions. */ |
| 17 | |
| 18 | |
| 19 | |
| 20 | /** |
| 21 | *** Bring-in the name-->CCSID mapping DFA tables. |
| 22 | **/ |
| 23 | |
| 24 | #include "ianatables.c" |
| 25 | |
| 26 | |
| 27 | |
| 28 | static int |
| 29 | findEncoding(const unsigned char * * namep) |
| 30 | |
| 31 | { |
| 32 | t_staterange curstate; |
| 33 | t_ccsid ccsid; |
| 34 | t_ccsid final; |
| 35 | t_transrange l; |
| 36 | t_transrange h; |
| 37 | const unsigned char * name; |
| 38 | |
| 39 | /** |
| 40 | *** Get the CCSID correspong to the name at *`namep'. |
| 41 | *** If success, update pointer at `namep' to 1st byte after matched |
| 42 | *** name and return the CCSID. |
| 43 | *** If failure, set errno and return -1. |
| 44 | **/ |
| 45 | |
| 46 | if (!namep || !(name = *namep)) { |
| 47 | errno = EINVAL; |
| 48 | return -1; |
| 49 | } |
| 50 | |
| 51 | curstate = 0; |
| 52 | final = 0; |
| 53 | |
| 54 | for (;;) { |
| 55 | if (curstate < sizeof final_array / sizeof final_array[0]) |
| 56 | if (final_array[curstate]) { |
| 57 | final = final_array[curstate]; |
| 58 | *namep = name; |
| 59 | } |
| 60 | |
| 61 | l = trans_array[curstate] - 1; |
| 62 | h = trans_array[curstate + 1]; |
| 63 | |
| 64 | do { |
| 65 | if (++l >= h) { |
| 66 | if (!final) { |
| 67 | errno = EINVAL; |
| 68 | return -1; |
| 69 | } |
| 70 | |
| 71 | return final - 1; |
| 72 | } |
| 73 | } while (label_array[l] != *name); |
| 74 | |
| 75 | curstate = goto_array[l]; |
| 76 | name++; |
| 77 | } |
| 78 | |
| 79 | /* NOTREACHED. */ |
| 80 | } |
| 81 | |
| 82 | |
| 83 | static void |
| 84 | makeos400codename(char * buf, unsigned int ccsid) |
| 85 | |
| 86 | { |
| 87 | ccsid &= 0xFFFF; |
| 88 | memset(buf, 0, 32); |
| 89 | sprintf(buf, "IBMCCSID%05u0000000", ccsid); |
| 90 | } |
| 91 | |
| 92 | |
| 93 | Iconv_t |
| 94 | IconvOpen(const char * tocode, const char * fromcode) |
| 95 | |
| 96 | { |
| 97 | int toccsid = findEncoding(&tocode); |
| 98 | int fromccsid = findEncoding(&fromcode); |
| 99 | char fromibmccsid[33]; |
| 100 | char toibmccsid[33]; |
| 101 | iconv_t * cd; |
| 102 | |
| 103 | if (toccsid < 0 || fromccsid < 0) |
| 104 | return (Iconv_t) -1; |
| 105 | |
| 106 | makeos400codename(fromibmccsid, fromccsid); |
| 107 | makeos400codename(toibmccsid, toccsid); |
| 108 | memset(toibmccsid + 13, 0, sizeof toibmccsid - 13); |
| 109 | |
| 110 | cd = (iconv_t *) malloc(sizeof *cd); |
| 111 | |
| 112 | if (!cd) |
| 113 | return (Iconv_t) -1; |
| 114 | |
| 115 | *cd = iconv_open(toibmccsid, fromibmccsid); |
| 116 | |
| 117 | if (cd->return_value) { |
| 118 | free((char *) cd); |
| 119 | return (Iconv_t) -1; |
| 120 | } |
| 121 | |
| 122 | return (Iconv_t) cd; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | size_t |
| 127 | Iconv(Iconv_t cd, char * * inbuf, size_t * inbytesleft, |
| 128 | char * * outbuf, size_t * outbytesleft) |
| 129 | |
| 130 | { |
| 131 | if (!cd || cd == (Iconv_t) -1) { |
| 132 | errno = EINVAL; |
| 133 | return (size_t) -1; |
| 134 | } |
| 135 | |
| 136 | return iconv(*(iconv_t *) cd, inbuf, inbytesleft, outbuf, outbytesleft); |
| 137 | } |
| 138 | |
| 139 | |
| 140 | int |
| 141 | IconvClose(Iconv_t cd) |
| 142 | |
| 143 | { |
| 144 | if (!cd || cd == (Iconv_t) -1) { |
| 145 | errno = EINVAL; |
| 146 | return -1; |
| 147 | } |
| 148 | |
| 149 | if (iconv_close(*(iconv_t *) cd)) |
| 150 | return -1; |
| 151 | |
| 152 | free((char *) cd); |
| 153 | return 0; |
| 154 | } |