/****************************************************************************** FILE: MC0.C Low level-routines for converting the various variable types across different machine formats. 89-02-21 - J. Ranada 95-02-16 - JR - modified copy_byte to make it possible to do "in-place" conversions, i.e., the convert_array_* routines can be called using the same address for dest and buff; since copy_byte does all the work, a test to see if dest == buff, and if so, to allocate some temporary buffer to do the byte-swapping was added. *****************************************************************************/ #include "common.h" /* HOST_ENVIRONMENT */ #include "mem_.h" /* cmp_byte() */ #include "find_def.h" /* find_def() */ #include "mc0.h" /*--------------------------------------------------------- BYTE-SWAPPING PATTERN FOR VAX-DFLOAT FORMAT DOUBLE TYPE ---------------------------------------------------------*/ int VAX_DOUBLE_INDEX[] = {1, 0, 3, 2, 5, 4, 7, 6}; /*----------------------------------------------------------------------------- FUNCTION: copy_byte Copies bytes from to AS_IS, INVERTED, or SPECIAL, depending on the setting of . If is set to SPECIAL, then the parameter must point to an index array indicating the order of byte-swapping. RETURNS: no. of bytes copied */ unsigned int copy_byte(char dest[], char src[], int nbytes, int flag, int index[]) { int i; char *buff; switch (flag) { case AS_IS: if (dest != src) { for (i = 0; i < nbytes; i++) dest[i] = src[i]; } else i = nbytes; break; case INVERTED: if (dest == src) buff = malloc(nbytes); else buff = dest; for (i = 0; i < nbytes; i++) buff[i] = src[nbytes-1-i]; if (dest != buff) { for (i = 0; i < nbytes; i++) dest[i] = buff[i]; free(buff); } break; case SPECIAL: if (dest == src) buff = malloc(nbytes); else buff = dest; for (i = 0; i < nbytes; i++) buff[i] = src[index[i]]; if (dest != buff) { for (i = 0; i < nbytes; i++) dest[i] = buff[i]; free(buff); } break; default: i = 0; break; } return(i); } /*----------------------------------------------------------------------------- FUNCTION: shift_double Shifts a double-sized to the RIGHT or LEFT depending on the setting of . */ void shift_double(unsigned char orig[], int nbits, int direction, int to) { int i; unsigned char c[8]; union { unsigned short int us; unsigned char c[2]; } u; int offset; /* adjust for byte swapping */ offset = !(to == PC_COMPATIBLE_HOST || to == VAXD_COMPATIBLE_HOST); copy_byte((char *) c, (char *) orig, 8, AS_IS, NULL); c[0] &= 0x7F; /* turn sign bit off */ u.us = 0; if (direction == RIGHT) for (i = 0; i < 8; i++) { *(u.c + offset) = c[i]; u.us = u.us << (8 - nbits); c[i] = *(u.c + (1 - offset)); u.us = u.us << nbits; } else for (i = 7; i >= 0; i--) { *(u.c + (1 - offset)) = c[i]; u.us = u.us >> (8 - nbits); c[i] = *(u.c + offset); u.us = u.us >> nbits; } if (orig[0] > 0x7F) c[0] |= 0x80; /* turn sign bit on */ copy_byte((char *) orig, (char *) c, 8, AS_IS, NULL); } /*----------------------------------------------------------------------------- FUNCTION: IEEE_to_VAXDFLOAT Converts an IEEE format double (bytes in normal order) to a VAX-DFLOAT format double . RETURNS: 0 if okay -1 if exponent overflow */ int IEEE_to_VAXDFLOAT(unsigned char vaxd[], unsigned char ieee[]) { unsigned char s, t; s = ieee[0] & 0x80; /* save sign bit */ ieee[0] &= 0x7F; /* turn off sign bit */ if (cmp_byte( (char *) ieee, "\0\0\0\0\0\0\0\0", 8)) { ieee[0] -= 0x37; t = ieee[1] - 0xE0; if (t > ieee[1]) ieee[0] --; /* there is a borrow */ ieee[1] = t; if (ieee[0] > 0xF) { printf("\n ERROR: exponent overflow %u", ieee[0]); puts("\n FROM FUNCTION: IEEE_to_VAXDFLOAT"); return(-1); } shift_double(ieee, 3, LEFT, VAXD_COMPATIBLE_HOST); } if (s != 0) ieee[0] |= 0x80; /* turn on sign bit */ copy_byte((char *) vaxd, (char *) ieee, 8, SPECIAL, VAX_DOUBLE_INDEX); return(0); } /*----------------------------------------------------------------------------- FUNCTION: VAXDFLOAT_to_IEEE Converts a VAX-DFLOAT format double to an IEEE format double . */ void VAXDFLOAT_to_IEEE(unsigned char ieee[], unsigned char vaxd[], int to) { unsigned char t; static unsigned char signed_zero[] = {0x80, 0, 0, 0, 0, 0, 0, 0}; copy_byte((char *) ieee, (char *) vaxd, 8, SPECIAL, VAX_DOUBLE_INDEX); if ((cmp_byte((char *) vaxd, "\0\0\0\0\0\0\0\0", 8)) && (cmp_byte((char *) vaxd, (char *)signed_zero, 8))) { shift_double(ieee, 3, RIGHT, to); ieee[0] += 0x37; /* add bias byte-by-byte */ t = ieee[1] + 0xE0; if (t < ieee[1]) ieee[0] ++; /* there is a carry */ ieee[1] = t; } } /*----------------------------------------------------------------------------- FUNCTION: convert_array_double Copies the array of doubles in format to the array of doubles in the HOST_ENVIRONMENT format. RETURNS: no. of bytes converted if okay BADUINT on error (unknown host or exponent overflow) */ unsigned int convert_array_double(char dest[], char src[], int from, int to, unsigned int nv) { unsigned char temp[8]; unsigned int i; switch(to) { case PC_COMPATIBLE_HOST: switch(from) { case SUN3_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(DOUBLE), src + i * sizeof(DOUBLE), sizeof(DOUBLE), INVERTED, NULL); return(nv * sizeof(DOUBLE)); case VAXD_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { VAXDFLOAT_to_IEEE(temp, (unsigned char *) src + i * sizeof(DOUBLE), to); copy_byte(dest + i * sizeof(DOUBLE), (char *) temp, sizeof(DOUBLE), INVERTED, NULL); } return(nv * sizeof(DOUBLE)); case PC_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(DOUBLE), AS_IS, NULL)); default: printf("\n ERROR: unknown host = %u", from); } break; case SUN3_COMPATIBLE_HOST: switch(from) { case SUN3_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(DOUBLE), AS_IS, NULL)); case PC_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(DOUBLE), src + i * sizeof(DOUBLE), sizeof(DOUBLE), INVERTED, NULL); return(nv * sizeof(DOUBLE)); case VAXD_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { VAXDFLOAT_to_IEEE(temp, (unsigned char *) src + i * sizeof(DOUBLE), to); copy_byte(dest + i * sizeof(DOUBLE), (char *) temp, sizeof(DOUBLE), AS_IS, NULL); } return(nv * sizeof(DOUBLE)); default: printf("\n ERROR: unknown host = %u", from); } break; case VAXD_COMPATIBLE_HOST: switch(from) { case PC_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { copy_byte((char *) temp, src + i * sizeof(DOUBLE), sizeof(DOUBLE), INVERTED, NULL); if (IEEE_to_VAXDFLOAT((unsigned char *) dest + i * sizeof(DOUBLE), temp) != 0) { printf("\n ERROR: exponent overflow converting value i = %u", i); goto error_found; } } return(nv * sizeof(DOUBLE)); case SUN3_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { copy_byte((char *) temp, src + i * sizeof(DOUBLE), sizeof(DOUBLE), AS_IS, NULL); if (IEEE_to_VAXDFLOAT((unsigned char *) dest + i * sizeof(DOUBLE), temp) != 0) { printf("\n ERROR: exponent overflow converting value i = %u", i); goto error_found; } } return(nv * sizeof(DOUBLE)); case VAXD_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(DOUBLE), AS_IS, NULL)); default: printf("\n ERROR: unknown host = %u", from); } break; default: printf("\n ERROR: unknown destination = %u", to); break; } error_found: puts("\n FROM FUNCTION: convert_array_double"); return(BADUINT); } /*----------------------------------------------------------------------------- FUNCTION: convert_array_float Copies the array of floats in format to the array of floats in HOST_ENVIRONMENT format. RETURNS: no. of bytes converted if okay BADUINT on error (unknown host) */ unsigned int convert_array_float(char dest[], char src[], int from, int to, unsigned int nv) { unsigned int i, j; static unsigned char ieee_signed_zero[] = {0x80, 0, 0, 0}; static unsigned char pc_signed_zero[] = {0, 0, 0, 0x80}; static unsigned char vax_signed_zero[] = {0, 0x80, 0, 0}; switch (to) { case PC_COMPATIBLE_HOST: switch (from) { case SUN3_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(FLOAT), src + i * sizeof(FLOAT), sizeof(FLOAT), INVERTED, NULL); return(nv * sizeof(FLOAT)); case VAXD_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { j = i * sizeof(FLOAT); *(dest + j) = *(src + j + 2); *(dest + j + 1) = *(src + j + 3); *(dest + j + 2) = *(src + j); if ((cmp_byte(src + j, "\0\0\0\0", 4)) && (cmp_byte(src + j,(char *) vax_signed_zero, 4))) *(dest + j + 3) = *(src + j + 1) - 1; /* adjust for bias difference */ else *(dest + j + 3) = *(src + j + 1); } return(nv * sizeof(FLOAT)); case PC_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(FLOAT), AS_IS, NULL)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_float"); return(BADUINT); } break; case VAXD_COMPATIBLE_HOST: switch(from) { case SUN3_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { j = i * sizeof(FLOAT); *(dest + j) = *(src + j + 1); if ((cmp_byte(src + j, "\0\0\0\0", 4)) && (cmp_byte(src + j, (char *)ieee_signed_zero, 4))) *(dest + j + 1) = *(src + j) + 1; /* adjust for bias difference */ else *(dest + j + 1) = *(src + j); *(dest + j + 2) = *(src + j + 3); *(dest + j + 3) = *(src + j + 2); } return(nv * sizeof(FLOAT)); case VAXD_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(FLOAT), AS_IS, NULL)); case PC_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { j = i * sizeof(FLOAT); *(dest + j) = *(src + j + 2); if ((cmp_byte(src + j, "\0\0\0\0", 4)) && (cmp_byte(src + j,(char *) pc_signed_zero, 4))) *(dest + j + 1) = *(src + j + 3) + 1; /* adjust for bias difference */ else *(dest + j + 1) = *(src + j + 3); *(dest + j + 2) = *(src + j); *(dest + j + 3) = *(src + j + 1); } return(nv * sizeof(FLOAT)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_float"); return(BADUINT); } break; case SUN3_COMPATIBLE_HOST: switch(from) { case SUN3_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(FLOAT), AS_IS, NULL)); case VAXD_COMPATIBLE_HOST: for (i = 0; i < nv; i++) { j = i * sizeof(FLOAT); if ((cmp_byte(src + j, "\0\0\0\0", 4)) && (cmp_byte(src + j, (char *)vax_signed_zero, 4))) *(dest + j) = *(src + j + 1) - 1; /* adjust for bias difference */ else *(dest + j) = *(src + j + 1); *(dest + j + 1) = *(src + j); *(dest + j + 2) = *(src + j + 3); *(dest + j + 3) = *(src + j + 2); } return(nv * sizeof(FLOAT)); case PC_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(FLOAT), src + i * sizeof(FLOAT), sizeof(FLOAT), INVERTED, NULL); return(nv * sizeof(FLOAT)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_float"); return(BADUINT); } break; default: printf("\n ERROR: unknown destination = %u", to); puts("\n FROM FUNCTION: convert_array_float"); } return(BADUINT); } /*----------------------------------------------------------------------------- FUNCTION: convert_array_long Copies the array of longs/unsigned longs in format to the array of longs/unsigned longs in HOST_ENVIRONMENT format. RETURNS: no. of bytes converted if okay BADUINT on error (unknown host) */ unsigned int convert_array_long(char dest[], char src[], int from, int to, unsigned int nv) { unsigned int i; switch(to) { case PC_COMPATIBLE_HOST: case VAXD_COMPATIBLE_HOST: switch (from) { case SUN3_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(LONG), src + i * sizeof(LONG), sizeof(LONG), INVERTED, NULL); return(nv * sizeof(LONG)); case VAXD_COMPATIBLE_HOST: case PC_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(LONG), AS_IS, NULL)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_long"); return(BADUINT); } break; case SUN3_COMPATIBLE_HOST: switch(from) { case SUN3_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(LONG), AS_IS, NULL)); case VAXD_COMPATIBLE_HOST: case PC_COMPATIBLE_HOST: for (i = 0; i < nv; i ++) copy_byte(dest + i * sizeof(LONG), src + i * sizeof(LONG), sizeof(LONG), INVERTED, NULL); return(nv * sizeof(LONG)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_long"); return(BADUINT); } break; default: printf("\n ERROR: unknown destination = %u", to); puts("\n FROM FUNCTION: convert_array_long"); } return(BADUINT); } /*----------------------------------------------------------------------------- FUNCTION: convert_array_short Copies the array of shorts/unsigned shorts in format to the array of shorts/unsigned shorts in HOST_ENVIRONMENT format. RETURNS: no. of bytes converted if okay BADUINT on error (unknown host) */ unsigned int convert_array_short(char dest[], char src[], int from, int to, unsigned int nv) { unsigned int i; switch(to) { case PC_COMPATIBLE_HOST: case VAXD_COMPATIBLE_HOST: switch (from) { case SUN3_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(SHORT), src + i * sizeof(SHORT), sizeof(SHORT), INVERTED, NULL); return(nv * sizeof(SHORT)); case VAXD_COMPATIBLE_HOST: case PC_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(SHORT), AS_IS, NULL)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_short"); return(BADUINT); } break; case SUN3_COMPATIBLE_HOST: switch(from) { case SUN3_COMPATIBLE_HOST: return(copy_byte(dest, src, nv * sizeof(SHORT), AS_IS, NULL)); case VAXD_COMPATIBLE_HOST: case PC_COMPATIBLE_HOST: for (i = 0; i < nv; i++) copy_byte(dest + i * sizeof(SHORT), src + i * sizeof(SHORT), sizeof(SHORT), INVERTED, NULL); return(nv * sizeof(SHORT)); default: printf("\n ERROR: unknown host = %u", from); puts("\n FROM FUNCTION: convert_array_short"); return(BADUINT); } break; default: printf("\n ERROR: unknown destination = %u", to); puts("\n FROM FUNCTION: convert_array_short"); } return(BADUINT); } /*----------------------------------------------------------------------------- FUNCTION: convert_struct Converts a structure in format to the structure in HOST_ENVIRONMENT format by referring to the structure definition specified by located somewhere in the linked list pointed to by . RETURNS: no. of bytes converted if okay BADUINT if no structure definition is found */ unsigned int convert_struct(char *dest, char *src, int from, int to, char *struct_name, STRUCT_DEF_HDR_TYPE *strdef) { unsigned int i, nelem, byte_count, ofs = 0; STRUCT_DEF_ENTRY_TYPE *strdef_ptr; if ((strdef == NULL) || ((strdef_ptr = (STRUCT_DEF_ENTRY_TYPE *) find_def(struct_name, strdef)) == NULL)) { printf("\n ERROR: undefined structure = %s", struct_name); goto error_found; } nelem = strdef_ptr->hdr.nelem; for (i = 0; i < nelem; i++) { strdef_ptr += 1; if ((byte_count = convert_select(dest + ofs, src + ofs, from, to, strdef_ptr->elem.count, strdef_ptr->elem.value_type, strdef_ptr->elem.name, strdef)) == BADUINT) goto error_found; ofs += byte_count; } return(ofs); error_found: puts("\n FROM FUNCTION: convert_struct"); return(BADUINT); } /*----------------------------------------------------------------------------- FUNCTION: convert_array_struct Converts instances of the structure from in format to in HOST_ENVIRONMENT format using the structure definition somewhere in as a key. NOTE: If the parameter is less than zero, then its absolute value is taken as an indication of the number of bytes in the entire array of structure, and conversion continues until all bytes have been processed. RETURNS: no. of bytes converted if okay BADUINT if error (undefined structure, unknown host or exponent overflow) */ unsigned int convert_array_struct(char *dest, char *src, int from, int to, int nv, char *struct_name, STRUCT_DEF_HDR_TYPE *strdef) { unsigned int i, ofs = 0, byte_count = 0; if (nv < 0) /* -nv is no. of bytes in data structure */ { while (ofs < abs(nv)) { if ((byte_count = convert_struct(dest + ofs, src + ofs, from, to, struct_name, strdef)) == BADUINT) goto error_found; ofs += byte_count; } return(ofs); } for (i = 0; i < nv; i++) { if ((byte_count = convert_struct(dest + ofs, src + ofs, from, to, struct_name, strdef)) == BADUINT) goto error_found; ofs += byte_count; } return(ofs); error_found: puts("\n FROM FUNCTION: convert_array_struct"); return(BADUINT); } /*----------------------------------------------------------------------------- FUNCTION: convert_select Copies values from array in format to the array in HOST_ENVIRONMENT format by calling the appropriate convert_array_* function, if needed, according to the setting of the flag. In the case of a STRUCT_VALUE_CODE , additional information regarding the and is needed. RETURNS: no. of bytes converted if okay BADUINT on error (undefined structure, unknown host, exponent overflow, or unrecognized value type) */ unsigned int convert_select(char *dest, char *src, int from, int to, unsigned int nv, unsigned int value_type, char *struct_name, STRUCT_DEF_HDR_TYPE *strdef) { switch (value_type) { case BYTE_VALUE_CODE: case UBYTE_VALUE_CODE: case CHAR_VALUE_CODE: case TEXT_VALUE_CODE: return(copy_byte(dest, src, nv, AS_IS, NULL)); case SHORT_VALUE_CODE: case USHORT_VALUE_CODE: return(convert_array_short(dest, src, from, to, nv)); case LONG_VALUE_CODE: case ULONG_VALUE_CODE: return(convert_array_long(dest, src, from, to, nv)); case FLOAT_VALUE_CODE: return(convert_array_float(dest, src, from, to, nv)); case DOUBLE_VALUE_CODE: return(convert_array_double(dest, src, from, to, nv)); case COMPLEX_VALUE_CODE: return(convert_array_float(dest, src, from, to, nv * 2)); case STRUCT_VALUE_CODE: return(convert_array_struct(dest, src, from, to, nv, struct_name, strdef)); default: printf("\n ERROR: unrecognized value type = %d", value_type); puts("\n FROM FUNCTION: convert_select"); return(BADUINT); } }