changeset 18616:aa861a98d84d stable

fwrite: don't convert to octave_int for char output types * oct-stream.cc (convert_chars): New template function. (ultimate_element_type): New traits class and specialization. (convert_data): Handle conversion to char types differently from single byte integer types. * io.tst: New test.
author John W. Eaton <jwe@octave.org>
date Thu, 03 Apr 2014 19:50:14 -0400
parents ef7bb00d8167
children c644cfa9cb3b
files libinterp/corefcn/oct-stream.cc test/io.tst
diffstat 2 files changed, 52 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/oct-stream.cc	Tue Apr 01 15:49:23 2014 +0200
+++ b/libinterp/corefcn/oct-stream.cc	Thu Apr 03 19:50:14 2014 -0400
@@ -3379,6 +3379,18 @@
 
 template <class T, class V>
 static void
+convert_chars (const void *data, void *conv_data, octave_idx_type n_elts)
+{
+  const T *tt_data = static_cast<const T *> (data);
+
+  V *vt_data = static_cast<V *> (conv_data);
+
+  for (octave_idx_type i = 0; i < n_elts; i++)
+    vt_data[i] = tt_data[i];
+}
+
+template <class T, class V>
+static void
 convert_ints (const T *data, void *conv_data, octave_idx_type n_elts,
               bool swap)
 {
@@ -3388,6 +3400,9 @@
 
   for (octave_idx_type i = 0; i < n_elts; i++)
     {
+      // Yes, we want saturation semantics when converting to an integer
+      // type.
+
       V val (data[i]);
 
       vt_data[i] = val.value ();
@@ -3398,6 +3413,20 @@
 }
 
 template <class T>
+class ultimate_element_type
+{
+public:
+  typedef T type;
+};
+
+template <class T>
+class ultimate_element_type<octave_int<T> >
+{
+public:
+  typedef T type;
+};
+
+template <class T>
 static bool
 convert_data (const T *data, void *conv_data, octave_idx_type n_elts,
               oct_data_conv::data_type output_type,
@@ -3412,18 +3441,26 @@
 
   bool do_float_conversion =  flt_fmt != oct_mach_info::float_format ();
 
-  // We use octave_intN classes here instead of converting directly to
-  // intN_t so that we get integer saturation semantics.
+  typedef typename ultimate_element_type<T>::type ult_elt_type;
 
   switch (output_type)
     {
     case oct_data_conv::dt_char:
+      convert_chars<ult_elt_type, char> (data, conv_data, n_elts);
+      break;
+
     case oct_data_conv::dt_schar:
+      convert_chars<ult_elt_type, signed char> (data, conv_data, n_elts);
+      break;
+
+    case oct_data_conv::dt_uchar:
+      convert_chars<ult_elt_type, unsigned char> (data, conv_data, n_elts);
+      break;
+
     case oct_data_conv::dt_int8:
       convert_ints<T, octave_int8> (data, conv_data, n_elts, swap);
       break;
 
-    case oct_data_conv::dt_uchar:
     case oct_data_conv::dt_uint8:
       convert_ints<T, octave_uint8> (data, conv_data, n_elts, swap);
       break;
--- a/test/io.tst	Tue Apr 01 15:49:23 2014 +0200
+++ b/test/io.tst	Thu Apr 03 19:50:14 2014 -0400
@@ -434,6 +434,18 @@
 %! assert (__prog_output_assert__ ("ok"));
 
 %!test
+%! x = char (128:255)';
+%! nm = tmpnam ();
+%! id = fopen (nm, "wb");
+%! fwrite (id, x);
+%! fclose (id);
+%! id = fopen (nm, "rb");
+%! y = fread (id, Inf, "uchar=>char");
+%! fclose (id);
+%! unlink (nm);
+%! assert (x, y);
+
+%!test
 %! nm = tmpnam ();
 %! id = fopen (nm, "wb");
 %! if (id > 0)