ls-oct-binary.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 1996-2012 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #include <cfloat>
00028 #include <cstring>
00029 #include <cctype>
00030 
00031 #include <fstream>
00032 #include <iomanip>
00033 #include <iostream>
00034 #include <string>
00035 #include <vector>
00036 
00037 #include "byte-swap.h"
00038 #include "data-conv.h"
00039 #include "file-ops.h"
00040 #include "glob-match.h"
00041 #include "lo-mappers.h"
00042 #include "mach-info.h"
00043 #include "oct-env.h"
00044 #include "oct-time.h"
00045 #include "quit.h"
00046 #include "str-vec.h"
00047 #include "oct-locbuf.h"
00048 
00049 #include "Cell.h"
00050 #include "defun.h"
00051 #include "error.h"
00052 #include "gripes.h"
00053 #include "load-save.h"
00054 #include "oct-obj.h"
00055 #include "oct-map.h"
00056 #include "ov-cell.h"
00057 #include "pager.h"
00058 #include "pt-exp.h"
00059 #include "sysdep.h"
00060 #include "unwind-prot.h"
00061 #include "utils.h"
00062 #include "variables.h"
00063 #include "version.h"
00064 #include "dMatrix.h"
00065 
00066 #include "ls-utils.h"
00067 #include "ls-oct-binary.h"
00068 
00069 // Extract one value (scalar, matrix, string, etc.) from stream IS and
00070 // place it in TC, returning the name of the variable.  If the value
00071 // is tagged as global in the file, return TRUE in GLOBAL.  If SWAP
00072 // is TRUE, swap bytes after reading.
00073 //
00074 // The data is expected to be in the following format:
00075 //
00076 // Header (one per file):
00077 // =====================
00078 //
00079 //   object               type            bytes
00080 //   ------               ----            -----
00081 //   magic number         string             10
00082 //
00083 //   float format         integer             1
00084 //
00085 //
00086 // Data (one set for each item):
00087 // ============================
00088 //
00089 //   object               type            bytes
00090 //   ------               ----            -----
00091 //   name_length          integer             4
00092 //
00093 //   name                 string    name_length
00094 //
00095 //   doc_length           integer             4
00096 //
00097 //   doc                  string     doc_length
00098 //
00099 //   global flag          integer             1
00100 //
00101 //   data type            char                1
00102 //
00103 // In general "data type" is 255, and in that case the next arguments
00104 // in the data set are
00105 //
00106 //   object               type            bytes
00107 //   ------               ----            -----
00108 //   type_length          integer             4
00109 //
00110 //   type                 string    type_length
00111 //
00112 // The string "type" is then used with octave_value_typeinfo::lookup_type
00113 // to create an octave_value of the correct type. The specific load/save
00114 // function is then called.
00115 //
00116 // For backward compatiablity "data type" can also be a value between 1
00117 // and 7, where this defines a hardcoded octave_value of the type
00118 //
00119 //   data type                  octave_value
00120 //   ---------                  ------------
00121 //   1                          scalar
00122 //   2                          matrix
00123 //   3                          complex scalar
00124 //   4                          complex matrix
00125 //   5                          string   (old style storage)
00126 //   6                          range
00127 //   7                          string
00128 //
00129 // Except for "data type" equal 5 that requires special treatment, these
00130 // old style "data type" value also cause the specific load/save functions
00131 // to be called. FILENAME is used for error messages.
00132 
00133 std::string
00134 read_binary_data (std::istream& is, bool swap,
00135                   oct_mach_info::float_format fmt,
00136                   const std::string& filename, bool& global,
00137                   octave_value& tc, std::string& doc)
00138 {
00139   std::string retval;
00140 
00141   unsigned char tmp = 0;
00142 
00143   int32_t name_len = 0;
00144   int32_t doc_len = 0;
00145 
00146   doc.resize (0);
00147 
00148   // We expect to fail here, at the beginning of a record, so not
00149   // being able to read another name should not result in an error.
00150 
00151   is.read (reinterpret_cast<char *> (&name_len), 4);
00152   if (! is)
00153     return retval;
00154   if (swap)
00155     swap_bytes<4> (&name_len);
00156 
00157   {
00158     OCTAVE_LOCAL_BUFFER (char, name, name_len+1);
00159     name[name_len] = '\0';
00160     if (! is.read (reinterpret_cast<char *> (name), name_len))
00161       goto data_read_error;
00162     retval = name;
00163   }
00164 
00165   is.read (reinterpret_cast<char *> (&doc_len), 4);
00166   if (! is)
00167     goto data_read_error;
00168   if (swap)
00169     swap_bytes<4> (&doc_len);
00170 
00171   {
00172     OCTAVE_LOCAL_BUFFER (char, tdoc, doc_len+1);
00173     tdoc[doc_len] = '\0';
00174     if (! is.read (reinterpret_cast<char *> (tdoc), doc_len))
00175       goto data_read_error;
00176     doc = tdoc;
00177   }
00178 
00179   if (! is.read (reinterpret_cast<char *> (&tmp), 1))
00180     goto data_read_error;
00181   global = tmp ? 1 : 0;
00182 
00183   tmp = 0;
00184   if (! is.read (reinterpret_cast<char *> (&tmp), 1))
00185     goto data_read_error;
00186 
00187   // All cases except 255 kept for backwards compatibility
00188   switch (tmp)
00189     {
00190     case 1:
00191       tc = octave_value_typeinfo::lookup_type ("scalar");
00192       break;
00193 
00194     case 2:
00195       tc = octave_value_typeinfo::lookup_type ("matrix");
00196       break;
00197 
00198     case 3:
00199       tc = octave_value_typeinfo::lookup_type ("complex scalar");
00200       break;
00201 
00202     case 4:
00203       tc = octave_value_typeinfo::lookup_type ("complex matrix");
00204       break;
00205 
00206     case 5:
00207       {
00208         // FIXMEX
00209         // This is cruft, since its for a save type that is old. Maybe
00210         // this is taking backward compatability too far!!
00211         int32_t len;
00212         if (! is.read (reinterpret_cast<char *> (&len), 4))
00213           goto data_read_error;
00214         if (swap)
00215           swap_bytes<4> (&len);
00216         OCTAVE_LOCAL_BUFFER (char, s, len+1);
00217         if (! is.read (reinterpret_cast<char *> (s), len))
00218           goto data_read_error;
00219         s[len] = '\0';
00220         tc = s;
00221 
00222         // Early return, since don't want rest of this function
00223         return retval;
00224       }
00225       break;
00226 
00227     case 6:
00228       tc = octave_value_typeinfo::lookup_type ("range");
00229       break;
00230 
00231     case 7:
00232       tc = octave_value_typeinfo::lookup_type ("string");
00233       break;
00234 
00235     case 255:
00236       {
00237         // Read the saved variable type
00238         int32_t len;
00239         if (! is.read (reinterpret_cast<char *> (&len), 4))
00240           goto data_read_error;
00241         if (swap)
00242           swap_bytes<4> (&len);
00243         OCTAVE_LOCAL_BUFFER (char, s, len+1);
00244         if (! is.read (s, len))
00245           goto data_read_error;
00246         s[len] = '\0';
00247         std::string typ = s;
00248         tc = octave_value_typeinfo::lookup_type (typ);
00249       }
00250       break;
00251     default:
00252       goto data_read_error;
00253       break;
00254     }
00255 
00256   if (!tc.load_binary (is, swap, fmt))
00257     {
00258     data_read_error:
00259       error ("load: trouble reading binary file '%s'", filename.c_str ());
00260     }
00261 
00262   return retval;
00263 }
00264 
00265 // Save the data from TC along with the corresponding NAME, help
00266 // string DOC, and global flag MARK_AS_GLOBAL on stream OS in the
00267 // binary format described above for read_binary_data.
00268 
00269 bool
00270 save_binary_data (std::ostream& os, const octave_value& tc,
00271                   const std::string& name, const std::string& doc,
00272                   bool mark_as_global, bool save_as_floats)
00273 {
00274   int32_t name_len = name.length ();
00275 
00276   os.write (reinterpret_cast<char *> (&name_len), 4);
00277   os << name;
00278 
00279   int32_t doc_len = doc.length ();
00280 
00281   os.write (reinterpret_cast<char *> (&doc_len), 4);
00282   os << doc;
00283 
00284   unsigned char tmp;
00285 
00286   tmp = mark_as_global;
00287   os.write (reinterpret_cast<char *> (&tmp), 1);
00288 
00289   // 255 flags the new binary format
00290   tmp = 255;
00291   os.write (reinterpret_cast<char *> (&tmp), 1);
00292 
00293   // Write the string corresponding to the octave_value type
00294   std::string typ = tc.type_name ();
00295   int32_t len = typ.length ();
00296   os.write (reinterpret_cast<char *> (&len), 4);
00297   const char *btmp = typ.data ();
00298   os.write (btmp, len);
00299 
00300   // The octave_value of tc is const. Make a copy...
00301   octave_value val = tc;
00302 
00303   // Call specific save function
00304   bool success = val.save_binary (os, save_as_floats);
00305 
00306   return (os && success);
00307 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines