/* Copyright (c) Xerox Corporation 1993. All rights reserved. */
/* tread.c -- Low-level Tioga reader routines.
David Nichols
December, 1990 */
#include <stdio.h> /* for NULL */
#include <ctype.h>
#include "tioga.h"
#include "tread.h"
#define TRUE 1
#define FALSE 0
extern char *malloc();
extern char *realloc();
long GetLength();
char *strsav();
unsigned char trailerID[] = { 0205, 0227 };
unsigned char commentID[] = { 0, 0 };
unsigned char controlID[] = { 0235, 0312 };
tread←Init(r, buf, len, procs, data)
struct tread←Reader *r;
char *buf;
long len;
struct tread←Procs *procs;
char *data;
{
unsigned char *p;
unsigned char *ubuf = (unsigned char *)buf;
long propLen, textLen, commentLen, totalControlLen, totalSize;
r->procs = procs;
r->data = data;
r->buf = buf;
r->totalLen = len;
/* Find the three main parts and verify that the lengths are ok. */
p = ubuf + len - tioga←TrailerLen;
if (CheckID(&p, trailerID) < 0)
return -1;
propLen = GetLength(&p);
textLen = GetLength(&p);
totalSize = GetLength(&p);
if (totalSize != len || propLen > len || textLen > len)
return -1;
p = ubuf + textLen;
if (CheckID(&p, commentID) < 0)
return -1;
commentLen = GetLength(&p);
p = ubuf + textLen + commentLen;
if (CheckID(&p, controlID) < 0)
return -1;
totalControlLen = GetLength(&p);
if (len != textLen + commentLen + totalControlLen)
return -1;
/* Find start and end of each section of the file. */
r->text.next = ubuf;
r->text.limit = r->text.next + textLen;
r->com.next = ubuf + textLen + tioga←CommentHeaderLen;
r->com.limit = ubuf + textLen + commentLen;
r->control.next = ubuf + textLen + commentLen + tioga←ControlHeaderLen;
r->control.limit = ubuf + len - tioga←TrailerLen;
/* Other reader state initialization. */
r->strLen = 0;
r->str = NULL;
/* First format is the null format. */
r->nFormats = 1;
r->formats[0] = NULL;
/* First look is the empty look. */
r->nLooks = 1;
r->looks[0] = 0;
/* First property is NIL. */
r->nProps = 1;
r->props[0] = NULL;
/* Preload system atoms. */
tread←AddProp(r, "prefix");
tread←AddProp(r, "postfix");
return 0;
}
static int CheckID(pp, id)
unsigned char **pp;
unsigned char *id;
{
unsigned char *s = *pp;
int ok = TRUE;
int i;
for (i = 0; i < tioga←IDLen; ++i) {
if (*s++ != *id++)
ok = FALSE;
}
*pp = s;
return ok ? 0 : -1;
}
/* Get next opcode from file. */
enum tioga←ControlOp tread←GetOp(r)
struct tread←Reader *r;
{
if (r->control.next < r->control.limit)
return (enum tioga←ControlOp) *r->control.next++;
else
return endOfFile;
}
static int EnsureStrLen(r, len)
struct tread←Reader *r;
long len;
{
if (r->strLen == 0) {
r->strLen = len;
r->str = (unsigned char *) malloc(len);
}
else if (len > r->strLen) {
r->strLen = len;
r->str = (unsigned char *) realloc(r->str, r->strLen);
}
if (r->str == NULL) {
tioga←Error("Out of memory.\n");
return -1;
}
return 0;
}
/* Get text from control stream. */
tread←GetStr(r)
struct tread←Reader *r;
{
long len = *r->control.next++;
return tread←SGetRope(r, &r->control, len);
}
/* Get text from a specific stream. */
tread←SGetRope(r, s, len)
struct tread←Reader *r;
struct tread←Stream *s;
long len;
{
long i;
if (EnsureStrLen(r, len + 1) < 0)
return -1;
for (i = 0; i < len; ++i) {
if (s->next >= s->limit) {
tioga←Error("Rope too long.\n");
return -1;
}
r->str[i] = *s->next++;
}
r->str[len] = 0;
return 0;
}
/* Add a new format, and return its index. */
int tread←AddFormat(r, format)
struct tread←Reader *r;
char *format;
{
int i;
/* Index zero reserved for null format. */
if (format == NULL || format[0] == 0)
return 0;
for (i = 1; i < r->nFormats; ++i) {
if (strcmp(r->formats[i], format) == 0)
return i;
}
if (r->nFormats < tioga←NumFormats) {
r->formats[r->nFormats] = strsav(format);
++r->nFormats;
return r->nFormats - 1;
}
else {
tioga←Error("Too many formats.\n");
return 0;
}
}
/* Add a new looks vector, and return its index. */
int tread←AddLooks(r, l)
struct tread←Reader *r;
long l;
{
int i;
/* Index zero reserved for empty looks. */
if (l == 0)
return 0;
for (i = 1; i < r->nLooks; ++i) {
if (r->looks[i] == l)
return i;
}
if (r->nLooks < tioga←NumLooks) {
r->looks[r->nLooks] = l;
++r->nLooks;
return r->nLooks - 1;
}
else {
tioga←Error("Too many looks.\n");
return 0;
}
}
/* Add a new property name, and return its index. */
int tread←AddProp(r, propName)
struct tread←Reader *r;
char *propName;
{
int i;
char *p;
/* Index zero reserved for NIL. */
if (propName == NULL || propName[0] == 0)
return 0;
for (i = 1; i < r->nProps; ++i) {
if (strcmp(r->props[i], propName) == 0)
return i;
}
if (r->nProps < tioga←NumProps) {
r->props[r->nProps] = strsav(propName);
for (p = r->props[r->nProps]; *p != 0; ++p) {
/* Can't use tolower due to ATK problems. */
if ('A' <= *p && *p <= 'Z')
*p = *p - 'A' + 'a';
}
++r->nProps;
return r->nProps - 1;
}
else {
tioga←Error("Too many properties..\n");
return 0;
}
}
/* Get a byte from the control stream. */
int tread←GetByte(r)
struct tread←Reader *r;
{
if (r->control.next < r->control.limit)
return *r->control.next++;
return 0;
}
/* Get an integer from the control stream. */
long tread←GetInt(r)
struct tread←Reader *r;
{
long result = 0;
int nBits = 0;
while (*r->control.next & 0x80) {
result |= (*r->control.next++ & 0x7f) << nBits;
nBits += 7;
}
result |= (*r->control.next++ & 0x7f) << nBits;
return result;
}
static long GetLength(pp)
unsigned char **pp;
{
unsigned char *s = *pp;
long result = 0;
result |= *s++ << 8;
result |= *s++;
result |= *s++ << 24;
result |= *s++ << 16;
*pp = s;
return result;
}
/* Allocate a copy of s and return it. */
char *strsav(s)
char *s;
{
char *p = malloc(strlen(s)+1);
if (p == NULL)
return NULL;
strcpy(p, s);
return p;
}