#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/Xfuncs.h>
#include "Xct.h"
#include <stdio.h>
#define UsedGraphic 0x0001
#define UsedDirection 0x0002
typedef struct _XctPriv {
XctString ptr;
XctString ptrend;
unsigned flags;
XctHDirection *dirstack;
unsigned dirsize;
char **encodings;
unsigned enc_count;
XctString itembuf;
unsigned buf_count;
} *XctPriv;
#define IsMore(priv) ((priv)->ptr != (priv)->ptrend)
#define AmountLeft(priv) ((priv)->ptrend - (priv)->ptr)
#include <stdlib.h>
#define HT 0x09
#define NL 0x0a
#define ESC 0x1b
#define CSI 0x9b
#define IsLegalC0(data, c) (((c) == HT) || ((c) == NL) || \
(((data)->version > XctVersion) && \
((data)->flags & XctAcceptC0Extensions)))
#define IsLegalC1(priv, c) (((data)->version > XctVersion) && \
((data)->flags & XctAcceptC1Extensions))
#define IsI2(c) (((c) >= 0x20) && ((c) <= 0x2f))
#define IsI3(c) (((c) >= 0x30) && ((c) <= 0x3f))
#define IsESCF(c) (((c) >= 0x30) && ((c) <= 0x7e))
#define IsCSIF(c) (((c) >= 0x40) && ((c) <= 0x7e))
#define IsC0(c) ((c) <= 0x1f)
#define IsGL(c) (((c) >= 0x20) && ((c) <= 0x7f))
#define IsC1(c) (((c) >= 0x80) && ((c) <= 0x9f))
#define IsGR(c) ((c) >= 0xa0)
#define HasC 1
#define HasGL 2
#define HasGR 4
#define ToGL 8
static void ComputeGLGR(XctData);
static int Handle94GR(XctData, int);
static int Handle96GR(XctData, int);
static int HandleExtended(XctData data, int);
static int HandleGL(XctData, int);
static int HandleMultiGL(XctData, int);
static int HandleMultiGR(XctData data, int);
static void ShiftGRToGL(XctData, int);
static void
ComputeGLGR(register XctData data)
{
if ((data->GL_set_size == 94) && (data->GL_char_size == 1) &&
(data->GL[0] == '\102') &&
(data->GR_set_size == 96) && (data->GR_char_size == 1))
data->GLGR_encoding = data->GR_encoding;
else if ((data->GL_set_size == 94) && (data->GL_char_size == 1) &&
(data->GL[0] == '\112') &&
(data->GR_set_size == 94) && (data->GR_char_size == 1))
data->GLGR_encoding = data->GR_encoding;
else
data->GLGR_encoding = (char *)NULL;
}
static int
HandleGL(register XctData data, int c)
{
switch (c) {
case 0x42:
data->GL = "\102";
data->GL_encoding = "ISO8859-1";
break;
case 0x4a:
data->GL = "\112";
data->GL_encoding = "JISX0201.1976-0";
break;
default:
return 0;
}
data->GL_set_size = 94;
data->GL_char_size = 1;
ComputeGLGR(data);
return 1;
}
static int
HandleMultiGL(register XctData data, int c)
{
switch (c) {
case 0x41:
data->GL = "\101";
data->GL_encoding = "GB2312.1980-0";
break;
case 0x42:
data->GL = "\102";
data->GL_encoding = "JISX0208.1983-0";
break;
case 0x43:
data->GL = "\103";
data->GL_encoding = "KSC5601.1987-0";
break;
default:
return 0;
}
data->GL_set_size = 94;
data->GL_char_size = 2;
#ifdef notdef
if (c < 0x60)
data->GL_char_size = 2;
else if (c < 0x70)
data->GL_char_size = 3;
else
data->GL_char_size = 4;
#endif
data->GLGR_encoding = (char *)NULL;
return 1;
}
static int
Handle94GR(register XctData data, int c)
{
switch (c) {
case 0x49:
data->GR = "\111";
data->GR_encoding = "JISX0201.1976-0";
break;
default:
return 0;
}
data->priv->flags &= ~ToGL;
data->GR_set_size = 94;
data->GR_char_size = 1;
data->GLGR_encoding = (char *)NULL;
return 1;
}
static int
Handle96GR(register XctData data, int c)
{
switch (c) {
case 0x41:
data->GR = "\101";
data->GR_encoding = "ISO8859-1";
break;
case 0x42:
data->GR = "\102";
data->GR_encoding = "ISO8859-2";
break;
case 0x43:
data->GR = "\103";
data->GR_encoding = "ISO8859-3";
break;
case 0x44:
data->GR = "\104";
data->GR_encoding = "ISO8859-4";
break;
case 0x46:
data->GR = "\106";
data->GR_encoding = "ISO8859-7";
break;
case 0x47:
data->GR = "\107";
data->GR_encoding = "ISO8859-6";
break;
case 0x48:
data->GR = "\110";
data->GR_encoding = "ISO8859-8";
break;
case 0x4c:
data->GR = "\114";
data->GR_encoding = "ISO8859-5";
break;
case 0x4d:
data->GR = "\115";
data->GR_encoding = "ISO8859-9";
break;
default:
return 0;
}
data->priv->flags &= ~ToGL;
data->GR_set_size = 96;
data->GR_char_size = 1;
ComputeGLGR(data);
return 1;
}
static int
HandleMultiGR(register XctData data, int c)
{
switch (c) {
case 0x41:
data->GR = "\101";
if (data->flags & XctShiftMultiGRToGL)
data->GR_encoding = "GB2312.1980-0";
else
data->GR_encoding = "GB2312.1980-1";
break;
case 0x42:
data->GR = "\102";
if (data->flags & XctShiftMultiGRToGL)
data->GR_encoding = "JISX0208.1983-0";
else
data->GR_encoding = "JISX0208.1983-1";
break;
case 0x43:
data->GR = "\103";
if (data->flags & XctShiftMultiGRToGL)
data->GR_encoding = "KSC5601.1987-0";
else
data->GR_encoding = "KSC5601.1987-1";
break;
default:
return 0;
}
if (data->flags & XctShiftMultiGRToGL)
data->priv->flags |= ToGL;
else
data->priv->flags &= ~ToGL;
data->GR_set_size = 94;
data->GR_char_size = 2;
#ifdef notdef
if (c < 0x60)
data->GR_char_size = 2;
else if (c < 0x70)
data->GR_char_size = 3;
else
data->GR_char_size = 4;
#endif
data->GLGR_encoding = (char *)NULL;
return 1;
}
static int
HandleExtended(register XctData data, int c)
{
register XctPriv priv = data->priv;
XctString enc = data->item + 6;
register XctString ptr = enc;
unsigned i, len;
while (*ptr != 0x02) {
if (!*ptr || (++ptr == priv->ptr))
return 0;
}
data->item = ptr + 1;
data->item_length = priv->ptr - data->item;
len = ptr - enc;
for (i = 0;
(i < priv->enc_count) &&
strncmp(priv->encodings[i], (char *)enc, len);
i++)
;
if (i == priv->enc_count) {
XctString cp;
for (cp = enc; cp != ptr; cp++) {
if ((!IsGL(*cp) && !IsGR(*cp)) || (*cp == 0x2a) || (*cp == 0x3f))
return 0;
}
ptr = (XctString)malloc((unsigned)len + 1);
(void) memmove((char *)ptr, (char *)enc, len);
ptr[len] = 0x00;
priv->enc_count++;
if (priv->encodings)
priv->encodings = (char **)realloc(
(char *)priv->encodings,
priv->enc_count * sizeof(char *));
else
priv->encodings = (char **)malloc(sizeof(char *));
priv->encodings[i] = (char *)ptr;
}
data->encoding = priv->encodings[i];
data->char_size = c - 0x30;
return 1;
}
static void
ShiftGRToGL(register XctData data, int hasCdata)
{
register XctPriv priv = data->priv;
register int i;
if (data->item_length > priv->buf_count) {
priv->buf_count = data->item_length;
if (priv->itembuf)
priv->itembuf = (XctString)realloc((char *)priv->itembuf,
priv->buf_count);
else
priv->itembuf = (XctString)malloc(priv->buf_count);
}
(void) memmove((char *)priv->itembuf, (char *)data->item,
data->item_length);
data->item = priv->itembuf;
if (hasCdata) {
for (i = data->item_length; --i >= 0; ) {
if (IsGR(data->item[i]))
data->item[i] &= 0x7f;
}
} else {
for (i = data->item_length; --i >= 0; )
data->item[i] &= 0x7f;
}
}
XctData
XctCreate(_Xconst unsigned char *string, int length, XctFlags flags)
{
register XctData data;
register XctPriv priv;
data = (XctData)malloc(sizeof(struct _XctRec) + sizeof(struct _XctPriv));
if (!data)
return data;
data->priv = priv = (XctPriv)(data + 1);
data->total_string = (XctString)string;
data->total_length = length;
data->flags = flags;
priv->dirstack = (XctHDirection *)NULL;
priv->dirsize = 0;
priv->encodings = (char **)NULL;
priv->enc_count = 0;
priv->itembuf = (XctString)NULL;
priv->buf_count = 0;
XctReset(data);
return data;
}
void
XctReset(register XctData data)
{
register XctPriv priv = data->priv;
priv->ptr = data->total_string;
priv->ptrend = data->total_string + data->total_length;
data->item = (XctString)NULL;
data->item_length = 0;
data->encoding = (char *)NULL;
data->char_size = 1;
data->horizontal = XctUnspecified;
data->horz_depth = 0;
priv->flags = 0;
data->GL_set_size = data->GR_set_size = 0;
(void)HandleGL(data, (unsigned char)0x42);
(void)Handle96GR(data, (unsigned char)0x41);
data->version = 1;
data->can_ignore_exts = 0;
if ((data->total_length >= 4) &&
(priv->ptr[0] == ESC) && (priv->ptr[1] == 0x23) &&
IsI2(priv->ptr[2]) &&
((priv->ptr[3] == 0x30) || (priv->ptr[3] == 0x31))) {
data->version = priv->ptr[2] - 0x1f;
if (priv->ptr[3] == 0x30)
data->can_ignore_exts = 1;
priv->ptr += 4;
}
}
XctResult
XctNextItem(register XctData data)
{
register XctPriv priv = data->priv;
unsigned char c;
int len, bits;
#define NEXT data->item_length++; priv->ptr++
while (IsMore(priv)) {
data->item = priv->ptr;
data->item_length = 0;
c = *priv->ptr;
if (c == ESC) {
NEXT;
while (IsMore(priv) && IsI2(*priv->ptr)) {
NEXT;
}
if (!IsMore(priv))
return XctError;
c = *priv->ptr;
NEXT;
if (!IsESCF(c))
return XctError;
switch (data->item[1]) {
case 0x24:
if (data->item_length > 3) {
if (data->item[2] == 0x28) {
if (HandleMultiGL(data, c))
continue;
} else if (data->item[2] == 0x29) {
if (HandleMultiGR(data, c))
continue;
}
}
break;
case 0x25:
if ((data->item_length == 4) && (data->item[2] == 0x2f) &&
(c <= 0x3f)) {
if ((AmountLeft(priv) < 2) ||
(priv->ptr[0] < 0x80) || (priv->ptr[1] < 0x80))
return XctError;
len = *priv->ptr - 0x80;
NEXT;
len = (len << 7) + (*priv->ptr - 0x80);
NEXT;
if (AmountLeft(priv) < len)
return XctError;
data->item_length += len;
priv->ptr += len;
if (c <= 0x34) {
if (!HandleExtended(data, c) ||
((data->horz_depth == 0) &&
(priv->flags & UsedDirection)))
return XctError;
priv->flags |= UsedGraphic;
return XctExtendedSegment;
}
}
break;
case 0x28:
if (HandleGL(data, c))
continue;
break;
case 0x29:
if (Handle94GR(data, c))
continue;
break;
case 0x2d:
if (Handle96GR(data, c))
continue;
break;
}
} else if (c == CSI) {
NEXT;
while (IsMore(priv) && IsI3(*priv->ptr)) {
NEXT;
}
while (IsMore(priv) && IsI2(*priv->ptr)) {
NEXT;
}
if (!IsMore(priv))
return XctError;
c = *priv->ptr;
NEXT;
if (!IsCSIF(c))
return XctError;
if (c == 0x5d) {
if ((data->item_length == 3) &&
((data->item[1] == 0x31) || (data->item[1] == 0x32))) {
data->horz_depth++;
if (priv->dirsize < data->horz_depth) {
priv->dirsize += 10;
if (priv->dirstack)
priv->dirstack = (XctHDirection *)
realloc((char *)priv->dirstack,
priv->dirsize *
sizeof(XctHDirection));
else
priv->dirstack = (XctHDirection *)
malloc(priv->dirsize *
sizeof(XctHDirection));
}
priv->dirstack[data->horz_depth - 1] = data->horizontal;
if (data->item[1] == 0x31)
data->horizontal = XctLeftToRight;
else
data->horizontal = XctRightToLeft;
if ((priv->flags & UsedGraphic) &&
!(priv->flags & UsedDirection))
return XctError;
priv->flags |= UsedDirection;
if (data->flags & XctHideDirection)
continue;
return XctHorizontal;
} else if (data->item_length == 2) {
if (!data->horz_depth)
return XctError;
data->horz_depth--;
data->horizontal = priv->dirstack[data->horz_depth];
if (data->flags & XctHideDirection)
continue;
return XctHorizontal;
}
}
} else if (data->flags & XctSingleSetSegments) {
NEXT;
if IsC0(c) {
data->encoding = (char *)NULL;
data->char_size = 1;
if (IsLegalC0(data, c))
return XctC0Segment;
} else if (IsGL(c)) {
data->encoding = data->GL_encoding;
data->char_size = data->GL_char_size;
while (IsMore(priv) && IsGL(*priv->ptr)) {
NEXT;
}
if (((data->char_size > 1) &&
(data->item_length % data->char_size)) ||
((data->horz_depth == 0) &&
(priv->flags & UsedDirection)))
return XctError;
priv->flags |= UsedGraphic;
return XctGLSegment;
} else if (IsC1(c)) {
data->encoding = (char *)NULL;
data->char_size = 1;
if (IsLegalC1(data, c))
return XctC1Segment;
} else {
data->encoding = data->GR_encoding;
data->char_size = data->GR_char_size;
while (IsMore(priv) && IsGR(*priv->ptr)) {
NEXT;
}
if (((data->char_size > 1) &&
(data->item_length % data->char_size)) ||
((data->horz_depth == 0) &&
(priv->flags & UsedDirection)))
return XctError;
priv->flags |= UsedGraphic;
if (!(priv->flags & ToGL))
return XctGRSegment;
ShiftGRToGL(data, 0);
return XctGLSegment;
}
} else {
bits = 0;
while (1) {
if (IsC0(c) || IsC1(c)) {
if ((c == ESC) || (c == CSI))
break;
if (IsC0(c) ? !IsLegalC0(data, c) : !IsLegalC1(data, c))
break;
bits |= HasC;
NEXT;
} else {
len = data->item_length;
if (IsGL(c)) {
if ((data->flags & XctShiftMultiGRToGL) &&
(bits & HasGR))
break;
NEXT;
bits |= HasGL;
while (IsMore(priv) && IsGL(*priv->ptr)) {
NEXT;
}
if ((data->GL_char_size > 1) &&
((data->item_length - len) % data->GL_char_size))
return XctError;
} else {
if ((data->flags & XctShiftMultiGRToGL) &&
(bits & HasGL))
break;
NEXT;
bits |= HasGR;
while (IsMore(priv) && IsGR(*priv->ptr)) {
NEXT;
}
if ((data->GR_char_size > 1) &&
((data->item_length - len) % data->GR_char_size))
return XctError;
}
}
if (!IsMore(priv))
break;
c = *priv->ptr;
}
if (data->item_length) {
if (bits & (HasGL|HasGR)) {
priv->flags |= UsedGraphic;
if ((data->horz_depth == 0) &&
(priv->flags & UsedDirection))
return XctError;
if ((data->flags & XctShiftMultiGRToGL) && (bits & HasGR))
ShiftGRToGL(data, bits & HasC);
}
if ((bits == (HasGL|HasGR)) ||
(data->GLGR_encoding && !(bits & HasC))) {
data->encoding = data->GLGR_encoding;
if (data->GL_char_size == data->GR_char_size)
data->char_size = data->GL_char_size;
else
data->char_size = 0;
} else if (bits == HasGL) {
data->encoding = data->GL_encoding;
data->char_size = data->GL_char_size;
} else if (bits == HasGR) {
data->encoding = data->GR_encoding;
data->char_size = data->GR_char_size;
} else {
data->encoding = (char *)NULL;
data->char_size = 1;
if ((bits & HasGL) &&
(data->GL_char_size != data->char_size))
data->char_size = 0;
if ((bits & HasGR) &&
(data->GR_char_size != data->char_size))
data->char_size = 0;
}
return XctSegment;
}
NEXT;
}
if (data->version <= XctVersion)
return XctError;
if (data->flags & XctProvideExtensions)
return XctExtension;
if (!data->can_ignore_exts)
return XctError;
}
return XctEndOfText;
}
void
XctFree(register XctData data)
{
unsigned i;
register XctPriv priv = data->priv;
if (priv->dirstack)
free((char *)priv->dirstack);
if (data->flags & XctFreeString)
free((char *)data->total_string);
for (i = 0; i < priv->enc_count; i++)
free(priv->encodings[i]);
if (priv->encodings)
free((char *)priv->encodings);
if (priv->itembuf)
free((char *)priv->itembuf);
free((char *)data);
}