/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #define MAX(a,b) (((a)>(b))?(a):(b)) /* * simple routines for common cases */ Object DXExtractInteger(Object o, int *ip) { return DXExtractParameter(o, TYPE_INT, 0, 1, (Pointer)ip); } Object DXExtractFloat(Object o, float *fp) { return DXExtractParameter(o, TYPE_FLOAT, 0, 1, (Pointer)fp); } /* slightly different - it returns a pointer to the start of the string. * the caller doesn't need to allocate space for it. */ Object DXExtractString(Object o, char **cp) { char *c; int len; Type t; /* this does the checking to be sure it is either a String object, * or a TYPE_STRING array. */ if(!DXQueryParameter(o, TYPE_STRING, 1, NULL)) return NULL; if(DXGetObjectClass(o) == CLASS_STRING) { if (cp) *cp = DXGetString((String)o); return o; } DXGetArrayInfo((Array) o, &len, &t, NULL, NULL, NULL); if (t == TYPE_STRING) { if (len > 1) return NULL; if (cp) *cp = (char *)DXGetArrayData((Array)o); return o; } /* for backwards compatibility - TYPE_UBYTE */ c = (char *)DXGetArrayData((Array)o); while (--len > 0) { if (*c++) /* fail if there are imbedded NULLs... */ continue; return NULL; } if (*c) /* ...or if there isn't a trailing NULL */ return NULL; if (cp) *cp = (char *)DXGetArrayData((Array)o); return o; } Object DXExtractNthString (Object o, int n, char **cp) { char *c, *cs; int len; Type type; int rank, shape; if (n < 0) return (NULL); /* only returns ok if object class String or Array TYPE_STRING or UBYTE */ if (! DXQueryParameter (o, TYPE_STRING, 1, NULL)) return (NULL); if (DXGetObjectClass(o) == CLASS_STRING) { /* String objects are 1 string, so asking for any string * but the 0th is bad. */ if (n) return (NULL); if (cp) *cp = DXGetString ((String) o); return (o); } DXGetArrayInfo ((Array) o, &len, &type, NULL, NULL, NULL); if (type == TYPE_STRING) { /* len is number of strings in array */ if (n >= len) return NULL; /* the Query call above made sure this is rank 1, * so shape is safe here */ DXGetArrayInfo ((Array) o, NULL, NULL, NULL, NULL, &shape); cs = (char *) DXGetArrayData ((Array) o); if (cp) *cp = cs + (n * shape); return o; } /* here for backward compatibility - * null separated chars in a UBYTE array */ cs = (char *) DXGetArrayData ((Array) o); for (c=cs; len--; ) { if (*c++) continue; if (n == 0) { if (cp) *cp = cs; return (o); } n--; cs = c; } return (NULL); } /* new code */ #define CONVTYPE(from, to) \ static Error \ from##2##to(int count, from *fp, to *tp) \ { \ int i; \ \ for (i=0; i a + 0i */ static Error real2complex(int count, Pointer from, Pointer to, int itemsize) { int i; Pointer efrom, eto; efrom = INC(from, itemsize * (count-1)); eto = INC(to, 2 * itemsize * (count-1)); for (i=count; i>0; i--) { memset(eto, '\0', itemsize); eto = DEC(to, itemsize); memcpy(efrom, eto, itemsize); efrom = DEC(from, itemsize); eto = DEC(to, itemsize); } return OK; } /* conversion is: a -> a + 0i + 0j + 0k */ static Error real2quatern(int count, Pointer from, Pointer to, int itemsize) { int i; Pointer efrom, eto; efrom = INC(from, itemsize * (count-1)); eto = INC(to, 4 * itemsize * (count-1)); for (i=count; i>0; i--) { memset(to, '\0', 3 * itemsize); to = DEC(to, 3 * itemsize); memcpy(from, to, itemsize); from = DEC(from, itemsize); to = DEC(to, itemsize); } return OK; } /* conversion is: a + bi -> a + bi + 0j + 0k */ static Error complex2quatern(int count, Pointer from, Pointer to, int itemsize) { int i; Pointer efrom, eto; efrom = INC(from, itemsize * (count-1)); eto = INC(from, 2 * itemsize * (count-1)); for (i=count; i>0; i--) { memset(to, '\0', itemsize); to = DEC(to, itemsize); memcpy(from, to, itemsize); from = DEC(from, itemsize); to = DEC(to, itemsize); } return OK; } struct convtable2 { int conversion; Error (*convfunc)(int count, Pointer from, Pointer to, int itemsize); int hascommon; Category commoncat; }; /* (uses same conversion flags as above) */ #define NUM_CATS 3 #define C_REAL 0 #define C_COMPLEX 1 #define C_QUATERN 2 static char *catname(Category c) { switch (c) { case CATEGORY_REAL: return "real"; case CATEGORY_COMPLEX: return "complex"; case CATEGORY_QUATERNION: return "quaternion"; default: return "unknown"; } /* notreached */ } static int catindex(Category c) { switch (c) { case CATEGORY_REAL: return C_REAL; case CATEGORY_COMPLEX: return C_COMPLEX; case CATEGORY_QUATERNION: return C_QUATERN; default: return -1; } /* notreached */ } static struct convtable2 cattable[NUM_CATS][NUM_CATS] = { /* from REAL */ /* to ... */ { CONV_EQUAL, NULL, HAS_COMMON, CATEGORY_REAL, /* REAL */ CONV_ALLOWED, real2complex, HAS_COMMON, CATEGORY_COMPLEX, /* COMPLEX */ CONV_ALLOWED, real2quatern, HAS_COMMON, CATEGORY_QUATERNION, }, /* QUATERN */ /* from COMPLEX */ /* to ... */ { CONV_ILLEGAL, NULL, HAS_COMMON, CATEGORY_COMPLEX, /* REAL */ CONV_EQUAL, NULL, HAS_COMMON, CATEGORY_COMPLEX, /* COMPLEX */ CONV_ALLOWED, complex2quatern, HAS_COMMON, CATEGORY_QUATERNION, }, /* QUATERN */ /* from QUATERN */ /* to ... */ { CONV_ILLEGAL, NULL, HAS_COMMON, CATEGORY_QUATERNION, /* REAL */ CONV_ILLEGAL, NULL, HAS_COMMON, CATEGORY_QUATERNION, /* COMPLEX */ CONV_EQUAL, NULL, HAS_COMMON, CATEGORY_QUATERNION, }, /* QUATERN */ }; /* this modifies shape in place to squeeze out shapes of 1 * (e.g. rank 3, shape 3 1 4 -> rank 2 shape 3 4) */ static void SqueezeShape(int *rank, int *shape) { int i, j; i = 0; while (i < *rank) { if (shape[i] > 1) i++; else { (*rank)--; for (j=i; j<*rank; j++) shape[j] = shape[j+1]; } } } /* this checks to see if it can squeeze the first rank/shape pair * to match the second, and if it can, it modifies them in place * and returns OK. otherwise it leaves them alone and returns ERROR * and sets the error code. * if it has to expand to match, it adds shape 1 at the end of the list. * * this routine isn't done yet. */ static Error SqueezeToShape(int *rank, int *shape, int trank, int *tshape) { int i, j; i = 0; while (i < *rank) { if (shape[i] > 1) i++; else { (*rank)--; for (j=i; j<*rank; j++) shape[j] = shape[j+1]; } } return ERROR; } static Error ConvertArrayContents(Array from, Array to, int squeeze) { int i, j, k; int fi, ti; Pointer fromdp, todp; int itemsize; int count; int fromcount, tocount; Type fromtype, totype; Category fromcat, tocat; int fromrank, torank; int fromshape[100], toshape[100]; DXGetArrayInfo(from, &fromcount, &fromtype, &fromcat, &fromrank, fromshape); DXGetArrayInfo(to, &tocount, &totype, &tocat, &torank, toshape); if (fromcount != tocount) DXErrorReturn(ERROR_INVALID_DATA, "array sizes don't match"); /* squeeze out shapes of 1 from both and make sure they match. */ if (squeeze) { SqueezeShape(&fromrank, fromshape); SqueezeShape(&torank, toshape); } if (fromrank != torank) { if (squeeze) DXErrorReturn(ERROR_INVALID_DATA, "data ranks don't match"); return ConvertArrayContents(from, to, 1); } for (i=0; i %d)", arank, rank); return ERROR; } return QueryArrayConvert(a, t, c, rank, shape, 1); } /* data rank and shape */ for (i=0; i 1) return NULL; if(dim == 0 && strlen(cp) > 1) return NULL; if(count) *count = strlen(cp); return o; } /* check general characteristics first, before worrying about * specific data types */ if( DXGetObjectClass(o) != CLASS_ARRAY || !DXGetArrayInfo((Array)o, &nitems, &at, &ac, &ar, as) || ac != CATEGORY_REAL || ar > 1 || nitems == 0) return NULL; /* don't do these checks for strings */ if (at != TYPE_STRING) { /* if dim > 1, rank must be 1 and shape must match dim. * dim 0 or 1 both match rank 1 shape 1 and rank 0 */ if(dim > 1) { if(ar != 1 || as[0] != dim) return NULL; } else { if(ar > 1 || (ar == 1 && as[0] != 1)) return NULL; } } if(count) *count = nitems; /* if types match exactly, you're done */ if(at == t) return o; /* see if the types could be promoted ok. 'at' is the actual * array type, 't' is what they want. */ if (dim == 0) { if (DXQueryArrayConvert((Array)o, t, CATEGORY_REAL, 0) == OK) return o; } else { if (DXQueryArrayConvert((Array)o, t, CATEGORY_REAL, 1, dim) == OK) return o; } DXResetError(); return NULL; } /* given an object, and a caller-allocated buffer, copy the input * to the buffer, converting type if necessary. */ Object DXExtractParameter(Object o, Type t, int dim, int count, Pointer p) { Array na; char *sp; int i, nitems; Type at; Category ac; int ar, as[MAXDIM]; if(!o) return NULL; /* slightly special case for string arrays, which might come in * as string objects. */ if(t == TYPE_STRING && DXGetObjectClass(o) == CLASS_STRING) { sp = DXGetString((String)o); if(!sp || dim > 1) return NULL; if(dim == 0 && strlen(sp) > 1) return NULL; if(count != strlen(sp)) return NULL; if (p) strcpy((char *)p, sp); return o; } /* check general characteristics first, before worrying about * specific data types */ if( DXGetObjectClass(o) != CLASS_ARRAY || !DXGetArrayInfo((Array)o, &nitems, &at, &ac, &ar, as) || ac != CATEGORY_REAL || ar > 1 || nitems == 0 || nitems != count) return NULL; /* if dim > 1, rank must be 1 and shape must match dim. * dim 0 or 1 both match rank 1 shape 1 and rank 0 */ if(dim > 1) { if(ar != 1 || as[0] != dim) return NULL; } else { if(ar > 1 || (ar == 1 && as[0] != 1)) return NULL; } /* if types match exactly, just memcpy the number of bytes and return */ if(at == t) { if (p) memcpy(p, DXGetArrayData((Array)o), nitems * DXGetItemSize((Array)o)); return o; } /* types don't match exactly, so see if they can be converted. */ if (dim == 0) na = DXArrayConvert((Array)o, t, CATEGORY_REAL, 0); else na = DXArrayConvert((Array)o, t, CATEGORY_REAL, 1, dim); if (!na) { DXResetError(); return NULL; } if (p) memcpy(p, DXGetArrayData(na), nitems * DXGetItemSize(na)); DXDelete((Object)na); return o; }