GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
data-conv.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2013 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include <cctype>
28 #include <cstdlib>
29 
30 #include <iostream>
31 #include <limits>
32 #include <vector>
33 
34 #include "byte-swap.h"
35 #include "data-conv.h"
36 #include "lo-error.h"
37 #include "lo-ieee.h"
38 #include "oct-locbuf.h"
39 
40 #if defined HAVE_LONG_LONG_INT
41 #define FIND_SIZED_INT_TYPE(VAL, BITS, TQ, Q) \
42  do \
43  { \
44  int sz = BITS / std::numeric_limits<unsigned char>::digits; \
45  if (sizeof (TQ char) == sz) \
46  VAL = oct_data_conv::dt_ ## Q ## char; \
47  else if (sizeof (TQ short) == sz) \
48  VAL = oct_data_conv::dt_ ## Q ## short; \
49  else if (sizeof (TQ int) == sz) \
50  VAL = oct_data_conv::dt_ ## Q ## int; \
51  else if (sizeof (TQ long) == sz) \
52  VAL = oct_data_conv::dt_ ## Q ## long; \
53  else if (sizeof (TQ long long) == sz) \
54  VAL = oct_data_conv::dt_ ## Q ## longlong; \
55  else \
56  VAL = oct_data_conv::dt_unknown; \
57  } \
58  while (0)
59 #else
60 #define FIND_SIZED_INT_TYPE(VAL, BITS, TQ, Q) \
61  do \
62  { \
63  int sz = BITS / std::numeric_limits<unsigned char>::digits; \
64  if (sizeof (TQ char) == sz) \
65  VAL = oct_data_conv::dt_ ## Q ## char; \
66  else if (sizeof (TQ short) == sz) \
67  VAL = oct_data_conv::dt_ ## Q ## short; \
68  else if (sizeof (TQ int) == sz) \
69  VAL = oct_data_conv::dt_ ## Q ## int; \
70  else if (sizeof (TQ long) == sz) \
71  VAL = oct_data_conv::dt_ ## Q ## long; \
72  else \
73  VAL = oct_data_conv::dt_unknown; \
74  } \
75  while (0)
76 #endif
77 
78 #define FIND_SIZED_FLOAT_TYPE(VAL, BITS) \
79  do \
80  { \
81  int sz = BITS / std::numeric_limits<unsigned char>::digits; \
82  if (sizeof (float) == sz) \
83  VAL = oct_data_conv::dt_float; \
84  else if (sizeof (double) == sz) \
85  VAL = oct_data_conv::dt_double; \
86  else \
87  VAL = oct_data_conv::dt_unknown; \
88  } \
89  while (0)
90 
91 // I'm not sure it is worth the trouble, but let's use a lookup table
92 // for the types that are supposed to be a specific number of bits
93 // wide. Given the macros above, this should work as long as
94 // std::numeric_limits<unsigned char>::digits is a multiple of 8 and
95 // there are types with the right sizes.
96 //
97 // The sized data type lookup table has the following format:
98 //
99 // bits
100 // +----+----+----+----+
101 // | 8 | 16 | 32 | 64 |
102 // +----+----+----+----+
103 // signed integer | | | | |
104 // +----+----+----+----+
105 // unsigned integer | | | | |
106 // +----+----+----+----+
107 // floating point | | | | |
108 // +----+----+----+----+
109 //
110 // So, the 0,3 element is supposed to contain the oct_data_conv enum
111 // value corresponding to the correct native data type for a signed
112 // 32-bit integer.
113 
114 static void
116 {
117  int bits = 8;
118 
119  for (int i = 0; i < 4; i++)
120  {
121  FIND_SIZED_INT_TYPE (table[0][i], bits, , );
122 
123  FIND_SIZED_INT_TYPE (table[1][i], bits, unsigned, u);
124 
125  FIND_SIZED_FLOAT_TYPE (table[2][i], bits);
126 
127  bits *= 2;
128  }
129 }
130 
131 static std::string
132 strip_spaces (const std::string& str)
133 {
134  size_t n = str.length ();
135 
136  size_t k = 0;
137 
138  std::string s (n, ' ');
139 
140  for (size_t i = 0; i < n; i++)
141  if (! isspace (str[i]))
142  s[k++] = tolower (str[i]);
143 
144  s.resize (k);
145 
146  return s;
147 }
148 
149 #define GET_SIZED_INT_TYPE(T, U) \
150  do \
151  { \
152  switch (sizeof (T)) \
153  { \
154  case 1: \
155  retval = dt_ ## U ## int8; \
156  break; \
157  \
158  case 2: \
159  retval = dt_ ## U ## int16; \
160  break; \
161  \
162  case 4: \
163  retval = dt_ ## U ## int32; \
164  break; \
165  \
166  case 8: \
167  retval = dt_ ## U ## int64; \
168  break; \
169  \
170  default: \
171  retval = dt_unknown; \
172  break; \
173  } \
174  } \
175  while (0)
176 
177 size_t
179 {
180  size_t retval = -1;
181 
182  switch (dt)
183  {
185  retval = sizeof (int8_t);
186  break;
187 
189  retval = sizeof (uint8_t);
190  break;
191 
193  retval = sizeof (int16_t);
194  break;
195 
197  retval = sizeof (uint16_t);
198  break;
199 
201  retval = sizeof (int32_t);
202  break;
203 
205  retval = sizeof (uint32_t);
206  break;
207 
209  retval = sizeof (int64_t);
210  break;
211 
213  retval = sizeof (uint64_t);
214  break;
215 
218  retval = sizeof (float);
219  break;
220 
222  retval = sizeof (double);
223  break;
224 
226  retval = sizeof (char);
227  break;
228 
230  retval = sizeof (signed char);
231  break;
232 
234  retval = sizeof (unsigned char);
235  break;
236 
238  retval = sizeof (short);
239  break;
240 
242  retval = sizeof (unsigned short);
243  break;
244 
246  retval = sizeof (int);
247  break;
248 
250  retval = sizeof (unsigned int);
251  break;
252 
254  retval = sizeof (long);
255  break;
256 
258  retval = sizeof (unsigned long);
259  break;
260 
262  retval = sizeof (long long);
263  break;
264 
266  retval = sizeof (unsigned long long);
267  break;
268 
270  retval = sizeof (bool);
271  break;
272 
274  default:
275  abort ();
276  break;
277  }
278 
279  return retval;
280 }
281 
283 oct_data_conv::string_to_data_type (const std::string& str)
284 {
285  data_type retval = dt_unknown;
286 
287  static bool initialized = false;
288 
289  static data_type sized_type_table[3][4];
290 
291  if (! initialized)
292  {
293  init_sized_type_lookup_table (sized_type_table);
294 
295  initialized = true;
296  }
297 
298  std::string s = strip_spaces (str);
299 
300  if (s == "int8" || s == "integer*1")
301  retval = dt_int8;
302  else if (s == "uint8")
303  retval = dt_uint8;
304  else if (s == "int16" || s == "integer*2")
305  retval = dt_int16;
306  else if (s == "uint16")
307  retval = dt_uint16;
308  else if (s == "int32" || s == "integer*4")
309  retval = dt_int32;
310  else if (s == "uint32")
311  retval = dt_uint32;
312  else if (s == "int64" || s == "integer*8")
313  retval = dt_int64;
314  else if (s == "uint64")
315  retval = dt_uint64;
316  else if (s == "single" || s == "float32" || s == "real*4")
317  retval = dt_single;
318  else if (s == "double" || s == "float64" || s == "real*8")
319  retval = dt_double;
320  else if (s == "char" || s == "char*1")
321  retval = dt_char;
322  else if (s == "schar" || s == "signedchar")
323  retval = dt_schar;
324  else if (s == "uchar" || s == "unsignedchar")
325  retval = dt_uchar;
326  else if (s == "short")
327  GET_SIZED_INT_TYPE (short, );
328  else if (s == "ushort" || s == "unsignedshort")
329  GET_SIZED_INT_TYPE (unsigned short, u);
330  else if (s == "int")
331  GET_SIZED_INT_TYPE (int, );
332  else if (s == "uint" || s == "unsignedint")
333  GET_SIZED_INT_TYPE (unsigned int, u);
334  else if (s == "long")
335  GET_SIZED_INT_TYPE (long, );
336  else if (s == "ulong" || s == "unsignedlong")
337  GET_SIZED_INT_TYPE (unsigned long, u);
338  else if (s == "longlong")
339  GET_SIZED_INT_TYPE (long long, );
340  else if (s == "ulonglong" || s == "unsignedlonglong")
341  GET_SIZED_INT_TYPE (unsigned long long, u);
342  else if (s == "float")
343  {
344  if (sizeof (float) == sizeof (double))
345  retval = dt_double;
346  else
347  retval = dt_single;
348  }
349  else if (s == "logical")
350  retval = dt_logical;
351  else
352  (*current_liboctave_error_handler) ("invalid data type specified");
353 
354  if (retval == dt_unknown)
355  (*current_liboctave_error_handler)
356  ("unable to find matching native data type for %s", s.c_str ());
357 
358  return retval;
359 }
360 
361 void
362 oct_data_conv::string_to_data_type (const std::string& str, int& block_size,
363  oct_data_conv::data_type& input_type,
364  oct_data_conv::data_type& output_type)
365 {
366  block_size = 1;
367  input_type = dt_uchar;
368  output_type = dt_double;
369 
370  bool input_is_output = false;
371 
372  std::string s = strip_spaces (str);
373 
374  size_t pos = 0;
375 
376  if (s[0] == '*')
377  input_is_output = true;
378  else
379  {
380  size_t len = s.length ();
381 
382  while (pos < len && isdigit (s[pos]))
383  pos++;
384 
385  if (pos > 0)
386  {
387  if (s[pos] == '*')
388  {
389  block_size = atoi (s.c_str ());
390  s = s.substr (pos+1);
391  }
392  else
393  {
394  (*current_liboctave_error_handler)
395  ("invalid repeat count in '%s'", str.c_str ());
396 
397  return;
398  }
399  }
400  }
401 
402  pos = s.find ('=');
403 
404  if (pos != std::string::npos)
405  {
406  if (s[pos+1] == '>')
407  {
408  std::string s1;
409 
410  if (input_is_output)
411  {
412  input_is_output = false;
413 
414  s1 = s.substr (1, pos-1);
415 
416  (*current_liboctave_warning_handler)
417  ("warning: ignoring leading * in fread precision");
418  }
419  else
420  s1 = s.substr (0, pos);
421 
422  input_type = string_to_data_type (s1);
423  output_type = string_to_data_type (s.substr (pos+2));
424  }
425  else
427  ("fread: invalid precision specified");
428  }
429  else
430  {
431  if (input_is_output)
432  s = s.substr (1);
433 
434  input_type = string_to_data_type (s);
435 
436  if (input_is_output)
437  output_type = input_type;
438  }
439 }
440 
441 void
442 oct_data_conv::string_to_data_type (const std::string& str, int& block_size,
443  oct_data_conv::data_type& output_type)
444 {
445  block_size = 1;
446  output_type = dt_double;
447 
448  std::string s = strip_spaces (str);
449 
450  size_t pos = 0;
451 
452  size_t len = s.length ();
453 
454  while (pos < len && isdigit (s[pos]))
455  pos++;
456 
457  if (pos > 0)
458  {
459  if (s[pos] == '*')
460  {
461  block_size = atoi (s.c_str ());
462  s = s.substr (pos+1);
463  }
464  else
465  {
466  (*current_liboctave_error_handler)
467  ("invalid repeat count in '%s'", str.c_str ());
468 
469  return;
470  }
471  }
472 
473  output_type = string_to_data_type (s);
474 }
475 
476 std::string
478 {
479  std::string retval;
480 
481  switch (dt)
482  {
484  retval = "int8";
485  break;
486 
488  retval = "uint8";
489  break;
490 
492  retval = "int16";
493  break;
494 
496  retval = "uint16";
497  break;
498 
500  retval = "int32";
501  break;
502 
504  retval = "uint32";
505  break;
506 
508  retval = "int64";
509  break;
510 
512  retval = "uint64";
513  break;
514 
516  retval = "single";
517  break;
518 
520  retval = "double";
521  break;
522 
524  retval = "char";
525  break;
526 
528  retval = "signed char";
529  break;
530 
532  retval = "unsigned char";
533  break;
534 
536  retval = "short";
537  break;
538 
540  retval = "unsigned short";
541  break;
542 
544  retval = "int";
545  break;
546 
548  retval = "unsigned int";
549  break;
550 
552  retval = "long";
553  break;
554 
556  retval = "unsigned long";
557  break;
558 
560  retval = "long long";
561  break;
562 
564  retval = "unsigned long long";
565  break;
566 
568  retval = "float";
569  break;
570 
572  retval = "logical";
573  break;
574 
576  default:
577  retval = "unknown";
578  break;
579  }
580 
581  return retval;
582 }
583 
584 #define LS_DO_READ(TYPE, swap, data, size, len, stream) \
585  do \
586  { \
587  if (len > 0) \
588  { \
589  OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \
590  std::streamsize n_bytes = size * len; \
591  stream.read (reinterpret_cast<char *> (ptr), n_bytes); \
592  if (swap) \
593  swap_bytes< size > (ptr, len); \
594  for (octave_idx_type i = 0; i < len; i++) \
595  data[i] = ptr[i]; \
596  } \
597  } \
598  while (0)
599 
600 // Have to use copy here to avoid writing over data accessed via
601 // Matrix::data ().
602 
603 #define LS_DO_WRITE(TYPE, data, size, len, stream) \
604  do \
605  { \
606  if (len > 0) \
607  { \
608  char tmp_type = type; \
609  stream.write (&tmp_type, 1); \
610  OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \
611  for (octave_idx_type i = 0; i < len; i++) \
612  ptr[i] = static_cast <TYPE> (data[i]); \
613  std::streamsize n_bytes = size * len; \
614  stream.write (reinterpret_cast<char *> (ptr), n_bytes); \
615  } \
616  } \
617  while (0)
618 
619 // Loading variables from files.
620 
621 static void
623 {
624  (*current_liboctave_error_handler)
625  ("unrecognized floating point format requested");
626 }
627 
628 // But first, some data conversion routines.
629 
630 // Currently, we only handle conversions for the IEEE types. To fix
631 // that, make more of the following routines work.
632 
633 // FIXME: assumes sizeof (Complex) == 8
634 // FIXME: assumes sizeof (double) == 8
635 // FIXME: assumes sizeof (float) == 4
636 
637 static void
639 {
640  swap_bytes<8> (d, len);
641 }
642 
643 static void
645 {
646  swap_bytes<4> (d, len);
647 }
648 
649 static void
651 {
652  swap_bytes<8> (d, len);
653 }
654 
655 static void
657 {
658  swap_bytes<4> (d, len);
659 }
660 
661 void
665 {
666  switch (to_fmt)
667  {
669  switch (from_fmt)
670  {
672  break;
673 
676  break;
677 
678  default:
680  break;
681  }
682  break;
683 
685  switch (from_fmt)
686  {
689  break;
690 
692  break;
693 
694  default:
696  break;
697  }
698  break;
699 
700  default:
701  (*current_liboctave_error_handler)
702  ("impossible state reached in file '%s' at line %d",
703  __FILE__, __LINE__);
704  break;
705  }
706 }
707 
708 void
712 {
713  switch (to_fmt)
714  {
716  switch (from_fmt)
717  {
719  break;
720 
723  break;
724 
725  default:
727  break;
728  }
729  break;
730 
732  switch (from_fmt)
733  {
736  break;
737 
739  break;
740 
741  default:
743  break;
744  }
745  break;
746 
747  default:
748  (*current_liboctave_error_handler)
749  ("impossible state reached in file '%s' at line %d",
750  __FILE__, __LINE__);
751  break;
752  }
753 }
754 
755 void
756 do_float_format_conversion (void *data, size_t sz, octave_idx_type len,
759 {
760  switch (sz)
761  {
762  case sizeof (float):
763  do_float_format_conversion (data, len, from_fmt, to_fmt);
764  break;
765 
766  case sizeof (double):
767  do_double_format_conversion (data, len, from_fmt, to_fmt);
768  break;
769 
770  default:
771  (*current_liboctave_error_handler)
772  ("impossible state reached in file '%s' at line %d",
773  __FILE__, __LINE__);
774  break;
775  }
776 }
777 
778 void
779 read_doubles (std::istream& is, double *data, save_type type,
780  octave_idx_type len, bool swap,
782 {
783  switch (type)
784  {
785  case LS_U_CHAR:
786  LS_DO_READ (uint8_t, swap, data, 1, len, is);
787  break;
788 
789  case LS_U_SHORT:
790  LS_DO_READ (uint16_t, swap, data, 2, len, is);
791  break;
792 
793  case LS_U_INT:
794  LS_DO_READ (uint32_t, swap, data, 4, len, is);
795  break;
796 
797  case LS_CHAR:
798  LS_DO_READ (int8_t, swap, data, 1, len, is);
799  break;
800 
801  case LS_SHORT:
802  LS_DO_READ (int16_t, swap, data, 2, len, is);
803  break;
804 
805  case LS_INT:
806  LS_DO_READ (int32_t, swap, data, 4, len, is);
807  break;
808 
809  case LS_FLOAT:
810  {
811  OCTAVE_LOCAL_BUFFER (float, ptr, len);
812  std::streamsize n_bytes = 4 * len;
813  is.read (reinterpret_cast<char *> (ptr), n_bytes);
814  do_float_format_conversion (ptr, len, fmt);
815  for (octave_idx_type i = 0; i < len; i++)
816  data[i] = ptr[i];
817  }
818  break;
819 
820  case LS_DOUBLE: // No conversion necessary.
821  {
822  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
823  is.read (reinterpret_cast<char *> (data), n_bytes);
824  do_double_format_conversion (data, len, fmt);
825 
826  for (int i = 0; i < len; i++)
827  data[i] = __lo_ieee_replace_old_NA (data[i]);
828  }
829  break;
830 
831  default:
832  is.clear (std::ios::failbit|is.rdstate ());
833  break;
834  }
835 }
836 
837 void
838 read_floats (std::istream& is, float *data, save_type type,
839  octave_idx_type len, bool swap,
841 {
842  switch (type)
843  {
844  case LS_U_CHAR:
845  LS_DO_READ (uint8_t, swap, data, 1, len, is);
846  break;
847 
848  case LS_U_SHORT:
849  LS_DO_READ (uint16_t, swap, data, 2, len, is);
850  break;
851 
852  case LS_U_INT:
853  LS_DO_READ (uint32_t, swap, data, 4, len, is);
854  break;
855 
856  case LS_CHAR:
857  LS_DO_READ (int8_t, swap, data, 1, len, is);
858  break;
859 
860  case LS_SHORT:
861  LS_DO_READ (int16_t, swap, data, 2, len, is);
862  break;
863 
864  case LS_INT:
865  LS_DO_READ (int32_t, swap, data, 4, len, is);
866  break;
867 
868  case LS_FLOAT: // No conversion necessary.
869  {
870  std::streamsize n_bytes = 4 * len;
871  is.read (reinterpret_cast<char *> (data), n_bytes);
872  do_float_format_conversion (data, len, fmt);
873  }
874  break;
875 
876  case LS_DOUBLE:
877  {
878  OCTAVE_LOCAL_BUFFER (double, ptr, len);
879  std::streamsize n_bytes = 8 * len;
880  is.read (reinterpret_cast<char *> (ptr), n_bytes);
881  do_double_format_conversion (ptr, len, fmt);
882  for (octave_idx_type i = 0; i < len; i++)
883  data[i] = ptr[i];
884  }
885  break;
886 
887  default:
888  is.clear (std::ios::failbit|is.rdstate ());
889  break;
890  }
891 }
892 
893 void
894 write_doubles (std::ostream& os, const double *data, save_type type,
895  octave_idx_type len)
896 {
897  switch (type)
898  {
899  case LS_U_CHAR:
900  LS_DO_WRITE (uint8_t, data, 1, len, os);
901  break;
902 
903  case LS_U_SHORT:
904  LS_DO_WRITE (uint16_t, data, 2, len, os);
905  break;
906 
907  case LS_U_INT:
908  LS_DO_WRITE (uint32_t, data, 4, len, os);
909  break;
910 
911  case LS_CHAR:
912  LS_DO_WRITE (int8_t, data, 1, len, os);
913  break;
914 
915  case LS_SHORT:
916  LS_DO_WRITE (int16_t, data, 2, len, os);
917  break;
918 
919  case LS_INT:
920  LS_DO_WRITE (int32_t, data, 4, len, os);
921  break;
922 
923  case LS_FLOAT:
924  LS_DO_WRITE (float, data, 4, len, os);
925  break;
926 
927  case LS_DOUBLE: // No conversion necessary.
928  {
929  char tmp_type = static_cast<char> (type);
930  os.write (&tmp_type, 1);
931  std::streamsize n_bytes = 8 * static_cast<std::streamsize> (len);
932  os.write (reinterpret_cast <const char *> (data), n_bytes);
933  }
934  break;
935 
936  default:
937  (*current_liboctave_error_handler)
938  ("unrecognized data format requested");
939  break;
940  }
941 }
942 
943 void
944 write_floats (std::ostream& os, const float *data, save_type type,
945  octave_idx_type len)
946 {
947  switch (type)
948  {
949  case LS_U_CHAR:
950  LS_DO_WRITE (uint8_t, data, 1, len, os);
951  break;
952 
953  case LS_U_SHORT:
954  LS_DO_WRITE (uint16_t, data, 2, len, os);
955  break;
956 
957  case LS_U_INT:
958  LS_DO_WRITE (uint32_t, data, 4, len, os);
959  break;
960 
961  case LS_CHAR:
962  LS_DO_WRITE (int8_t, data, 1, len, os);
963  break;
964 
965  case LS_SHORT:
966  LS_DO_WRITE (int16_t, data, 2, len, os);
967  break;
968 
969  case LS_INT:
970  LS_DO_WRITE (int32_t, data, 4, len, os);
971  break;
972 
973  case LS_FLOAT: // No conversion necessary.
974  {
975  char tmp_type = static_cast<char> (type);
976  os.write (&tmp_type, 1);
977  std::streamsize n_bytes = 4 * len;
978  os.write (reinterpret_cast <const char *> (data), n_bytes);
979  }
980  break;
981 
982  case LS_DOUBLE:
983  LS_DO_WRITE (double, data, 8, len, os);
984  break;
985 
986  default:
987  (*current_liboctave_error_handler)
988  ("unrecognized data format requested");
989  break;
990  }
991 }