binio.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /*
  2. * This library is free software; you can redistribute it and/or
  3. * modify it under the terms of the GNU Lesser General Public
  4. * License as published by the Free Software Foundation; either
  5. * version 2.1 of the License, or (at your option) any later version.
  6. *
  7. * This library is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. * Lesser General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU Lesser General Public
  13. * License along with this library; if not, write to the Free Software
  14. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  15. *
  16. * binio.cpp - Binary stream I/O classes
  17. * Copyright (C) 2002, 2003 Simon Peter <dn.tlp@gmx.net>
  18. */
  19. #include <string.h>
  20. #include "binio.h"
  21. #if BINIO_WITH_MATH
  22. #include <math.h>
  23. #ifdef __QNXNTO__
  24. #define pow std::powf
  25. #endif // __QNXNTO__
  26. // If 'math.h' doesn't define HUGE_VAL, we try to use HUGE instead.
  27. #ifndef HUGE_VAL
  28. # define HUGE_VAL HUGE
  29. #endif
  30. #endif
  31. /***** Defines *****/
  32. #if BINIO_ENABLE_STRING
  33. // String buffer size for std::string readString() method
  34. #define STRINGBUFSIZE 256
  35. #endif
  36. /***** binio *****/
  37. const binio::Flags binio::system_flags = binio::detect_system_flags();
  38. const binio::Flags binio::detect_system_flags() {
  39. Flags f = 0;
  40. // Endian test
  41. union {
  42. int word;
  43. Byte byte;
  44. } endian_test;
  45. endian_test.word = 1;
  46. if (endian_test.byte != 1) f |= BigEndian;
  47. // IEEE-754 floating-point test
  48. float fl = 6.5;
  49. Byte *dat = (Byte *)&fl;
  50. if (sizeof(float) == 4 && sizeof(double) == 8) {
  51. if (f & BigEndian) {
  52. if (dat[0] == 0x40 && dat[1] == 0xD0 && !dat[2] && !dat[3])
  53. f |= FloatIEEE;
  54. } else {
  55. if (dat[3] == 0x40 && dat[2] == 0xD0 && !dat[1] && !dat[0])
  56. f |= FloatIEEE;
  57. }
  58. }
  59. return f;
  60. }
  61. binio::binio()
  62. : my_flags(system_flags), err(NoError) {
  63. }
  64. binio::~binio() {
  65. }
  66. void binio::setFlag(Flag f, bool set) {
  67. if (set)
  68. my_flags |= f;
  69. else
  70. my_flags &= !f;
  71. }
  72. bool binio::getFlag(Flag f) {
  73. return (my_flags & f ? true : false);
  74. }
  75. binio::Error binio::error() {
  76. Error e = err;
  77. err = NoError;
  78. return e;
  79. }
  80. bool binio::eof() {
  81. return (err & Eof ? true : false);
  82. }
  83. /***** binistream *****/
  84. binistream::binistream() {
  85. }
  86. binistream::~binistream() {
  87. }
  88. binistream::Int binistream::readInt(unsigned int size) {
  89. unsigned int i;
  90. Int val = 0, in;
  91. // Check if 'size' doesn't exceed our system's biggest type.
  92. if (size > sizeof(Int)) {
  93. err |= Unsupported;
  94. return 0;
  95. }
  96. for (i = 0; i < size; i++) {
  97. in = getByte();
  98. if (getFlag(BigEndian))
  99. val <<= 8;
  100. else
  101. in <<= i * 8;
  102. val |= in;
  103. }
  104. return val;
  105. }
  106. binistream::Float binistream::readFloat(FType ft) {
  107. if (getFlag(FloatIEEE)) { // Read IEEE-754 floating-point value
  108. unsigned int i, size = 0;
  109. Byte in[8];
  110. bool swap;
  111. // Determine appropriate size for given type.
  112. switch (ft) {
  113. case Single:
  114. size = 4;
  115. break; // 32 bits
  116. case Double:
  117. size = 8;
  118. break; // 64 bits
  119. }
  120. // Determine byte ordering, depending on what we do next
  121. if (system_flags & FloatIEEE)
  122. swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
  123. else
  124. swap = !getFlag(BigEndian);
  125. // Read the float byte by byte, converting endianess
  126. for (i = 0; i < size; i++)
  127. if (swap)
  128. in[size - i - 1] = getByte();
  129. else
  130. in[i] = getByte();
  131. if (system_flags & FloatIEEE) {
  132. // Compatible system, let the hardware do the conversion
  133. switch (ft) {
  134. case Single:
  135. return *reinterpret_cast<float *>(in);
  136. case Double:
  137. return *reinterpret_cast<double *>(in);
  138. }
  139. } else { // Incompatible system, convert manually
  140. switch (ft) {
  141. case Single:
  142. return ieee_single2float(in);
  143. case Double:
  144. return ieee_double2float(in);
  145. }
  146. }
  147. }
  148. // User tried to read a (yet) unsupported floating-point type. Bail out.
  149. err |= Unsupported;
  150. return 0.0;
  151. }
  152. binistream::Float binistream::ieee_single2float(Byte *data) {
  153. signed int sign = data[0] >> 7 ? -1 : 1;
  154. unsigned int exp = ((data[0] << 1) & 0xff) | ((data[1] >> 7) & 1),
  155. fracthi7 = data[1] & 0x7f;
  156. Float fract = fracthi7 * 65536.0 + data[2] * 256.0 + data[3];
  157. // Signed and unsigned zero
  158. if (!exp && !fracthi7 && !data[2] && !data[3]) return sign * 0.0;
  159. // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
  160. if (exp == 255) {
  161. if (!fracthi7 && !data[2] && !data[3]) {
  162. #ifdef HUGE_VAL
  163. if (sign == -1) return -HUGE_VAL;
  164. else return HUGE_VAL;
  165. #else
  166. err |= Unsupported;
  167. if (sign == -1) return -1.0;
  168. else return 1.0;
  169. #endif
  170. } else { // Not a number (maybe unsupported on non-IEEE systems)
  171. #ifdef NAN
  172. return NAN;
  173. #else
  174. err |= Unsupported;
  175. return 0.0;
  176. #endif
  177. }
  178. }
  179. if (!exp) // Unnormalized float values
  180. return sign * pow(2.0f, -126.0f) * fract * pow(2.0f, -23.0f);
  181. else // Normalized float values
  182. return sign * pow(2.0f, exp - 127.0f) * (fract * pow(2.0f, -23.0f) + 1);
  183. err |= Fatal;
  184. return 0.0;
  185. }
  186. binistream::Float binistream::ieee_double2float(Byte *data) {
  187. signed int sign = data[0] >> 7 ? -1 : 1;
  188. unsigned int exp = ((unsigned int)(data[0] & 0x7f) << 4) | (data[1] >> 4),
  189. fracthi4 = data[1] & 0xf;
  190. Float fract = fracthi4 * pow(2.0f, 48.0f) + data[2] * pow(2.0f, 40.0f) + data[3] *
  191. pow(2.0f, 32.0f) + data[4] * pow(2.0f, 24.0f) + data[5] * pow(2.0f, 16.0f) + data[6] *
  192. pow(2.0f, 8.0f) + data[7];
  193. // Signed and unsigned zero
  194. if (!exp && !fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] &&
  195. !data[6] && !data[7]) return sign * 0.0;
  196. // Signed and unsigned infinity (maybe unsupported on non-IEEE systems)
  197. if (exp == 2047) {
  198. if (!fracthi4 && !data[2] && !data[3] && !data[4] && !data[5] && !data[6] && !data[7]) {
  199. #ifdef HUGE_VAL
  200. if (sign == -1) return -HUGE_VAL;
  201. else return HUGE_VAL;
  202. #else
  203. err |= Unsupported;
  204. if (sign == -1) return -1.0;
  205. else return 1.0;
  206. #endif
  207. } else { // Not a number (maybe unsupported on non-IEEE systems)
  208. #ifdef NAN
  209. return NAN;
  210. #else
  211. err |= Unsupported;
  212. return 0.0;
  213. #endif
  214. }
  215. }
  216. if (!exp) // Unnormalized float values
  217. return sign * pow(2.0f, -1022.0f) * fract * pow(2.0f, -52.0f);
  218. else // Normalized float values
  219. return sign * pow(2.0f, exp - 1023.0f) * (fract * pow(2.0f, -52.0f) + 1);
  220. err |= Fatal;
  221. return 0.0;
  222. }
  223. #if !BINIO_WITH_MATH
  224. binio::Float binio::pow(Float base, signed int exp)
  225. /* Our own, stripped-down version of pow() for not having to depend on 'math.h'.
  226. * This one handles float values for the base and an integer exponent, both
  227. * positive and negative.
  228. */
  229. {
  230. int i;
  231. Float val = base;
  232. if (!exp) return 1.0;
  233. for (i = 1; i < (exp < 0 ? -exp : exp); i++)
  234. val *= base;
  235. if (exp < 0) val = 1.0 / val;
  236. return val;
  237. }
  238. #endif
  239. unsigned long binistream::readString(char *str, unsigned long maxlen) {
  240. unsigned long i;
  241. for (i = 0; i < maxlen; i++) {
  242. str[i] = (char)getByte();
  243. if (err) {
  244. str[i] = '\0';
  245. return i;
  246. }
  247. }
  248. return maxlen;
  249. }
  250. unsigned long binistream::readString(char *str, unsigned long maxlen,
  251. const char delim) {
  252. unsigned long i;
  253. for (i = 0; i < maxlen; i++) {
  254. str[i] = (char)getByte();
  255. if (str[i] == delim || err) {
  256. str[i] = '\0';
  257. return i;
  258. }
  259. }
  260. str[maxlen] = '\0';
  261. return maxlen;
  262. }
  263. #if BINIO_ENABLE_STRING
  264. std::string binistream::readString(const char delim) {
  265. char buf[STRINGBUFSIZE + 1];
  266. std::string tempstr;
  267. unsigned long read;
  268. do {
  269. read = readString(buf, STRINGBUFSIZE, delim);
  270. tempstr.append(buf, read);
  271. } while (read == STRINGBUFSIZE);
  272. return tempstr;
  273. }
  274. #endif
  275. binistream::Int binistream::peekInt(unsigned int size) {
  276. Int val = readInt(size);
  277. if (!err) seek(-(long)size, Add);
  278. return val;
  279. }
  280. binistream::Float binistream::peekFloat(FType ft) {
  281. Float val = readFloat(ft);
  282. if (!err)
  283. switch (ft) {
  284. case Single:
  285. seek(-4, Add);
  286. break;
  287. case Double:
  288. seek(-8, Add);
  289. break;
  290. }
  291. return val;
  292. }
  293. bool binistream::ateof() {
  294. Error olderr = err; // Save current error state
  295. bool eof_then;
  296. peekInt(1);
  297. eof_then = eof(); // Get error state of next byte
  298. err = olderr; // Restore original error state
  299. return eof_then;
  300. }
  301. void binistream::ignore(unsigned long amount) {
  302. unsigned long i;
  303. for (i = 0; i < amount; i++)
  304. getByte();
  305. }
  306. /***** binostream *****/
  307. binostream::binostream() {
  308. }
  309. binostream::~binostream() {
  310. }
  311. void binostream::writeInt(Int val, unsigned int size) {
  312. unsigned int i;
  313. // Check if 'size' doesn't exceed our system's biggest type.
  314. if (size > sizeof(Int)) {
  315. err |= Unsupported;
  316. return;
  317. }
  318. for (i = 0; i < size; i++) {
  319. if (getFlag(BigEndian))
  320. putByte((val >> (size - i - 1) * 8) & 0xff);
  321. else {
  322. putByte(val & 0xff);
  323. val >>= 8;
  324. }
  325. }
  326. }
  327. void binostream::writeFloat(Float f, FType ft) {
  328. if (getFlag(FloatIEEE)) { // Write IEEE-754 floating-point value
  329. unsigned int i, size = 0;
  330. Byte *out = NULL;
  331. bool swap;
  332. if (system_flags & FloatIEEE) {
  333. // compatible system, let the hardware do the conversion
  334. float outf = f;
  335. double outd = f;
  336. // Hardware could be big or little endian, convert appropriately
  337. swap = getFlag(BigEndian) ^ (system_flags & BigEndian);
  338. // Determine appropriate size for given type and convert by hardware
  339. switch (ft) {
  340. case Single:
  341. size = 4;
  342. out = (Byte *)&outf;
  343. break; // 32 bits
  344. case Double:
  345. size = 8;
  346. out = (Byte *)&outd;
  347. break; // 64 bits
  348. }
  349. } else {
  350. #if BINIO_WITH_MATH
  351. // incompatible system, do the conversion manually
  352. Byte buf[8];
  353. // Our own value is always big endian, just check whether we have to
  354. // convert for a different stream format.
  355. swap = !getFlag(BigEndian);
  356. // Convert system's float to requested IEEE-754 float
  357. switch (ft) {
  358. case Single:
  359. size = 4;
  360. float2ieee_single(f, buf);
  361. break;
  362. case Double:
  363. size = 8;
  364. float2ieee_double(f, buf);
  365. break;
  366. }
  367. out = buf; // Make the value ready for writing
  368. #else
  369. // No necessary support routines to do the conversion, bail out!
  370. err |= Unsupported;
  371. return;
  372. #endif
  373. }
  374. // Write the float byte by byte, converting endianess
  375. if (swap) out += size - 1;
  376. for (i = 0; i < size; i++) {
  377. putByte(*out);
  378. if (swap) out--;
  379. else out++;
  380. }
  381. return; // We're done.
  382. }
  383. // User tried to write an unsupported floating-point type. Bail out.
  384. err |= Unsupported;
  385. }
  386. #ifdef BINIO_WITH_MATH
  387. /*
  388. * Single and double floating-point to IEEE-754 equivalent conversion functions
  389. * courtesy of Ken Turkowski.
  390. *
  391. * Copyright (C) 1989-1991 Ken Turkowski. <turk@computer.org>
  392. *
  393. * All rights reserved.
  394. *
  395. * Warranty Information
  396. * Even though I have reviewed this software, I make no warranty
  397. * or representation, either express or implied, with respect to this
  398. * software, its quality, accuracy, merchantability, or fitness for a
  399. * particular purpose. As a result, this software is provided "as is,"
  400. * and you, its user, are assuming the entire risk as to its quality
  401. * and accuracy.
  402. *
  403. * This code may be used and freely distributed as long as it includes
  404. * this copyright notice and the above warranty information.
  405. */
  406. /****************************************************************
  407. * The following two routines make up for deficiencies in many
  408. * compilers to convert properly between unsigned integers and
  409. * floating-point. Some compilers which have this bug are the
  410. * THINK_C compiler for the Macintosh and the C compiler for the
  411. * Silicon Graphics MIPS-based Iris.
  412. ****************************************************************/
  413. #ifdef applec /* The Apple C compiler works */
  414. # define FloatToUnsigned(f) ((unsigned long)(f))
  415. #else
  416. # define FloatToUnsigned(f) ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
  417. #endif
  418. #define SEXP_MAX 255
  419. #define SEXP_OFFSET 127
  420. #define SEXP_SIZE 8
  421. #define SEXP_POSITION (32-SEXP_SIZE-1)
  422. void binostream::float2ieee_single(Float num, Byte *bytes) {
  423. long sign;
  424. register long bits;
  425. if (num < 0) { /* Can't distinguish a negative zero */
  426. sign = 0x80000000;
  427. num *= -1;
  428. } else {
  429. sign = 0;
  430. }
  431. if (num == 0) {
  432. bits = 0;
  433. } else {
  434. Float fMant;
  435. int expon;
  436. fMant = frexp(num, &expon);
  437. if ((expon > (SEXP_MAX-SEXP_OFFSET+1)) || !(fMant < 1)) {
  438. /* NaN's and infinities fail second test */
  439. bits = sign | 0x7F800000; /* +/- infinity */
  440. }
  441. else {
  442. long mantissa;
  443. if (expon < -(SEXP_OFFSET-2)) { /* Smaller than normalized */
  444. int shift = (SEXP_POSITION+1) + (SEXP_OFFSET-2) + expon;
  445. if (shift < 0) { /* Way too small: flush to zero */
  446. bits = sign;
  447. } else { /* Nonzero denormalized number */
  448. mantissa = (long)(fMant * (1L << shift));
  449. bits = sign | mantissa;
  450. }
  451. }
  452. else { /* Normalized number */
  453. mantissa = (long)floor(fMant * (1L << (SEXP_POSITION+1)));
  454. mantissa -= (1L << SEXP_POSITION); /* Hide MSB */
  455. bits = sign | ((long)((expon + SEXP_OFFSET - 1)) << SEXP_POSITION) | mantissa;
  456. }
  457. }
  458. }
  459. bytes[0] = bits >> 24; /* Copy to byte string */
  460. bytes[1] = bits >> 16;
  461. bytes[2] = bits >> 8;
  462. bytes[3] = bits;
  463. }
  464. #define DEXP_MAX 2047
  465. #define DEXP_OFFSET 1023
  466. #define DEXP_SIZE 11
  467. #define DEXP_POSITION (32-DEXP_SIZE-1)
  468. void binostream::float2ieee_double(Float num, Byte *bytes) {
  469. long sign;
  470. long first, second;
  471. if (num < 0) { /* Can't distinguish a negative zero */
  472. sign = 0x80000000;
  473. num *= -1;
  474. } else {
  475. sign = 0;
  476. }
  477. if (num == 0) {
  478. first = 0;
  479. second = 0;
  480. } else {
  481. Float fMant, fsMant;
  482. int expon;
  483. fMant = frexp(num, &expon);
  484. if ((expon > (DEXP_MAX-DEXP_OFFSET+1)) || !(fMant < 1)) {
  485. /* NaN's and infinities fail second test */
  486. first = sign | 0x7FF00000; /* +/- infinity */
  487. second = 0;
  488. }
  489. else {
  490. long mantissa;
  491. if (expon < -(DEXP_OFFSET-2)) { /* Smaller than normalized */
  492. int shift = (DEXP_POSITION+1) + (DEXP_OFFSET-2) + expon;
  493. if (shift < 0) { /* Too small for something in the MS word */
  494. first = sign;
  495. shift += 32;
  496. if (shift < 0) { /* Way too small: flush to zero */
  497. second = 0;
  498. } else { /* Pretty small demorn */
  499. second = FloatToUnsigned(floor(ldexp(fMant, shift)));
  500. }
  501. } else { /* Nonzero denormalized number */
  502. fsMant = ldexp(fMant, shift);
  503. mantissa = (long)floor(fsMant);
  504. first = sign | mantissa;
  505. second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
  506. }
  507. }
  508. else { /* Normalized number */
  509. fsMant = ldexp(fMant, DEXP_POSITION+1);
  510. mantissa = (long)floor(fsMant);
  511. mantissa -= (1L << DEXP_POSITION); /* Hide MSB */
  512. fsMant -= (1L << DEXP_POSITION);
  513. first = sign | ((long)((expon + DEXP_OFFSET - 1)) << DEXP_POSITION) | mantissa;
  514. second = FloatToUnsigned(floor(ldexp(fsMant - mantissa, 32)));
  515. }
  516. }
  517. }
  518. bytes[0] = first >> 24;
  519. bytes[1] = first >> 16;
  520. bytes[2] = first >> 8;
  521. bytes[3] = first;
  522. bytes[4] = second >> 24;
  523. bytes[5] = second >> 16;
  524. bytes[6] = second >> 8;
  525. bytes[7] = second;
  526. }
  527. #endif // BINIO_WITH_MATH
  528. unsigned long binostream::writeString(const char *str, unsigned long amount) {
  529. unsigned int i;
  530. if (!amount) amount = strlen(str);
  531. for (i = 0; i < amount; i++) {
  532. putByte(str[i]);
  533. if (err) return i;
  534. }
  535. return amount;
  536. }
  537. #if BINIO_ENABLE_STRING
  538. unsigned long binostream::writeString(const std::string &str) {
  539. return writeString(str.c_str());
  540. }
  541. #endif