port_init.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*!
  2. \file diglib/port_init.c
  3. \brief Vector library - portability (lower level functions)
  4. Lower level functions for reading/writing/manipulating vectors.
  5. This code is a quick hack to allow the writing of portable
  6. binary data files.
  7. The approach is to take known values and compare them against
  8. the current machine's internal representation. A cross reference
  9. table is then built, and then all file reads and writes must go
  10. through these routines to correct the numbers if need be.
  11. As long as the byte switching is symetrical, the conversion routines
  12. will work both directions.
  13. The integer test patterns are quite simple, and their choice was
  14. arbitrary, but the float and double valued were more critical.
  15. I did not have a specification for IEEE to go by, so it is possible
  16. that I have missed something. My criteria were:
  17. First, true IEEE numbers had to be chosen to avoid getting an FPE.
  18. Second, every byte in the test pattern had to be unique. And
  19. finally, the number had to not be sensitive to rounding by the
  20. specific hardware implementation.
  21. By experimentation it was found that the number 1.3333 met
  22. all these criteria for both floats and doubles
  23. See the discourse at the end of this file for more information
  24. The 3.0 dig, and dig_plus files are inherently non-portable. This
  25. can be seen in moving files between a SUN 386i and other SUN machines.
  26. The recommended way to transport files was always to convert to ASCII
  27. (b.a.vect) and copy the ASCII files: dig_ascii and dig_att to the
  28. destination machine.
  29. The problem lies in the way that different architectures internally
  30. represent data. If a number is internally store as 0x01020304 on
  31. a 680x0 family machine, the same number will be stored as
  32. 0x04030201 on an 80386 class machine.
  33. The CERL port of GRASS to the Compaq 386 already has code to deal
  34. with this incompatibility. This code converts all files that are written
  35. out to conform to the 680x0 standard. These binary files can then be
  36. shared between machines without conversion.
  37. This code is designed to work with the majority of computers in use
  38. today that fit the following requirements:
  39. byte == 8 bits
  40. int == 4 bytes
  41. long == 4 bytes
  42. double == IEEE standard 64 bit
  43. float == IEEE standard 32 bit
  44. bytes can be swapped around in any reasonable way, but bits within each
  45. byte must be maintained in normal high to low ordering: 76543210
  46. is this a problem?
  47. If this ability is desired on a SUN 386i, for example, you simply
  48. define the compiler flag CERL_PORTABLE in the src/CMD/makehead file
  49. and recompile all of the mapdev programs.
  50. needs update, makehead/mapdev no longer exist
  51. Binary DLG files are NOT supported by this code, and will continue to
  52. be non-portable between different architectures.
  53. applies to the files coor/topo/cidx, needs testing
  54. (C) 2001-2009 by the GRASS Development Team
  55. This program is free software under the GNU General Public License
  56. (>=v2). Read the file COPYING that comes with GRASS for details.
  57. \author Original author CERL, probably Dave Gerdes
  58. \author Update to GRASS 5.7 Radim Blazek
  59. */
  60. #include <stdio.h>
  61. #include <sys/types.h>
  62. #include <grass/vector.h>
  63. #include <grass/glocale.h>
  64. #define TEST_PATTERN 1.3333
  65. #ifdef HAVE_LONG_LONG_INT
  66. #define LONG_LONG_TEST 0x0102030405060708LL
  67. #endif
  68. #define LONG_TEST 0x01020304
  69. #define INT_TEST 0x01020304
  70. #define SHORT_TEST 0x0102
  71. static double u_d = TEST_PATTERN;
  72. static float u_f = TEST_PATTERN;
  73. off_t u_o; /* depends on sizeof(off_t) */
  74. static long u_l = LONG_TEST;
  75. static int u_i = INT_TEST;
  76. static short u_s = SHORT_TEST;
  77. /* dbl_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
  78. static const unsigned char dbl_cmpr[] =
  79. { 0x3f, 0xf5, 0x55, 0x32, 0x61, 0x7c, 0x1b, 0xda };
  80. /* flt_cmpr holds the bytes of an IEEE representation of TEST_PATTERN */
  81. static const unsigned char flt_cmpr[] = { 0x3f, 0xaa, 0xa9, 0x93 };
  82. static const unsigned char off_t_cmpr[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
  83. static const unsigned char lng_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
  84. static const unsigned char int_cmpr[] = { 0x01, 0x02, 0x03, 0x04 };
  85. static const unsigned char shrt_cmpr[] = { 0x01, 0x02 };
  86. /* Find native sizes */
  87. int nat_dbl = sizeof(double);
  88. int nat_flt = sizeof(float);
  89. int nat_off_t = sizeof(off_t);
  90. int nat_lng = sizeof(long);
  91. int nat_int = sizeof(int);
  92. int nat_shrt = sizeof(short);
  93. int dbl_order;
  94. int flt_order;
  95. int off_t_order;
  96. int lng_order;
  97. int int_order;
  98. int shrt_order;
  99. unsigned char dbl_cnvrt[sizeof(double)];
  100. unsigned char flt_cnvrt[sizeof(float)];
  101. unsigned char off_t_cnvrt[sizeof(off_t)];
  102. unsigned char lng_cnvrt[sizeof(long)];
  103. unsigned char int_cnvrt[sizeof(int)];
  104. unsigned char shrt_cnvrt[sizeof(short)];
  105. /*
  106. * match search_value against each char in basis.
  107. * return offset or -1 if not found
  108. */
  109. static int find_offset(const unsigned char *basis, unsigned char search_value,
  110. int size)
  111. {
  112. int i;
  113. for (i = 0; i < size; i++)
  114. if (basis[i] == search_value)
  115. return (i);
  116. return (-1);
  117. }
  118. static int find_offsets(const void *pattern, unsigned char *cnvrt,
  119. const unsigned char *cmpr, int port_size,
  120. int nat_size, const char *typename)
  121. {
  122. int big, ltl;
  123. int i;
  124. for (i = 0; i < port_size; i++) {
  125. int off = find_offset(pattern, cmpr[i], nat_size);
  126. if (off < 0)
  127. G_fatal_error(_("Unable to find '%x' in %s"), cmpr[i], typename);
  128. cnvrt[i] = off;
  129. }
  130. big = ltl = 1;
  131. for (i = 0; i < port_size; i++) {
  132. if (cnvrt[i] != (nat_size - port_size + i))
  133. big = 0; /* isn't big endian */
  134. if (cnvrt[i] != (port_size - 1 - i))
  135. ltl = 0; /* isn't little endian */
  136. }
  137. if (big)
  138. return ENDIAN_BIG;
  139. if (ltl)
  140. return ENDIAN_LITTLE;
  141. return ENDIAN_OTHER;
  142. }
  143. /*!
  144. \brief Initialize Port_info structures
  145. */
  146. void port_init(void)
  147. {
  148. static int done;
  149. if (done)
  150. return;
  151. done = 1;
  152. /* Following code checks only if all assumptions are fullfilled */
  153. /* Check sizes */
  154. if (nat_dbl != PORT_DOUBLE)
  155. G_fatal_error("sizeof(double) != %d", PORT_DOUBLE);
  156. if (nat_flt != PORT_FLOAT)
  157. G_fatal_error("sizeof(float) != %d", PORT_DOUBLE);
  158. /* off_t size is variable, depending on the vector size and LFS support */
  159. if (nat_lng < PORT_LONG)
  160. G_fatal_error("sizeof(long) < %d", PORT_LONG);
  161. if (nat_int < PORT_INT)
  162. G_fatal_error("sizeof(int) < %d", PORT_INT);
  163. if (nat_shrt < PORT_SHORT)
  164. G_fatal_error("sizeof(short) < %d", PORT_SHORT);
  165. /* Find for each byte in big endian test pattern (*_cmpr)
  166. * offset of corresponding byte in machine native order.
  167. * Look if native byte order is little or big or some other (pdp)
  168. * endian.
  169. */
  170. if (nat_off_t == 8)
  171. #ifdef HAVE_LONG_LONG_INT
  172. u_o = (off_t) LONG_LONG_TEST;
  173. #else
  174. G_fatal_error("Internal error: can't construct an off_t literal");
  175. #endif
  176. else
  177. u_o = (off_t) LONG_TEST;
  178. dbl_order =
  179. find_offsets(&u_d, dbl_cnvrt, dbl_cmpr, PORT_DOUBLE, nat_dbl,
  180. "double");
  181. flt_order =
  182. find_offsets(&u_f, flt_cnvrt, flt_cmpr, PORT_FLOAT, nat_flt, "float");
  183. off_t_order =
  184. find_offsets(&u_o, off_t_cnvrt, off_t_cmpr, nat_off_t, nat_off_t, "off_t");
  185. lng_order =
  186. find_offsets(&u_l, lng_cnvrt, lng_cmpr, PORT_LONG, nat_lng, "long");
  187. int_order =
  188. find_offsets(&u_i, int_cnvrt, int_cmpr, PORT_INT, nat_int, "int");
  189. shrt_order =
  190. find_offsets(&u_s, shrt_cnvrt, shrt_cmpr, PORT_SHORT, nat_shrt,
  191. "short");
  192. }