/* typeconv.c - convert between char arrays and unsigneds */ /* Copyright (C) 1994 Bruce Evans */ /* c2u2(): 2 byte array to 2 byte unsigned c4u4(): 4 byte array to 4 byte unsigned cnu2(): n byte array to 2 byte unsigned cnu4(): n byte array to 4 byte unsigned u2c2(): 2 byte unsigned to 2 byte array u2cn(): 2 byte unsigned to n byte array u4c4(): 4 byte unsigned to 4 byte array u4cn(): 4 byte unsigned to n byte array typeconv_init: (re)initialise for given byte order. Default is no swapping, but the initialisation should be done anyway to provide some validity checks (returns FALSE if error). Not provided: c2u4(), c4u2(), u2c4(), u4c2(). Each of these is best done by truncating or extending a return value or argument to the appropiate fixed-count function. c4u2() has too many cases to do in-line conveniently, and the others are hardly more efficient when done in-line. 4 byte orderings for both char arrays and unsigneds are supported: 0123 - little-endian 3210 - big-endian 2301 - little-endian with long words big-endian (pdp11) 1032 - big-endian with long words little_endian (who knows?) The unsigned's byte order is that of the machine on which these routines are running. It is determined at run time initialisation since the compiler/ preprocessor is too dumb to tell us at compile time. */ #include "const.h" #include "type.h" #include "globvar.h" FORWARD u2_pt c2u2_00 P((char *buf)); FORWARD u4_pt c4u4_00 P((char *buf)); FORWARD u2_pt c2u2_ss P((char *buf)); FORWARD u4_pt c4u4_ss P((char *buf)); FORWARD u4_pt c4u4_s0 P((char *buf)); FORWARD u4_pt c4u4_0s P((char *buf)); FORWARD void u2c2_00 P((char *buf, u2_pt offset)); FORWARD void u4c4_00 P((char *buf, u4_t offset)); FORWARD void u2c2_ss P((char *buf, u2_pt offset)); FORWARD void u4c4_ss P((char *buf, u4_t offset)); FORWARD void u4c4_s0 P((char *buf, u4_t offset)); FORWARD void u4c4_0s P((char *buf, u4_t offset)); PRIVATE u2_pt (*pc2u2) P((char *buf)) = c2u2_00; PRIVATE u4_pt (*pc4u4) P((char *buf)) = c4u4_00; PRIVATE void (*pu2c2) P((char *buf, u2_pt offset)) = u2c2_00; PRIVATE void (*pu4c4) P((char *buf, u4_t offset)) = u4c4_00; /* === char arrays to unsigneds === */ /* no bytes swapped, longwinded to avoid alignment problems */ PRIVATE u2_pt c2u2_00(buf) register char *buf; { u2_t offset; ((char *) &offset)[0] = buf[0]; ((char *) &offset)[1] = buf[1]; return offset; } PRIVATE u4_pt c4u4_00(buf) register char *buf; { u4_t offset; ((char *) &offset)[0] = buf[0]; ((char *) &offset)[1] = buf[1]; ((char *) &offset)[2] = buf[2]; ((char *) &offset)[3] = buf[3]; return offset; } /* straight swapping for little-endian to big-endian and vice versa */ PRIVATE u2_pt c2u2_ss(buf) register char *buf; { u2_t offset; ((char *) &offset)[0] = buf[1]; ((char *) &offset)[1] = buf[0]; return offset; } PRIVATE u4_pt c4u4_ss(buf) register char *buf; { u4_t offset; ((char *) &offset)[0] = buf[3]; ((char *) &offset)[1] = buf[2]; ((char *) &offset)[2] = buf[1]; ((char *) &offset)[3] = buf[0]; return offset; } /* wierd swapping for different-endian u2's, same-endian u4's */ PRIVATE u4_pt c4u4_s0(buf) register char *buf; { u4_t offset; ((char *) &offset)[0] = buf[1]; ((char *) &offset)[1] = buf[0]; ((char *) &offset)[2] = buf[3]; ((char *) &offset)[3] = buf[2]; return offset; } /* very wierd swapping for same-endian u2's, different-endian u4's */ PRIVATE u4_pt c4u4_0s(buf) register char *buf; { u4_t offset; ((char *) &offset)[0] = buf[2]; ((char *) &offset)[1] = buf[3]; ((char *) &offset)[2] = buf[0]; ((char *) &offset)[3] = buf[1]; return offset; } /* === entry points === */ PUBLIC u2_pt c2u2(buf) char *buf; { return (*pc2u2) (buf); } PUBLIC u4_t c4u4(buf) char *buf; { return (*pc4u4) (buf); } PUBLIC u2_pt cnu2(buf, count) char *buf; unsigned count; { switch (count) { case 1: return buf[0] & 0xFF; case 2: return (*pc2u2) (buf); case 4: return (u2_pt) (*pc4u4) (buf); default: return 0; } } PUBLIC u4_t cnu4(buf, count) char *buf; unsigned count; { switch (count) { case 1: return buf[0] & 0xFF; case 2: return (*pc2u2) (buf); case 4: return (*pc4u4) (buf); default: return 0; } } /* === unsigneds to char arrays === */ /* no bytes swapped, longwinded to avoid alignment problems */ PRIVATE void u2c2_00(buf, offset) register char *buf; u2_pt offset; { buf[0] = ((char *) &offset)[0]; buf[1] = ((char *) &offset)[1]; } PRIVATE void u4c4_00(buf, offset) register char *buf; u4_t offset; { buf[0] = ((char *) &offset)[0]; buf[1] = ((char *) &offset)[1]; buf[2] = ((char *) &offset)[2]; buf[3] = ((char *) &offset)[3]; } /* straight swapping for little-endian to big-endian and vice versa */ PRIVATE void u2c2_ss(buf, offset) register char *buf; u2_pt offset; { u2_t offset2; offset2 = offset; buf[0] = ((char *) &offset2)[1]; buf[1] = ((char *) &offset2)[0]; } PRIVATE void u4c4_ss(buf, offset) register char *buf; u4_t offset; { buf[0] = ((char *) &offset)[3]; buf[1] = ((char *) &offset)[2]; buf[2] = ((char *) &offset)[1]; buf[3] = ((char *) &offset)[0]; } /* wierd swapping for different-endian u2's, same-endian u4's */ PRIVATE void u4c4_s0(buf, offset) register char *buf; u4_t offset; { buf[0] = ((char *) &offset)[1]; buf[1] = ((char *) &offset)[0]; buf[2] = ((char *) &offset)[3]; buf[3] = ((char *) &offset)[2]; } /* very wierd swapping for same-endian u2's, different-endian u4's */ PRIVATE void u4c4_0s(buf, offset) register char *buf; u4_t offset; { buf[0] = ((char *) &offset)[2]; buf[1] = ((char *) &offset)[3]; buf[2] = ((char *) &offset)[0]; buf[3] = ((char *) &offset)[1]; } /* === entry points === */ PUBLIC void u2c2(buf, offset) register char *buf; u2_pt offset; { (*pu2c2) (buf, offset); } PUBLIC void u4c4(buf, offset) register char *buf; u4_t offset; { (*pu4c4) (buf, offset); } PUBLIC void u2cn(buf, offset, count) register char *buf; u2_pt offset; unsigned count; { switch (count) { case 1: buf[0] = (char) offset; return; case 2: (*pu2c2) (buf, offset); return; case 4: (*pu4c4) (buf, (u4_t) offset); return; } } PUBLIC void u4cn(buf, offset, count) register char *buf; u4_t offset; unsigned count; { switch (count) { case 1: buf[0] = (char) offset; return; case 2: (*pu2c2) (buf, (u2_pt) (u2_t) offset); return; case 4: (*pu4c4) (buf, offset); return; } } /* initialise type conversion, return FALSE if it cannot be handled */ PUBLIC bool_pt typeconv_init(big_endian, long_big_endian) bool_pt big_endian; bool_pt long_big_endian; { u2_pt conv2; u4_pt conv4; char *conv2ptr; char *conv4ptr; if (sizeof(u2_t) != 2 || sizeof(u4_t) != 4) /* dumb preprocessor's don't accept sizeof in #if expressions */ return FALSE; if (big_endian) { conv2ptr = (conv4ptr = "\1\2\3\4") + 2; if (!long_big_endian) conv4ptr = "\3\4\1\2"; } else { conv2ptr = conv4ptr = "\4\3\2\1"; if (long_big_endian) conv4ptr = "\2\1\4\3"; } conv2 = c2u2_00(conv2ptr); conv4 = c4u4_00(conv4ptr); if (conv2 == 0x0304) { pc2u2 = c2u2_00; pc4u4 = c4u4_00; pu2c2 = u2c2_00; pu4c4 = u4c4_00; if (conv4 == 0x03040102L) { pc4u4 = c4u4_0s; pu4c4 = u4c4_0s; } else if (conv4 != 0x01020304L) return FALSE; } else if (conv2 == 0x0403) { pc2u2 = c2u2_ss; pc4u4 = c4u4_ss; pu2c2 = u2c2_ss; pu4c4 = u4c4_ss; if (conv4 == 0x02010403L) { pc4u4 = c4u4_s0; pu4c4 = u4c4_s0; } else if (conv4 != 0x04030201L) return FALSE; } else return FALSE; return TRUE; } #ifdef DEBUG_TYPECONV main() { char *source; char target[4]; u2_t u2; u2_t u2a; u4_t u4; u4_t u4a; printf("%u\n", typeconv_init(FALSE, FALSE)); printf("%u\n", typeconv_init(FALSE, TRUE)); printf("%u\n", typeconv_init(TRUE, FALSE)); printf("%u\n", typeconv_init(TRUE, TRUE)); typeconv_init(FALSE, FALSE); source = "\4\3\2\1"; target[0] = 0; target[1] = 0; u2 = cnu2(source, 2); u2cn(target, u2, 2); if (strncmp(source, target, 2)) printf("oops9\n"); target[0] = 0; target[1] = 0; u4a = cnu4(source, 2); u4cn(target, u4a, 2); if (strncmp(source, target, 2)) printf("oops10\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u2a = cnu2(source, 4); u2cn(target, u2a, 4); if (strncmp(target, "\4\3\0\0", 4)) printf("oops11\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u4 = cnu4(source, 4); u4cn(target, u4, 4); if (strncmp(source, target, 4)) printf("oops12\n"); printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a); typeconv_init(FALSE, TRUE); source = "\2\1\4\3"; target[0] = 0; target[1] = 0; u2 = cnu2(source + 2, 2); u2cn(target, u2, 2); if (strncmp(source + 2, target, 2)) printf("oops13\n"); target[0] = 0; target[1] = 0; u4a = cnu4(source + 2, 2); u4cn(target, u4a, 2); if (strncmp(source + 2, target, 2)) printf("oops14\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u2a = cnu2(source, 4); u2cn(target, u2a, 4); if (strncmp(target, "\0\0\4\3", 4)) printf("oops15\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u4 = cnu4(source, 4); u4cn(target, u4, 4); if (strncmp(source, target, 4)) printf("oops16\n"); printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a); typeconv_init(TRUE, FALSE); source = "\3\4\1\2"; target[0] = 0; target[1] = 0; u2 = cnu2(source, 2); u2cn(target, u2, 2); if (strncmp(source, target, 2)) printf("oops5\n"); target[0] = 0; target[1] = 0; u4a = cnu4(source, 2); u4cn(target, u4a, 2); if (strncmp(source, target, 2)) printf("oops6\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u2a = cnu2(source, 4); u2cn(target, u2a, 4); if (strncmp(target, "\3\4\0\0", 4)) printf("oops7\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u4 = cnu4(source, 4); u4cn(target, u4, 4); if (strncmp(source, target, 4)) printf("oops8\n"); printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a); typeconv_init(TRUE, TRUE); source = "\1\2\3\4"; target[0] = 0; target[1] = 0; u2 = cnu2(source + 2, 2); u2cn(target, u2, 2); if (strncmp(source + 2, target, 2)) printf("oops1\n"); target[0] = 0; target[1] = 0; u4a = cnu4(source + 2, 2); u4cn(target, u4a, 2); if (strncmp(source + 2, target, 2)) printf("oops2\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u2a = cnu2(source, 4); u2cn(target, u2a, 4); if (strncmp(target, "\0\0\3\4", 4)) printf("oops3\n"); target[0] = 0; target[1] = 0; target[2] = 0; target[3] = 0; u4 = cnu4(source, 4); u4cn(target, u4, 4); if (strncmp(source, target, 4)) printf("oops4\n"); printf("%04x %04x %08lx %08lx\n", u2, u2a, u4, u4a); } #endif /* DEBUG_TYPECONV */