Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'newlib/libc/iconv/lib/ces_iso2022.c')
-rw-r--r--newlib/libc/iconv/lib/ces_iso2022.c332
1 files changed, 332 insertions, 0 deletions
diff --git a/newlib/libc/iconv/lib/ces_iso2022.c b/newlib/libc/iconv/lib/ces_iso2022.c
new file mode 100644
index 000000000..7753db56d
--- /dev/null
+++ b/newlib/libc/iconv/lib/ces_iso2022.c
@@ -0,0 +1,332 @@
+/*-
+ * Copyright (c) 1999,2000
+ * Konstantin Chuguev. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * iconv (Charset Conversion Library) v2.0
+ */
+#ifdef ENABLE_ICONV
+
+#include <_ansi.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+typedef struct {
+ _CONST char *sequence;
+ size_t length;
+ int prefix_type;
+} iconv_ces_iso2022_shift;
+
+enum { ICONV_PREFIX_STATE = 0, ICONV_PREFIX_LINE, ICONV_PREFIX_CHAR };
+
+static _CONST iconv_ces_iso2022_shift iso_shift[] = {
+ { "\x0f", 1, ICONV_PREFIX_STATE },
+ { "\x0e", 1, ICONV_PREFIX_LINE },
+ { "\x1bN", 2, ICONV_PREFIX_CHAR },
+ { "\x1bO", 2, ICONV_PREFIX_CHAR }
+};
+
+#define shift_num (sizeof(iso_shift) / sizeof(iconv_ces_iso2022_shift))
+
+typedef struct {
+ int nccs;
+ ucs_t previous_char;
+ int shift_index;
+ int shift_tab[shift_num];
+ char prefix_cache[128];
+ struct iconv_ccs ccs[1];
+} iconv_ces_iso2022_state;
+
+int
+_DEFUN(iconv_iso2022_init, (rptr, data, desc_data, num),
+ struct _reent *rptr _AND
+ _VOID_PTR *data _AND
+ _CONST _VOID_PTR desc_data _AND
+ size_t num)
+{
+ size_t stsz = sizeof(iconv_ces_iso2022_state) +
+ sizeof(struct iconv_ccs) * (num - 1);
+ int i;
+ iconv_ces_iso2022_state *state
+ = (iconv_ces_iso2022_state *)_malloc_r(rptr, stsz);
+
+ if (state == NULL)
+ return __errno_r(rptr);
+ bzero(state->prefix_cache, sizeof(state->prefix_cache));
+ for (i = 0; i < num; i++) {
+ _CONST iconv_ces_iso2022_ccs *ccsattr =
+ &(((_CONST iconv_ces_iso2022_ccs *)desc_data)[i]);
+ int res = iconv_ccs_init(rptr, &(state->ccs[i]), ccsattr->name);
+ if (res) {
+ while (--i >= 0)
+ state->ccs[i].close(rptr, &(state->ccs[i]));
+ _free_r(rptr, state);
+ return res;
+ }
+ if (ccsattr->designatorlen)
+ state->prefix_cache[(int)ccsattr->designator[0]] = 1;
+ if (ccsattr->shift >= 0)
+ state->prefix_cache[(int)iso_shift[ccsattr->shift].sequence[0]] = 1;
+ }
+ state->nccs = num;
+ iconv_iso2022_reset(state);
+ (iconv_ces_iso2022_state *)*data = state;
+ return 0;
+}
+
+#define state ((iconv_ces_iso2022_state *)data)
+
+int
+_DEFUN(iconv_iso2022_close, (rptr, data),
+ struct _reent *rptr _AND
+ _VOID_PTR data)
+{
+ int i, res = 0;
+
+ for (i = 0; i < state->nccs; i++)
+ res = state->ccs[i].close(rptr, &(state->ccs[i])) || res;
+ _free_r(rptr, data);
+ return res;
+}
+
+_VOID
+_DEFUN(iconv_iso2022_reset, (data), _VOID_PTR data)
+{
+ size_t i;
+
+ state->shift_index = 0;
+ state->shift_tab[0] = 0;
+ for (i = 1; i < shift_num; i++)
+ state->shift_tab[i] = -1;
+ state->previous_char = UCS_CHAR_NONE;
+}
+
+#undef state
+
+#define CES_STATE(ces) ((iconv_ces_iso2022_state *)((ces)->data))
+#define CES_CCSATTR(ces) ((_CONST iconv_ces_iso2022_ccs *) \
+ (((struct iconv_ces_desc *)((ces)->desc))->data))
+
+static _VOID
+_DEFUN(update_shift_state, (ces, ch),
+ _CONST struct iconv_ces *ces _AND
+ ucs_t ch)
+{
+ iconv_ces_iso2022_state *iso_state = CES_STATE(ces);
+ size_t i;
+
+ if (ch == '\n' && iso_state->previous_char == '\r') {
+ for (i = 0; i < shift_num; i ++) {
+ if (iso_shift[i].prefix_type != ICONV_PREFIX_STATE)
+ iso_state->shift_tab[i] = -1;
+ }
+ }
+ iso_state->previous_char = ch;
+}
+
+#define is_7_14bit(ccs) ((ccs)->nbits & 7)
+
+static ssize_t
+_DEFUN(cvt_ucs2iso, (ces, in, outbuf, outbytesleft, cs),
+ _CONST struct iconv_ces *ces _AND
+ ucs_t in _AND
+ unsigned char **outbuf _AND
+ size_t *outbytesleft _AND
+ int cs)
+{
+ iconv_ces_iso2022_state *iso_state = CES_STATE(ces);
+ _CONST iconv_ces_iso2022_ccs *ccsattr;
+ _CONST struct iconv_ccs *ccs;
+ ucs_t res;
+ size_t len = 0;
+ int need_designator, need_shift;
+
+ ccs = &(iso_state->ccs[cs]);
+ res = (in == UCS_CHAR_NONE) ?
+ in : ICONV_CCS_CONVERT_FROM_UCS(ccs, in);
+ if (in != UCS_CHAR_NONE) {
+ if (iso_shift[cs].prefix_type == ICONV_PREFIX_CHAR &&
+ !is_7_14bit(ccs)) {
+ if ((res & 0x8080) == 0)
+ return -1;
+ res &= 0x7F7F;
+ } else if (res & 0x8080)
+ return -1; /* Invalid/missing character in the output charset */
+ }
+ ccsattr = &(CES_CCSATTR(ces)[cs]);
+ if ((need_shift = (ccsattr->shift != iso_state->shift_index)))
+ len += iso_shift[ccsattr->shift].length;
+ if ((need_designator = (cs != iso_state->shift_tab[ccsattr->shift])))
+ len += ccsattr->designatorlen;
+ if (in != UCS_CHAR_NONE)
+ len += res & 0xFF00 ? 2 : 1;
+ if (len > *outbytesleft)
+ return 0; /* No space in output buffer */
+ if (need_designator && (len = ccsattr->designatorlen)) {
+ memcpy(*outbuf, ccsattr->designator, len);
+ (*outbuf) += len;
+ (*outbytesleft) -= len;
+ iso_state->shift_tab[ccsattr->shift] = cs;
+ }
+ if (need_shift && (len = iso_shift[ccsattr->shift].length)) {
+ memcpy(*outbuf, iso_shift[ccsattr->shift].sequence, len);
+ (*outbuf) += len;
+ (*outbytesleft) -= len;
+ if (iso_shift[ccsattr->shift].prefix_type != ICONV_PREFIX_CHAR)
+ iso_state->shift_index = ccsattr->shift;
+ }
+ if (in == UCS_CHAR_NONE)
+ return 1;
+ if (res & 0xFF00) {
+ *(unsigned char *)(*outbuf) ++ = res >> 8;
+ (*outbytesleft)--;
+ }
+ *(unsigned char *)(*outbuf) ++ = res;
+ (*outbytesleft) --;
+ update_shift_state(ces, res);
+ return 1;
+}
+
+ssize_t
+_DEFUN(iconv_iso2022_convert_from_ucs, (ces, in, outbuf, outbytesleft),
+ struct iconv_ces *ces _AND
+ ucs_t in _AND
+ unsigned char **outbuf _AND
+ size_t *outbytesleft)
+{
+ iconv_ces_iso2022_state *iso_state = CES_STATE(ces);
+ ssize_t res;
+ int cs, i;
+
+ if (in == UCS_CHAR_NONE)
+ return cvt_ucs2iso(ces, in, outbuf, outbytesleft, 0);
+ if (iconv_char32bit(in))
+ return -1;
+ cs = iso_state->shift_tab[iso_state->shift_index];
+ if ((res = cvt_ucs2iso(ces, in, outbuf, outbytesleft, cs)) >= 0)
+ return res;
+ for (i = 0; i < iso_state->nccs; i++) {
+ if (i == cs)
+ continue;
+ if ((res = cvt_ucs2iso(ces, in, outbuf, outbytesleft, i)) >= 0)
+ return res;
+ }
+ (*outbuf) ++;
+ (*outbytesleft) --;
+ return -1; /* No character in output charset */
+}
+
+static ucs_t
+_DEFUN(cvt_iso2ucs, (ccs, inbuf, inbytesleft, prefix_type),
+ _CONST struct iconv_ccs *ccs _AND
+ _CONST unsigned char **inbuf _AND
+ size_t *inbytesleft _AND
+ int prefix_type)
+{
+ size_t bytes = ccs->nbits > 8 ? 2 : 1;
+ ucs_t ch = **inbuf;
+
+ if (*inbytesleft < bytes)
+ return UCS_CHAR_NONE; /* Not enough bytes in the input buffer */
+ if (bytes == 2)
+ ch = (ch << 8) | *(++(*inbuf));
+ (*inbuf)++;
+ (*inbytesleft) -= bytes;
+ if (ch & 0x8080)
+ return UCS_CHAR_INVALID;
+ if (prefix_type == ICONV_PREFIX_CHAR && !is_7_14bit(ccs))
+ ch |= (bytes == 2) ? 0x8080 : 0x80;
+ return ICONV_CCS_CONVERT_TO_UCS(ccs, ch);
+}
+
+ucs_t
+_DEFUN(iconv_iso2022_convert_to_ucs, (ces, inbuf, inbytesleft),
+ struct iconv_ces *ces _AND
+ _CONST unsigned char **inbuf _AND
+ size_t *inbytesleft)
+{
+ iconv_ces_iso2022_state *iso_state = CES_STATE(ces);
+ _CONST iconv_ces_iso2022_ccs *ccsattr;
+ ucs_t res;
+ _CONST unsigned char *ptr = *inbuf;
+ unsigned char byte;
+ size_t len, left = *inbytesleft;
+ int i;
+
+ while (left) {
+ byte = *ptr;
+ if (byte & 0x80) {
+ (*inbuf)++;
+ (*inbytesleft) --;
+ return UCS_CHAR_INVALID;
+ }
+ if (!iso_state->prefix_cache[byte])
+ break;
+ for (i = 0; i < iso_state->nccs; i++) {
+ ccsattr = &(CES_CCSATTR(ces)[i]);
+ len = ccsattr->designatorlen;
+ if (len) {
+ if (len + 1 > left)
+ return UCS_CHAR_NONE;
+ if (memcmp(ptr, ccsattr->designator, len) == 0) {
+ iso_state->shift_tab[ccsattr->shift] = i;
+ ptr += len;
+ left -= len;
+ break;
+ }
+ }
+ len = iso_shift[ccsattr->shift].length;
+ if (len) {
+ if (len + 1 > left)
+ return UCS_CHAR_NONE;
+ if (memcmp(ptr,
+ iso_shift[ccsattr->shift].sequence, len) == 0) {
+ if (iso_shift[ccsattr->shift].prefix_type != ICONV_PREFIX_CHAR)
+ iso_state->shift_index = ccsattr->shift;
+ ptr += len;
+ left -= len;
+ break;
+ }
+ }
+ }
+ }
+ i = iso_state->shift_tab[iso_state->shift_index];
+ if (i < 0) {
+ (*inbuf) ++;
+ (*inbytesleft) --;
+ return UCS_CHAR_INVALID;
+ }
+ res = cvt_iso2ucs(&(iso_state->ccs[i]), &ptr, &left,
+ iso_shift[i].prefix_type);
+ if (res != UCS_CHAR_NONE) {
+ *inbuf = (_CONST char*)ptr;
+ *inbytesleft = left;
+ update_shift_state(ces, res);
+ }
+ return res;
+}
+
+#endif /* #ifdef ENABLE_ICONV */
+