home *** CD-ROM | disk | FTP | other *** search
- // C++ .cc file for gplot, CGM-specific I/O and parsing -*-c++-*-
- // copyright Phil Andrews, Pittsburgh Supercomputing Center, 1992
- // all rights reserved
- #ifdef macintosh
- # include <errors.h>
- #endif
- #include <ctype.h>
- #include <stdio.h>
- #include <values.h>
- #include "cgm.h"
- #include "cgmio.h"
- #ifndef _toupper
- #define _toupper(c) ((c) -'a'+'A')
- #endif
- ////
- // error call
- ////
- extern void myError(const char *inMsg, const char *inMsg2=NULL,
- int severity=1);
- #ifdef macintosh
- #pragma segment CIO1
- #endif
- // inititalization needed for some compilers
- int cgmInput::beginPictureIndex = 0;
- int cgmInput::endMetafileIndex = 0;
- ////
- // basic cgm input
- ////
- const int cgmInput::noErrors = 1;
- const int cgmInput::noSep = 1<<1;
- const int cgmInput::skipParen = 1<<2;
- ////
- //initialize constants
- ////
-
-
-
- void cgmInput::initialize()
- {
- // do we need to initialize the name array ?
- if (!cgmNameArray) initNameArray();
- // initialize other pointers
- vdcTypeCmd = NULL;
- intPrecCmd = NULL;
- realPrecCmd = NULL;
- indexPrecCmd = NULL;
- defColrPrec.maxInt = 255;
- defColrPrec.noBytes = 1;
- defColrIndexPrec.maxInt = 255;
- defColrIndexPrec.noBytes = 1;
- colrPrecCmd = NULL;
- colrIndexPrecCmd = NULL;
- vdcIntPrecCmd = NULL;
- defVdcIntPrecCmd = NULL;
- vdcRealPrecCmd = NULL;
- defVdcRealPrecCmd = NULL;
- inputError = 0;
- }
- ////
- // index the metafile
- ////
- void cgmInput::makeIndex(cgmMetafile *inMF)
- {
- if (!inMF->firstPic) return; // no pictures
- cgmBeginPicture *myBeginPic;
- cgmPicture *lastPic, *currPic = NULL;
- ////
- // mark our spot
- filePos savePos = pos();
- ////
- // go to the beginning
- goTo(inMF->start());
- lastPic = inMF->firstPic;
- ////
- // find all of the begin picture commands (already have at least first one)
- int noPics = 0;
- while (getCmd() && !sameCmd(cgmNameArray[endMetafileIndex])) {
- if (sameCmd(cgmNameArray[beginPictureIndex])) { // begin picture
- if (noPics) { // at second one, at least
- myBeginPic = new cgmBeginPicture(inMF, this);
- if (!currPic) lastPic->next =
- new cgmPicture(inMF, this, myBeginPic, lastPic);
- lastPic = lastPic->next;
- }
- currPic = lastPic->next;
- ++noPics;
- } // begin picture
- } // got a command
- ////
- // go back to where we began
- goTo(savePos);
- }
- ////
- // get a direct colour (R,G,B)
- ////
- void cgmInput::getDColr(dColr &inColr)
- {
- // for (int i=0; i<3; ++i) inColr[i] = getCD();
- for (int i=0; i<3; ++i) inColr.setValue(i, getCD());
- }
- ////
- // get a general colour
- ////
- genColr *cgmInput::getColr(int mode, const colrValueExtent *inExtent,
- const colrTable *inTable)
- {
- if (mode) { // r, g, b mode
- int red = getCD();
- int green = getCD();
- int blue = getCD();
- return new genColr(red, green, blue, inExtent, inTable);
- } else return new genColr(getCI(), inExtent, inTable); // indexed
- }
- ////
- // get a single vdc measure
- ////
- vdc *cgmInput::getVdc()
- {
- if (myVdcType()) { // real VDC
- return new vdc(getVRP());
- } else { // integer VDC
- return new vdc(getVIP());
- }
- }
- ////
- // get a set of vdc points
- ////
- vdcPts *cgmInput::getVdcPts(int inNoPts)
- {
- int maxPts = inNoPts ? inNoPts : getNoPts(); // how many would we like
- int ptsGot = 0;
- if (myVdcType()) { // real VDC
- float *floatPtr = new float[maxPts * 2]; // real vdc
- while ((ptsGot < maxPts) && getPt(floatPtr + 2 * ptsGot)) ++ptsGot;
- return new vdcPts(floatPtr, ptsGot);
- } else { // integer VDC
- int *intPtr = new int[maxPts * 2]; // integer vdc
- while ((ptsGot < maxPts) && getPt(intPtr + 2 * ptsGot)) ++ptsGot;
- return new vdcPts(intPtr, ptsGot);
- }
- }
- ////
- // get a polygon set
- ////
- void cgmInput::polygonSet(vdcPts* &outPts, int* &outFlags)
- {
- int maxPts = polygonSetSize(), ptsGot = 0;
- outFlags = new int[maxPts];
- if (myVdcType()) { // real VDC
- float *floatPtr = new float[maxPts * 2]; // real vdc
- while ((ptsGot < maxPts) && getPt(floatPtr + 2 * ptsGot)) {
- outFlags[ptsGot] = getType(cgmPolygonSet::typeList,
- cgmPolygonSet::typeListSize);
- ++ptsGot;
- }
- outPts = new vdcPts(floatPtr, ptsGot);
- } else { // integer VDC
- int *intPtr = new int[maxPts * 2]; // integer vdc
- while ((ptsGot < maxPts) && getPt(intPtr + 2 * ptsGot)) {
- outFlags[ptsGot] = getType(cgmPolygonSet::typeList,
- cgmPolygonSet::typeListSize);
- ++ptsGot;
- }
- outPts = new vdcPts(intPtr, ptsGot);
- }
- }
- ////
- // get a colour table
- ////
- colrTable *cgmInput::getColrTable(const colrValueExtent *inExtent)
- {
- int startIndex = getCI();
- int noEntries = getNoDColrs();
- dColr tmpDColr; // temporary
- colrTable *newTable = new colrTable(noEntries, inExtent, startIndex);
- for (int i=0; i<noEntries; ++i) {
- getDColr(tmpDColr);
- newTable->addColr(tmpDColr);
- }
- return newTable;
- }
- ////
- // clear text input
- ////
- // the constant values for the clear info class
- ////
- const char clearInfo::termChar = ';'; // terminating character
- const char clearInfo::termChar1 = '/';
- const char clearInfo::quoteChar = '\"'; // quotation character
- const char clearInfo::quoteChar1 = '\'';
- const char clearInfo::sepChar = ' '; // separation character
- const char clearInfo::sepChar1 = '\011';
- const char clearInfo::sepChar2 = '\012';
- const char clearInfo::sepChar3 = '\013';
- const char clearInfo::sepChar4 = '\014';
- const char clearInfo::sepChar5 = '\015';
- const char clearInfo::sepChar6 = ',';
- const char clearInfo::nullChar = '_'; // null character (ignored inside tokens)
- const char clearInfo::nullChar1 = '$';
- const char clearInfo::commentChar = '%'; // comment character
- ////
- // the clear input class
- ////
- // get one clear text command into memory
- #if __MSDOS__
- HugePt clearInput::getCmd()
- #else
- unsigned char *clearInput::getCmd()
- #endif
- {
- // state of parsing
- enum {normalS, quoting, spacing, commenting} myState = normalS;
- int done = 0; // have we finished ?
- int endFile = 0; // ran out of input
- char c; // latest character
- char lastQuote = 0; // last quotation character used
- myLastPos = pos(); // mark our spot
- bIndex = 0; // initialize buffer index
- // now loop until done and still have input
- #ifdef macintosh
- long char_count = 1;
- while (!done && !(endFile = (FSRead(frefHand,&char_count, &c) == eofErr))) {
- #elif __MSDOS__
- while ( !done && !(endFile = eof(frefHand))) {
- read(frefHand, &c,1);
- #else
- while (!done && !(endFile = ((c = getc(filePtr)) == EOF))) {
- #endif
- switch (myState) {
- case commenting: // in the middle of a comment
- if (isComment(c)) myState = normalS; // end of comment
- break; // else ignore input for now
- case quoting: // in the middle of a quote
- if (c == lastQuote) myState = normalS; // end of quote
- buffer[bIndex++] = c; // in any case take input
- break;
- case spacing: // getting spaces
- if (isSep(c)) break; // no input
- else myState = normalS; // fall thru to normalS state to process c
- case normalS: // normalS input mode
- if (isQuote(c)) { // begin quoting
- myState = quoting;
- lastQuote = c;
- } else if (isComment(c)) { // begin a comment
- myState = commenting;
- break; // no input
- } else if (isTerm(c)) { // finished this command
- done = 1;
- } else if (isSep(c)) { // a separator
- myState = spacing;
- if (bIndex) { // had some real input already
- c = sepChar; // standard separator character
- } else break; // no leading spaces
- } else if (isNull(c)) { // null character, ignore
- break;
- } else if (iscntrl(c)) { // control character, ignore
- break;
- }
- else if (islower(c)) { // lower case
- c = _toupper(c); // map to upper case for convenience
- }
- buffer[bIndex++] = c; // acceptable input
- } // end of switch statement
- if (bIndex >= bufferSize) { // need more memory
- if (!doubleBuffer(bIndex)) {
- myError("couldn't double buffer size", "aborting", 0);
- return NULL;
- }
- }
- } // end of while statement
- if (endFile) return NULL; // no more input, will terminate
- if (!done) { // incomplete command
- bIndex = 0; // ignore this command, but continue processing
- }
- // normal finish
- buffer[bIndex] = 0; // terminate string
- return buffer; // return the parsed string
- }
- ////
- // match the incoming command name to the beginning of the buffer
- ////
- int clearInput::same(const char *inCmd)
- {
- static const int caseDiff = 'A' - 'a';
- int foundMatch;
-
- for (int i=0; (i<bIndex) && inCmd[i]; ++i) {
- if (buffer[i] == inCmd[i]) continue;
- if ((((int)buffer[i] - inCmd[i]) == caseDiff) &&
- (islower(inCmd[i]))) continue;
- if (((inCmd[i] - (int) buffer[i]) == caseDiff) &&
- (isupper(inCmd[i]))) continue;
- return 0; // no match
- }
- // match if got to end of inCmd, nothing useful left in buffer
- foundMatch = (!inCmd[i]) && !isalnum(buffer[i]);
- if (foundMatch) { // skip over the command name
- aIndex = i;
- }
- return foundMatch;
- }
- // figure out how many points we have coming
- // somewhat simple minded, but should give an upper bound
- int clearInput::getNoPts()
- {
- int noVDC = 0; long tIndex = aIndex;
- enum {between, inNumber} myState = between;
-
- while ((tIndex < bIndex) && (!isTerm(buffer[tIndex]))) { // loop thru input
- if (isSep(buffer[tIndex]) || (buffer[tIndex] == '(')
- || (buffer[tIndex] == ')')) { // not in a number
- myState = between; // mark state
- } else if (myState == between) { // entering a number
- myState = inNumber;
- ++noVDC;
- }
- ++tIndex;
- } // end of input
- return (noVDC + 1) / 2;
- }
- // figure out how many points in a polygon set
- int clearInput::polygonSetSize()
- {
- return (getNoTokens() + 2) / 3;
- }
- // figure out how many tokens we have coming
- int clearInput::getNoTokens()
- {
- int noTokens = 0; long tIndex = aIndex;
- enum {between, inToken} myState = between;
-
- while ((tIndex < bIndex) && (!isTerm(buffer[tIndex]))) {
- if (isSep(buffer[tIndex])) {
- if (myState == inToken) {
- myState = between;
- }
- } else if (myState == between) {
- myState = inToken;
- ++noTokens;
- }
- ++tIndex;
- }
- return noTokens;
- }
- ////
- // get an integer point
- ////
- int clearInput::getPt(int *outArray)
- {
- int useParen;
- while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
-
- if ((useParen = (buffer[aIndex] == '('))) ++aIndex; // using parentheses
- outArray[0] = getInt(); // x
- outArray[1] = getInt(); // y
- while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
- if (useParen && (buffer[aIndex] == ')')) ++aIndex; // matching parenthesis
- return inputError ? (inputError = 0), 0 : 1;
- }
- ////
- // get a real point
- ////
- int clearInput::getPt(float *outArray)
- {
- int useParen;
- while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
-
- if ((useParen = (buffer[aIndex] == '('))) ++aIndex; // using parentheses
- outArray[0] = getVRP(); // x
- outArray[1] = getVRP(); // y
- while ((aIndex < bIndex) && isSep(buffer[aIndex])) ++aIndex; // skip seps
- if (useParen && (buffer[aIndex] == ')')) ++aIndex; // matching parenthesis
- return inputError ? (inputError = 0), 0 : 1;
- }
- ////
- // grab a string from the input, make memory for it and return a pointer
- ////
- char *clearInput::getString(int &outSize)
- {
- char lastQuote, *newPtr;
- int stringSize;
-
- // skip over separators
- while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
- if (aIndex >= bIndex) {
- myError("couldn't find string");
- outSize = 0;
- return NULL;
- }
- if (!isQuote(buffer[aIndex])) {
- myError("couldn't find quotation mark");
- outSize = 0;
- return NULL;
- }
- lastQuote = buffer[aIndex++];
- for (stringSize = 0; ((aIndex + stringSize) < bIndex) &&
- (lastQuote != buffer[aIndex + stringSize]); ++stringSize);
- if (lastQuote != buffer[aIndex + stringSize]) {
- myError("couldn't find end of quote");
- outSize = 0;
- return NULL;
- }
- newPtr = new char[stringSize + 1];
- for (int i=0; i < stringSize; ++i) newPtr[i] = buffer[aIndex + i];
- newPtr[i] = 0;
- aIndex += stringSize + 1; // 1 for the closing quote
- outSize = stringSize;
- return newPtr;
- }
- ////
- // basic cgm output
- ////
- // polygon set
- ////
- int cgmOutput::polygonSet(const vdcPts *inPts, const int *inFlags)
- {
- if (!inPts || !inFlags) {
- myError("no input for cgmOutput::polygonSet");
- return 1;
- }
- vdc *myVdc;
- for (int i=0; i<inPts->no(); ++i) {
- myVdc = inPts->newVdc(2*i);
- outVdc(myVdc);
- delete myVdc;
- myVdc = inPts->newVdc(2*i + 1);
- outVdc(myVdc);
- delete myVdc;
- outType(cgmPolygonSet::typeList, inFlags[i]);
- }
- return 1;
- }
- ////
- // clear text output
- ////
- int clearOutput::startCmd(baseCGM *inCGM) // start outputting the command
- {
- return outS(inCGM->cgmName());
- }
- int clearOutput::endCmd() // end the command
- {
- return outC(termChar) && endLine();
- }
- int clearOutput::outString(const char *inString) // output a CGM string
- {
- return outSep() && outC(quoteChar) && outS(inString) &&
- outC(quoteChar);
- }
- // output one of a list of types
- int clearOutput::outType(const char **inList, int inValue)
- {
- return outSep() && outS(inList[inValue]);
- }
- ////
- // input one of a list of types, assume both are in upper case
- ////
- int clearInput::getType(const char **inList, int listSize)
- {
- // skip over separators
- while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
- if (aIndex >= bIndex) {
- myError("couldn't find type");
- return 0;
- }
- for (int i=0; i<listSize; ++i) {
- for (int j=0; (aIndex < bIndex) && inList[i][j] &&
- (inList[i][j] == buffer[aIndex + j]); ++j);
- if (!inList[i][j] && !isalnum(buffer[aIndex + j])) { // found match
- aIndex += j;
- return i;
- }
- }
- myError("couldn't match type ", (char *)buffer + aIndex);
- return 0;
- }
- ////
- // get an integer precision
- ////
- void clearInput::getIntPrec(intPrec *inPrec)
- {
- inPrec->minInt = getInt();
- inPrec->maxInt = getInt();
- inPrec->noBytes = 0;
- }
- ////
- // get an unsigned integer precision
- ////
- void clearInput::getIntPrec(uIntPrec *inPrec)
- {
- inPrec->maxInt = getInt();
- inPrec->noBytes = 0;
- }
- ////
- // get a real precision
- ////
- void clearInput::getRealPrec(realPrec *inPrec)
- {
- inPrec->minReal = getReal();
- inPrec->maxReal = getReal();
- inPrec->noDigits = getInt();
- inPrec->format = 0;
- inPrec->expPart = 0;
- inPrec->fractPart = 0;
- }
- // put an unsigned integer precision
- int clearOutput::outIntPrec(uIntPrec *inPrec)
- {
- outInt(inPrec->maxInt);
- return 1;
- }
- // put an integer precision
- int clearOutput::outIntPrec(intPrec *inPrec)
- {
- outInt(inPrec->minInt);
- outInt(inPrec->maxInt);
- return 1;
- }
- // put a real precision
- int clearOutput::outRealPrec(realPrec *inPrec)
- {
- outReal(inPrec->minReal);
- outReal(inPrec->maxReal);
- outInt(inPrec->noDigits);
- return 1;
- }
- // get a real number
- float clearInput::getReal()
- {
- const int noPowers = 21; // should be enough
- static float powers[noPowers] = {1., 10., 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
- 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14,
- 1e15, 1e16, 1e17, 1e18, 1e19, 1e20};
-
- int i;
- float fractPart = 0;
- int intPart = getInt(noErrors); // get the leading integer, may not exist
- float ret;
- if (buffer[aIndex] == '.') {
- ++aIndex; // skip the period
- for (i=0; isdigit(buffer[aIndex + i]); ++i); // how many digits to come
- ////
- // renormalize the fractional part
- if (i && (fractPart = getLongDecimal())) { // have a non-zero fraction
- if (i<noPowers) { // easy case
- fractPart /= powers[i];
- } else { // maybe on some machine of the future
- for (; i; --i) fractPart /= 10.0; // must be real, ULTRIX C bug
- }
- }
- }
- ret = (intPart < 0) ? intPart - fractPart : intPart + fractPart;
- ////
- // do we have an exponent ?
- if (buffer[aIndex] == 'E') { // scaled number
- int exponent = getInt();
- if (exponent < 0) {
- if (exponent < noPowers) ret /= powers[exponent];
- else for (i=0; i>exponent; --i) ret /= 10.0;
- } else if (exponent > 0) {
- if (exponent < noPowers) ret *= powers[exponent];
- else for (i=0; i<exponent; ++i) ret *= 10.0;
- }
- }
- // all done
- return ret;
- }
- ////
- // get a cell array
- ////
- cellArray *clearInput::getCellArray(int inColMode,
- const colrValueExtent *inExtent,
- const colrTable *inTable)
- {
- const int noPrec = 6;
- static const unsigned int precValues[noPrec] = {1, 2, 4, 8, 16, 24};
- long i;
- vdcPts *myPts = getVdcPts(3);
- int nx = getInt();
- int ny = getInt();
- unsigned int localColrPrec = getE(); // local colour precision
- if (!localColrPrec) localColrPrec = colrPrec().maxInt; // use default
- ////
- // will encode in binary format, find the corresponding precision
- for (i=0; (i<noPrec) && (localColrPrec > ((1<<precValues[i]) - 1)); ++i);
- unsigned int binaryPrec = (i<noPrec) ? precValues[i] : 32; // 32 is the max
- ////
- // create the cellarray
- cellArray *myPtr = new cellArray(inColMode, inExtent, myPts, nx, ny,
- binaryPrec, 1, inTable);
- ////
- // now get the values
- long noValues;
- if (inColMode) { // direct colour mode
- noValues = (long)3 * nx * ny;
- for (i=0; i<noValues; ++i) myPtr->addValue(getInt(skipParen));
- } else {
- noValues = (long)nx * ny;
- for (i=0; i<noValues; ++i) myPtr->addValue(getInt(skipParen));
- }
- ////
- return myPtr;
- }
- ////
- // output a cell array
- ////
- int clearOutput::outCellArray(cellArray *inC)
- {
- int ret = 1;
- ret = ret && outVdcPts(inC->corners()) && outInt(inC->nx())
- && outInt(inC->ny());
- // get the binary precision
- unsigned int binaryPrec = inC->prec();
- // find the equivalent clear text precision and output it
- if (binaryPrec > (8 * sizeof(unsigned int))) {
- myError("unsigned int not big enough, tell Phil !");
- }
- unsigned int clearPrec = (unsigned int)
- (((unsigned long) 1 << binaryPrec) - 1);
- ret = ret && outInt(clearPrec);
- // now the values
- int noValues = inC->nx() * inC->ny(); // for indexed
- if (inC->colMode()) noValues *= 3; // for direct
- for (int i=0; i<noValues; ++i) ret = ret && outInt(inC->getValue(i));
- return ret;
- }
- ////
- // put a direct colour (R,G,B)
- ////
- int clearOutput::outDColr(dColr &inColr)
- {
- // return outInt(inColr[0]) && outInt(inColr[1]) && outInt(inColr[2]);
- return outInt(inColr.getValue(0)) &&
- outInt(inColr.getValue(1)) && outInt(inColr.getValue(2));
- }
- ////
- // output a general colour
- ////
- int clearOutput::outColr(genColr *inColr)
- {
- int ret = 1;
- if (inColr->type()) { // r, g, b format
- for (int i=0; i<3; ++i) ret = ret && outInt(inColr->i(i));
- } else ret = outInt(inColr->i());
- return ret;
- }
- ////
- // output a colour table
- ////
- int clearOutput::outColrTable(colrTable *inTable)
- {
- int ret = 1;
- outInt(inTable->start());
- for (int i=0; i<inTable->no(); ++i) ret = ret && outDColr(inTable->val(i));
- return ret;
- }
- ////
- // output a set of defaults
- ////
- int clearOutput::outDefaults(cgmDefaults *inDefaults)
- {
- int ret = 1;
- endCmd(); // a completely separate command in this encoding
- for (baseCGM *myPtr = inDefaults->contents(); myPtr; myPtr = myPtr->next) {
- myPtr->cgmOut(this);
- }
- outS(cgmMetafileDefaultsReplacement::endName);
- return ret;
- }
- ////
- // output a single vdc
- ////
- int clearOutput::outVdc(const vdc *inVDC)
- {
- return (inVDC->type()) ? outReal(inVDC->f()) : outInt(inVDC->i());
- }
- ////
- // output a set of vdc points
- ////
- int clearOutput::outVdcPts(const vdcPts *inPts)
- {
- int i;
- if (inPts->type()) { // real
- for (i = 0; (i<inPts->no()) && outReal(inPts->fx(i)) &&
- outReal(inPts->fy(i)); ++i);
- } else { // integer
- for (i = 0; (i<inPts->no()) && outInt(inPts->ix(i)) &&
- outInt(inPts->iy(i)); ++i);
- }
- return i >= inPts->no(); // all successful
- }
- // functions to read in a clear text integer
- // get an integer from the input
- int clearInput::getInt(int flag)
- {
- int isNeg = 0, firstInt;
- // may skip over separators
- if (flag & skipParen) { // skip over parentheses
- while ((isSep(buffer[aIndex]) || (buffer[aIndex] == '(')
- || (buffer[aIndex] == ')')) && (aIndex < bIndex)) ++aIndex;
- } else if (!(flag & noSep)) { // mustn't jump over separators
- while (isSep(buffer[aIndex]) && (aIndex < bIndex)) ++aIndex;
- }
- if (aIndex >= bIndex) {
- myError("couldn't find integer");
- inputError = 1;
- return 0;
- }
- // what's our first character ?
- if (buffer[aIndex] == '-') {
- isNeg = 1;
- ++aIndex;
- } else if (buffer[aIndex] == '+') ++aIndex;
- else if (!isdigit(buffer[aIndex])) { // no digit ?, may be OK
- if (!(flag & noErrors)) { // should get an integer
- myError("no digits for getInt in", (char *)buffer);
- myError("getInt read to", (char *)buffer + aIndex);
- inputError = 1;
- }
- return 0; // return 0 in any case
- }
- // now guarranteed some digits
- firstInt = getDecimal();
- if (buffer[aIndex] == '#') { // do we have a base ?
- if ((firstInt >= 2) && (firstInt <= 16)) {
- return (isNeg) ? - getBased(firstInt) : getBased(firstInt);
- } else {
- myError("illegal base");
- inputError = 1;
- return 0;
- }
- } // bare integer
- return (isNeg) ? - firstInt : firstInt;
- }
- // read a simple decimal integer, assume already lined up at first digit
- int clearInput::getDecimal()
- {
- int i;
- long ret = 0;
- while (isdigit(buffer[aIndex])) { // should work anywhere
- for (i=0; (digits[i] != buffer[aIndex]); ++i); // first matching digit
- ret = 10 * ret + i;
- ++aIndex;
- }
- return (int) ret;
- }
- // read a simple long decimal integer, assume already lined up at first digit
- long clearInput::getLongDecimal()
- {
- int i;
- long ret = 0;
- while (isdigit(buffer[aIndex])) { // should work anywhere
- for (i=0; (digits[i] != buffer[aIndex]); ++i); // first matching digit
- ret = 10 * ret + i;
- ++aIndex;
- }
- return ret;
- }
- // read a based integer
- int clearInput::getBased(int inBase)
- {
- static char extDigits[] =
- {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
- static const int maxExtend = sizeof(extDigits) / sizeof(extDigits[0]);
- int ret = 0, i;
-
- // check that we have a legal base
- if ((inBase < 2) || (inBase > maxExtend)) {
- myError("illegal base");
- return 0;
- }
-
- // check that we have a legit number
- for (i=0; (i<inBase) && (extDigits[i] != buffer[aIndex]); ++i);
- if (i>=inBase) {
- myError("illegal based integer");
- return 0;
- }
-
- while (1) {
- for (i=0; (i<inBase) && (extDigits[i] != buffer[aIndex]); ++i);
- if (i>=inBase) { // no more digits
- return ret;
- } else { // more to go ?
- ret = inBase * ret + i;
- ++aIndex;
- }
- }
- }
- ////
- // the binary input class
- ////
- // destructor
- ////
- binaryInput::~binaryInput() {} // keep Cray CC happy
- ////
- // get one binary command into memory
- ////
- #if __MSDOS__
- HugePt binaryInput::getCmd()
- #else
- unsigned char *binaryInput::getCmd()
- #endif
- {
- int pLen, done, bytesNeeded;
- // get the next 2 non-zero bytes (skip simple, 2-byte NULLS)
- do {
- if (!getOffBytes(2)) {
- myError("couldn't get command header");
- return NULL;
- }
- } while (!(buffer[0] || buffer[1]));
- myLastPos = pos() - 2; // mark beginning of actual command
- aIndex = bIndex = 2;
- ////
- // get the parameter length
- pLen = buffer[1] & 31;
- if (pLen < 31) { // short form, buffer size is guaranteed larger
- // next command must start on even boundary
- bytesNeeded = (pLen % 2) ? pLen + 1 : pLen;
- if (bytesNeeded && !getOffBytes(bytesNeeded, bIndex)) {
- myError("couldn't get command");
- return NULL;
- } else {
- bIndex += pLen;
- return buffer;
- }
- }
- // long form
- do { // carry on until we get a terminating partition header
- if (!getOffBytes(2, bIndex)) { // get the next 2 bytes
- myError("couldn't get partition header");
- return NULL;
- }
- pLen = ((buffer[bIndex] & 127) << 8) | buffer[bIndex + 1];
- done = !(buffer[bIndex] & 128); // finished ?
- // next command must start on even boundary
- bytesNeeded = (done && ((bIndex + pLen) % 2)) ? pLen + 1 : pLen;
- // may need more memory
- while ((bytesNeeded + bIndex) > bufferSize) {
- if (!doubleBuffer(bIndex)) return NULL;
- } // get bytes, maybe overwriting partition header
- if (bytesNeeded && !getOffBytes(bytesNeeded, bIndex)) {
- myError("couldn't get partition");
- return NULL;
- }
- bIndex += pLen;
- } while (!done);
- return buffer;
- }
- ////
- // grab a string from the input, make memory for it and return a pointer
- ////
- char *binaryInput::getString(int &outSize)
- {
- char *newPtr = NULL;
- int i, pLen, sIndex;
- unsigned int stringSize = (aIndex < bIndex)? buffer[aIndex++] : 0; // first byte has initial length
- if (stringSize < 255) { // simple string
- newPtr = new char[stringSize + 1];
- for (i=0; i < stringSize; ++i) newPtr[i] = buffer[aIndex + i];
- newPtr[i] = 0;
- aIndex += stringSize;
- outSize = stringSize;
- return newPtr;
- }
- // now have complex string, get size first
- int done;
- stringSize = 0; // start fresh
- do {
- done = !(buffer[aIndex + stringSize] & 128); // finished ?
- stringSize += ((buffer[aIndex + stringSize] & 127) << 8)
- | buffer[aIndex + stringSize + 1];
- } while (!done);
- // now make the memory
- newPtr = new char[stringSize + 1];
- // and fill it out
- sIndex = 0;
- do {
- done = !(buffer[aIndex] & 128); // finished ?
- pLen = ((buffer[aIndex] & 127) << 8) | buffer[aIndex + 1];
- aIndex += 2;
- for (i=0; i<pLen; ++i) newPtr[sIndex++] = buffer[aIndex++];
- } while (!done);
- if (sIndex != stringSize) myError("bad string");
- newPtr[sIndex] = 0;
- outSize = stringSize;
- return newPtr;
- }
- ////
- // diagnostic
- ////
- const char *binaryInput::cmdSignature()
- {
- static char myString[60];
- sprintf(myString, "(%d, %d) = (%d, %d)", (int) buffer[0], (int) buffer[1],
- bufferClass(), bufferElement());
- return myString;
- }
- ////
- // general signed integer (assume long at least 4 bytes, may truncate)
- ////
- int binaryInput::gInt(int noBytes)
- {
- long ret = (buffer[aIndex] & 128) ? (-1 ^ 255) | (int) buffer[aIndex++]
- : buffer[aIndex++];
- switch(noBytes) {
- case 4:
- ret = (ret<<8) | buffer[aIndex++]; // fallthru
- case 3:
- ret = (ret<<8) | buffer[aIndex++]; // fallthru
- case 2:
- ret = (ret<<8) | buffer[aIndex++]; // end
- }
- return (int) ret;
- }
- ////
- // general shifted signed integer
- ////
- int binaryInput::gShiftInt(int noBytes, int bitsRead)
- {
- // for convenience/speed
- static unsigned char bitMask[8] = {255, 127, 63, 31, 15, 7, 3, 1};
- //
- if ((bitsRead > 7) || (bitsRead < 0)) {
- myError("illegal bitsRead");
- return 0;
- }
- if (bitsRead == 0) return gInt(noBytes); // no shift
- // span parts of noBytes + 1 bytes
- //
- // spans at least 2 bytes, get 'em one at a time
- // first byte
- // get the sign
- long ret = ((buffer[aIndex] & (1 << (7 - bitsRead))) ? -1 : 0)
- << (7 - bitsRead);
- // now the rest of the bits
- ret = ret | (buffer[aIndex++] & bitMask[bitsRead]);
- switch(noBytes) {
- case 4:
- ret = (ret<<8) | buffer[aIndex++]; // fallthru
- case 3:
- ret = (ret<<8) | buffer[aIndex++]; // fallthru
- case 2:
- ret = (ret<<8) | buffer[aIndex++]; // end
- }
- // last byte
- ret = (ret << bitsRead) | (buffer[aIndex] >> (8 - bitsRead));
- return ret;
- }
- ////
- // general unsigned integer
- ////
- unsigned int binaryInput::gUInt(int noBytes)
- {
- unsigned long ret = buffer[aIndex++];
- switch(noBytes) {
- case 4:
- ret = (ret<<8) | (buffer[aIndex++] & 255); // fallthru
- case 3:
- ret = (ret<<8) | (buffer[aIndex++] & 255); // fallthru
- case 2:
- ret = (ret<<8) | (buffer[aIndex++] & 255); // end
- }
- return (unsigned int) ret;
- }
- ////
- // figure out how many points we have coming
- ////
- int binaryInput::getNoPts()
- {
- if (aIndex >= bIndex) {
- myError("no Pts to get");
- return 0;
- }
- // each vdc uses an even number of bytes, 2 vdc's per point (8/2 = 4)
- if (myVdcType()) { // real vdc's
- return ((bIndex - aIndex) * 4) /
- (vdcRealPrec().expPart + vdcRealPrec().fractPart);
- } else return (bIndex - aIndex) / (2 * vdcIntPrec().noBytes);
- }
- ////
- // figure out how many points we have in a polygon set
- ////
- int binaryInput::polygonSetSize()
- {
- if (aIndex >= bIndex) {
- myError("no polygon set Pts to get");
- return 0;
- }
- // each vdc uses an even number of bytes, 2 vdc's per point (8/2 = 4)
- // the enumerated flag takes 2 bytes
- if (myVdcType()) { // real vdc's
- return ((bIndex - aIndex) * 4) /
- (vdcRealPrec().expPart + vdcRealPrec().fractPart + 8);
- } else return (bIndex - aIndex) / (2 * vdcIntPrec().noBytes + 2);
- }
- ////
- // get one real vdc pt
- ////
- int binaryInput::getPt(float *inF)
- {
- if (aIndex >= bIndex) return 0;
- inF[0]=getVRP();
- if (aIndex >= bIndex) return 0;
- inF[1]=getVRP();
- return (aIndex > bIndex) ? 0 : 1;
- }
- ////
- // get one integer vdc pt
- ////
- int binaryInput::getPt(int *inI)
- {
- if (aIndex >= bIndex) return 0;
- inI[0]=getVIP();
- if (aIndex >= bIndex) return 0;
- inI[1]=getVIP();
- return (aIndex > bIndex) ? 0 : 1;
- }
- ////
- // general fixed point real
- ////
- float binaryInput::gFX(realPrec &inPrec)
- {
- double expPart = gInt(inPrec.expPart/8);
- double fractPart = gUInt(inPrec.fractPart/8);
- float ret = expPart + fractPart / ((long) 1 << inPrec.fractPart);
- return ret;
- }
- ////
- // general floating point real
- ////
- float binaryInput::gFP(realPrec &inPrec)
- {
- static double p149 = 1, p23 = 1, p1074, p52;
- double dfract;
- unsigned int exponent;
- unsigned long fract;
- float ret;
- int i;
- if (p149 == 1) for (i=0; i<149; ++i) p149 *= 2.0; // initialize
- if (p23 == 1) for (i=0; i<23; ++i) p23 *= 2.0; // initialize
- if (p1074 == 1) for (i=0; i<1074; ++i) p1074 *= 2.0; // initialize
- if (p52 == 1) for (i=0; i<p52; ++i) p52 *= 2.0; // initialize
-
- int signBit = (buffer[aIndex] >> 7) & 1; // is this negative ?
- // which precision is this ?
- switch (inPrec.fractPart + inPrec.expPart) {
- case 32: // 32 bit precision
- // get the exponent
- exponent = ((buffer[aIndex] & 127) << 1) + ((buffer[aIndex + 1] >> 7) & 1);
- // get the fractional part
- fract = ((unsigned long)(buffer[aIndex + 1] & 127) << 16) +
- ((unsigned long)buffer[aIndex + 2] << 8)
- + buffer[aIndex + 3];
- // step forward the pointer before we forget
- aIndex += 4;
- // check for special cases
- if (exponent == 255) {
- if (fract == 0) { // big number
- return (signBit) ? -MAXFLOAT : MAXFLOAT;
- } else { // screwed up
- myError("undefined IEEE number");
- return 0;
- }
- } else if (exponent == 0) {
- if (fract == 0) return 0;
- else return (signBit) ? -fract / p149 : fract / p149; // fract / 2^149
- } else { // normal number
- ret = 1 + fract / p23;
- if (exponent < 127) for (i=0; i<(127-exponent); ++i) ret /= 2.0;
- else if (exponent > 127) for (i=0; i<(exponent-127); ++i) ret *= 2.0;
- return (signBit) ? -ret : ret;
- }
- break;
- case 64: // 64 bit precision !!! not for PC
- exponent = ((buffer[aIndex] & 127) << 4) + ((buffer[aIndex+1] >> 4) & 15);
- // fractional [part might not fit in a long
- dfract = buffer[aIndex + 1] & 15;
- for (i=2; i<8; ++i) {
- dfract *= 256.0;
- dfract += buffer[aIndex + i];
- }
- // step forward the pointer before we forget
- aIndex += 8;
- if (exponent == 2047) {
- if (fract == 0) { // big number
- return (signBit) ? -MAXFLOAT : MAXFLOAT;
- } else { // screwed up
- myError("undefined IEEE number");
- return 0;
- }
- } else if (exponent == 0) {
- if (fract == 0) return 0;
- else return (signBit) ? -fract / p1074 : fract /p1074; // fract / 2^1074
- } else { // normal number
- ret = 1 + dfract / p52;
- if (exponent < 1023) {
- for (i=0; i<(1023 - exponent); ++i) ret /= 2.0;
- } else if (exponent > 1023) {
- for (i=0; i<(exponent - 1023); ++i) ret *= 2.0;
- return (signBit) ? -ret : ret;
- } else return 0; // screwed up
- }
- break;
- }
- return 0; // for safety
- }
- ////
- // get a real precision
- ////
- void binaryInput::getRealPrec(realPrec *inPrec)
- {
- char myString[60];
- int format = getE();
- int expPart = getInt();
- int fractPart = getInt();
- // check for legality
- if ((((fractPart + expPart) != 32) && ((fractPart + expPart) != 64)) ||
- ((format != 0) && (format != 1)) ||
- ((format == 0) && ((fractPart != 9) && (fractPart != 23))) ||
- ((format == 1) && ((fractPart != 16) && (fractPart != 32)))) {
- sprintf(myString, "(%d, %d, %d)", format, expPart, fractPart);
- myError("illegal binary real precision", myString);
- return;
- }
- ////
- inPrec->format = format;
- inPrec->expPart = expPart;
- inPrec->fractPart = fractPart;
- inPrec->minReal = - 1 << expPart; // guess
- inPrec->maxReal = 1 << expPart; // guess
- }
- ////
- // NCAR specific input
- ////
- // initialization
- ////
- void NCARInput::initialize()
- {
- if (!fillLocalBuffer()) myError("couldn't get first NCAR block");
- }
- ////
- // get some bytes
- ////
- int NCARInput::getOffBytes(unsigned int noBytes, unsigned long offset)
- {
- for (int i=0; i<noBytes; ++i) {
- while ((endIndex <= startIndex) && fillLocalBuffer()); // may need bytes
- if (endIndex <= startIndex) {
- myError("couldn't get NCAR data");
- return 0;
- } else buffer[offset + i] = localBuffer[startIndex++];
- }
- return 1;
- }
- ////
- // fill the local buffer
- ////
- int NCARInput::fillLocalBuffer()
- {
- if (!getBytes(NCARSIZE, localBuffer)) {
- myError("couldn't get NCAR block");
- return 0;
- }
- startIndex = 4; // start of real data
- endIndex = startIndex + ((localBuffer[0] << 8) | (localBuffer[1] & 255));
- if (endIndex % 2) ++endIndex; // sometimes NCAR doesn't include pad byte
- if (endIndex > NCARSIZE) {
- char myString[20];
- sprintf(myString, "%d bytes", endIndex - startIndex);
- myError("too many bytes in NCAR header", myString);
- return 0;
- } else return 1;
- }
- ////
- // get a cell array
- ////
- cellArray *binaryInput::getCellArray(int inColMode,
- const colrValueExtent *inExtent,
- const colrTable *inTable)
- {
- char myString[60];
- long i;
- vdcPts *myPts = getVdcPts(3);
- int nx = getInt();
- int ny = getInt();
- unsigned int localColrPrec = getE(); // local colour precision
- if (!localColrPrec) localColrPrec = colrPrec().noBytes * 8; // use default
- ////
- // create the cellarray
- cellArray *myPtr = new cellArray(inColMode, inExtent, myPts, nx, ny,
- localColrPrec, 1, inTable);
- // what mode is this ?
- int repMode = getE();
- ////
- // now get the values
- int valSize = (inColMode) ? 3 : 1;
- int valBits = valSize * localColrPrec;
- int noValues = valSize * nx;
- int rowSize = 2 * ((noValues * localColrPrec + 15) / 16); // padded
- if (repMode) { // packed list
- for (i=0; i<ny; ++i) {
- if ((aIndex + rowSize) > bIndex) {
- myError("not enough bytes for cell array");
- break;
- }
- // add a complete row
- myPtr->addValues(&buffer[aIndex], 0, noValues);
- aIndex += rowSize;
- }
- } else { // run length encoded
- int runCount, valsGot, j, bitsGot;
- for (i=0; i<ny; ++i) { // rows start on a 2-byte boundary
- bitsGot = valsGot = 0;
- while (valsGot < nx) {
- runCount = getShiftInt(bitsGot); // increases aIndex
- if (((runCount + valsGot) > nx) || (runCount < 0)) {
- sprintf(myString, "%d, x = %d, nx = %d, y = %d, ny = %d",
- runCount, valsGot, nx, i, ny);
- myError("illegal runcount in cell array", myString);
- return myPtr;
- } // else OK, replicate value
- for (j=0; j<runCount; ++j)
- myPtr->addValues(&buffer[aIndex], bitsGot, valSize);
- valsGot += runCount;
- bitsGot += valBits;
- if (bitsGot > 7) { // step forward the byte index
- aIndex += bitsGot / 8;
- bitsGot = bitsGot % 8;
- }
- }
- if (aIndex > bIndex) {
- myError("not enough bytes for run length encoding");
- return myPtr;
- }
- if (bitsGot) ++aIndex; // start at a clean byte
- if (aIndex % 2) ++aIndex; // pad at end of rows
- }
- }
- ////
- return myPtr;
- }
- #ifdef macintosh
- #pragma segment CIO2
- #endif
- ////
- // parsing initialization
- ////
- // set the parser's pointer
- ////
- cgmNameNew *cgmInput::cgmNameArray = NULL;
- ////
- // add new classes to this array later so that the parser knows about them
- ////
- // define an INITMACRO set up for runtime initialization
- ////
- #define INITMACRO(inName) \
- cgmNameArray[i].myName = &inName::myName;\
- cgmNameArray[i].myClass = inName::myClass;\
- cgmNameArray[i].myElement = inName::myElement;\
- cgmNameArray[i].fp = inName::getNew; ++i;
- ////
- // now fill out the structure, either at runtime
- ////
- void cgmInput::initNameArray() {
- ////
- // grab some memory
- cgmNameArray = new cgmNameNew[cgmNoClasses];
- if (!cgmNameArray) myError("couldn't create parsing array", "", 0);
- int i = 0;
- ////
- // delimiters
- INITMACRO(cgmBeginMetafile)
- endMetafileIndex = i; // will need this later
- INITMACRO(cgmEndMetafile)
- beginPictureIndex = i; // will need this later
- INITMACRO(cgmBeginPicture)
- INITMACRO(cgmBeginPictureBody)
- INITMACRO(cgmEndPicture)
- // metafile descriptors
- INITMACRO(cgmMetafileVersion)
- INITMACRO(cgmMetafileDescription)
- INITMACRO(cgmVdcType)
- INITMACRO(cgmIntegerPrec)
- INITMACRO(cgmRealPrec)
- INITMACRO(cgmIndexPrec)
- INITMACRO(cgmColrPrec)
- INITMACRO(cgmColrIndexPrec)
- INITMACRO(cgmMaxColrIndex)
- INITMACRO(cgmColrValueExtent)
- INITMACRO(cgmMetafileElementList)
- INITMACRO(cgmMetafileDefaultsReplacement)
- INITMACRO(cgmFontList)
- INITMACRO(cgmCharacterSetList)
- INITMACRO(cgmCharacterCodingAnnouncer)
- // picture descriptors
- INITMACRO(cgmScalingMode)
- INITMACRO(cgmColrMode)
- INITMACRO(cgmLineWidthMode)
- INITMACRO(cgmMarkerSizeMode)
- INITMACRO(cgmEdgeWidthMode)
- INITMACRO(cgmVdcExtent)
- INITMACRO(cgmBackgroundColr)
- // control elements
- INITMACRO(cgmVdcInteger)
- INITMACRO(cgmVdcReal)
- INITMACRO(cgmAuxColr)
- INITMACRO(cgmTransparency)
- INITMACRO(cgmClipRect)
- INITMACRO(cgmClip)
- // graphical primitives
- INITMACRO(cgmPolyline)
- INITMACRO(cgmDisPolyline)
- INITMACRO(cgmPolymarker)
- INITMACRO(cgmText)
- INITMACRO(cgmRestrText)
- INITMACRO(cgmApndText)
- INITMACRO(cgmPolygon)
- INITMACRO(cgmPolygonSet)
- INITMACRO(cgmGDP)
- INITMACRO(cgmCellArray)
- INITMACRO(cgmRectangle)
- INITMACRO(cgmCircle)
- INITMACRO(cgmArc3Pt)
- INITMACRO(cgmArc3PtClose)
- INITMACRO(cgmArcCtr)
- INITMACRO(cgmArcCtrClose)
- INITMACRO(cgmEllipse)
- INITMACRO(cgmEllipArc)
- INITMACRO(cgmEllipArcClose)
- // attributes
- INITMACRO(cgmLineIndex)
- INITMACRO(cgmLineType)
- INITMACRO(cgmLineWidth)
- INITMACRO(cgmLineColr)
- INITMACRO(cgmMarkerIndex)
- INITMACRO(cgmMarkerType)
- INITMACRO(cgmMarkerSize)
- INITMACRO(cgmMarkerColr)
- INITMACRO(cgmTextIndex)
- INITMACRO(cgmFontIndex)
- INITMACRO(cgmTextPrec)
- INITMACRO(cgmCharExpan)
- INITMACRO(cgmCharSpace)
- INITMACRO(cgmTextColr)
- INITMACRO(cgmCharHeight)
- INITMACRO(cgmCharOri)
- INITMACRO(cgmTextPath)
- INITMACRO(cgmTextAlign)
- INITMACRO(cgmCharSetIndex)
- INITMACRO(cgmAltCharSetIndex)
- INITMACRO(cgmFillIndex)
- INITMACRO(cgmHatchIndex)
- INITMACRO(cgmPatIndex)
- INITMACRO(cgmIntStyle)
- INITMACRO(cgmFillColr)
- INITMACRO(cgmEdgeIndex)
- INITMACRO(cgmEdgeType)
- INITMACRO(cgmEdgeWidth)
- INITMACRO(cgmEdgeColr)
- INITMACRO(cgmEdgeVis)
- INITMACRO(cgmFillRefPt)
- INITMACRO(cgmPatTable)
- INITMACRO(cgmPatSize)
- INITMACRO(cgmColrTable)
- INITMACRO(cgmASF)
- // escape element
- INITMACRO(cgmEscapeElement)
- // externals
- INITMACRO(cgmMessage)
- INITMACRO(cgmApplData)
- };
- #undef INITMACRO
- ////
- // binary output
- ////
- int binaryOutput::startCmd(baseCGM *inCGM) // start outputting the command
- {
- return 1; // fix later
- }
- int binaryOutput::endCmd() // end the command
- {
- return 1; // fix later
- }
- int binaryOutput::outString(const char *inString) // output a CGM string
- {
- return 1; // fix later
- }
- // output one of a list of types
- int binaryOutput::outType(const char **inList, int inValue)
- {
- return 1; // fix later
- }
-