diskio_meat.hpp

Go to the documentation of this file.
00001 // Copyright (C) 2009 NICTA
00002 // 
00003 // Authors:
00004 // - Conrad Sanderson (conradsand at ieee dot org)
00005 // 
00006 // This file is part of the Armadillo C++ library.
00007 // It is provided without any warranty of fitness
00008 // for any purpose. You can redistribute this file
00009 // and/or modify it under the terms of the GNU
00010 // Lesser General Public License (LGPL) as published
00011 // by the Free Software Foundation, either version 3
00012 // of the License or (at your option) any later version.
00013 // (see http://www.opensource.org/licenses for more info)
00014 
00015 
00016 //! \addtogroup diskio
00017 //! @{
00018 
00019 
00020 //! Generate the first line of the header used for saving matrices in text format.
00021 //! Format: "ARMA_MAT_TXT_ABXYZ".
00022 //! A is one of: I (for integral types) or F (for floating point types).
00023 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
00024 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
00025 template<typename eT>
00026 inline
00027 std::string
00028 diskio::gen_txt_header(const Mat<eT>& x)
00029   {
00030   arma_type_check<diskio::is_supported_type<eT>::value == false>::apply();
00031 
00032   if(is_u8<eT>::value == true)
00033     {
00034     return std::string("ARMA_MAT_TXT_IU001");
00035     }
00036   else
00037   if(is_s8<eT>::value == true)
00038     {
00039     return std::string("ARMA_MAT_TXT_IS001");
00040     }
00041   else
00042   if(is_u16<eT>::value == true)
00043     {
00044     return std::string("ARMA_MAT_TXT_IU002");
00045     }
00046   else
00047   if(is_s16<eT>::value == true)
00048     {
00049     return std::string("ARMA_MAT_TXT_IS002");
00050     }
00051   else
00052   if(is_u32<eT>::value == true)
00053     {
00054     return std::string("ARMA_MAT_TXT_IU004");
00055     }
00056   else
00057   if(is_s32<eT>::value == true)
00058     {
00059     return std::string("ARMA_MAT_TXT_IS004");
00060     }
00061   else
00062   if(is_float<eT>::value == true)
00063     {
00064     return std::string("ARMA_MAT_TXT_FN004");
00065     }
00066   else
00067   if(is_double<eT>::value == true)
00068     {
00069     return std::string("ARMA_MAT_TXT_FN008");
00070     }
00071   else
00072   if(is_complex_float<eT>::value == true)
00073     {
00074     return std::string("ARMA_MAT_TXT_FC008");
00075     }
00076   else
00077   if(is_complex_double<eT>::value == true)
00078     {
00079     return std::string("ARMA_MAT_TXT_FC016");
00080     }
00081   else
00082     {
00083     return std::string();
00084     }
00085   
00086   }
00087 
00088 
00089 
00090 //! Generate the first line of the header used for saving matrices in binary format.
00091 //! Format: "ARMA_MAT_BIN_ABXYZ".
00092 //! A is one of: I (for integral types) or F (for floating point types).
00093 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
00094 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
00095 template<typename eT>
00096 inline
00097 std::string
00098 diskio::gen_bin_header(const Mat<eT>& x)
00099   {
00100   arma_type_check<diskio::is_supported_type<eT>::value == false>::apply();
00101   
00102   if(is_u8<eT>::value == true)
00103     {
00104     return std::string("ARMA_MAT_BIN_IU001");
00105     }
00106   else
00107   if(is_s8<eT>::value == true)
00108     {
00109     return std::string("ARMA_MAT_BIN_IS001");
00110     }
00111   else
00112   if(is_u16<eT>::value == true)
00113     {
00114     return std::string("ARMA_MAT_BIN_IU002");
00115     }
00116   else
00117   if(is_s16<eT>::value == true)
00118     {
00119     return std::string("ARMA_MAT_BIN_IS002");
00120     }
00121   else
00122   if(is_u32<eT>::value == true)
00123     {
00124     return std::string("ARMA_MAT_BIN_IU004");
00125     }
00126   else
00127   if(is_s32<eT>::value == true)
00128     {
00129     return std::string("ARMA_MAT_BIN_IS004");
00130     }
00131   else
00132   if(is_float<eT>::value == true)
00133     {
00134     return std::string("ARMA_MAT_BIN_FN004");
00135     }
00136   else
00137   if(is_double<eT>::value == true)
00138     {
00139     return std::string("ARMA_MAT_BIN_FN008");
00140     }
00141   else
00142   if(is_complex_float<eT>::value == true)
00143     {
00144     return std::string("ARMA_MAT_BIN_FC008");
00145     }
00146   else
00147   if(is_complex_double<eT>::value == true)
00148     {
00149     return std::string("ARMA_MAT_BIN_FC016");
00150     }
00151   else
00152     {
00153     return std::string();
00154     }
00155   
00156   }
00157 
00158 
00159 
00160 inline
00161 char
00162 diskio::conv_to_hex_char(const u8 x)
00163   {
00164   char out;
00165   switch(x)
00166     {
00167     case  0: out = '0'; break;
00168     case  1: out = '1'; break;
00169     case  2: out = '2'; break;
00170     case  3: out = '3'; break;
00171     case  4: out = '4'; break;
00172     case  5: out = '5'; break;
00173     case  6: out = '6'; break;
00174     case  7: out = '7'; break;
00175     case  8: out = '8'; break;
00176     case  9: out = '9'; break;
00177     case 10: out = 'a'; break;
00178     case 11: out = 'b'; break;
00179     case 12: out = 'c'; break;
00180     case 13: out = 'd'; break;
00181     case 14: out = 'e'; break;
00182     case 15: out = 'f'; break;
00183     default: out = '-'; break;
00184     }
00185 
00186   return out;  
00187   }
00188 
00189 
00190 
00191 inline
00192 void
00193 diskio::conv_to_hex(char* out, const u8 x)
00194   {
00195   const u8 a = x / 16;
00196   const u8 b = x - 16*a;
00197 
00198   out[0] = conv_to_hex_char(a);
00199   out[1] = conv_to_hex_char(b);
00200   }
00201 
00202 
00203 
00204 //! Append a quasi-random string to the given filename.
00205 //! The rand() function is deliberately not used,
00206 //! as rand() has an internal state that changes
00207 //! from call to call. Such states should not be
00208 //! modified in scientific applications, where the
00209 //! results should be reproducable and not affected 
00210 //! by saving data.
00211 inline
00212 std::string
00213 diskio::gen_tmp_name(const std::string& x)
00214   {
00215   const std::string* ptr_x     = &x;
00216   const u8*          ptr_ptr_x = reinterpret_cast<const u8*>(&ptr_x);
00217   
00218   const char* extra      = ".tmp_";
00219   const u32   extra_size = 5;
00220   
00221   const u32   tmp_size   = 2*sizeof(u8*) + 2*2;
00222         char  tmp[tmp_size];
00223   
00224   u32 char_count = 0;
00225   
00226   for(u32 i=0; i<sizeof(u8*); ++i)
00227     {
00228     conv_to_hex(&tmp[char_count], ptr_ptr_x[i]);
00229     char_count += 2;
00230     }
00231   
00232   const u32 x_size = x.size();
00233   u8 sum = 0;
00234   
00235   for(u32 i=0; i<x_size; ++i)
00236     {
00237     sum += u8(x[i]);
00238     }
00239   
00240   conv_to_hex(&tmp[char_count], sum);
00241   char_count += 2;
00242   
00243   conv_to_hex(&tmp[char_count], u8(x_size));
00244   
00245   
00246   std::string out;
00247   out.resize(x_size + extra_size + tmp_size);
00248   
00249   
00250   for(u32 i=0; i<x_size; ++i)
00251     {
00252     out[i] = x[i];
00253     }
00254   
00255   for(u32 i=0; i<extra_size; ++i)
00256     {
00257     out[x_size + i] = extra[i];
00258     }
00259   
00260   for(u32 i=0; i<tmp_size; ++i)
00261     {
00262     out[x_size + extra_size + i] = tmp[i];
00263     }
00264   
00265   return out;
00266   }
00267 
00268 
00269 
00270 //! Safely rename a file.
00271 //! Before renaming, test if we can write to the final file.
00272 //! This should prevent:
00273 //! (i)  overwriting files that have been write protected,
00274 //! (ii) overwriting directories.
00275 inline
00276 void
00277 diskio::safe_rename(const std::string& old_name, const std::string& new_name)
00278   {
00279   std::fstream f(new_name.c_str(), std::fstream::out | std::fstream::app);
00280   f.put(' ');
00281   
00282   const bool writing_problem = (f.good() == false);
00283   f.close();
00284   
00285   arma_warn( writing_problem, "trouble writing ", new_name );
00286   
00287   if(writing_problem == false)
00288     {
00289     std::remove(new_name.c_str());
00290     
00291     const int mv_result = std::rename(old_name.c_str(), new_name.c_str());
00292     arma_warn( (mv_result != 0), "trouble writing ", new_name );
00293     }
00294   
00295   }
00296 
00297 
00298 
00299 //! Save a matrix as raw text (no header, human readable).
00300 //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
00301 template<typename eT>
00302 inline
00303 void
00304 diskio::save_raw_ascii(const Mat<eT>& x, const std::string& final_name)
00305   {
00306   arma_extra_debug_sigprint();
00307   
00308   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00309   
00310   std::fstream f(tmp_name.c_str(), std::fstream::out);
00311   
00312   if(f.is_open() == false)
00313     {
00314     arma_print("unable to write ", tmp_name);
00315     }
00316   else
00317     {
00318     u32 cell_width;
00319     
00320     // TODO: need sane values for complex numbers
00321     
00322     if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00323       {
00324       f.setf(ios::scientific);
00325       f.precision(8);
00326       cell_width = 16;
00327       }
00328     
00329     for(u32 row=0; row < x.n_rows; ++row)
00330       {
00331       for(u32 col=0; col < x.n_cols; ++col)
00332         {
00333         f.put(' ');
00334         
00335         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00336           {
00337           f.width(cell_width);
00338           }
00339         
00340         f << x.at(row,col);
00341         }
00342         
00343       f.put('\n');
00344       }
00345     
00346     const bool writing_problem = (f.good() == false);
00347     
00348     arma_warn(writing_problem, "trouble writing ", tmp_name );
00349     
00350     f.flush();
00351     f.close();
00352     
00353     if(writing_problem == false)
00354       {
00355       diskio::safe_rename(tmp_name, final_name);
00356       }
00357     }
00358   
00359   }
00360 
00361 
00362 
00363 //! Save a matrix in text format (human readable),
00364 //! with a header that indicates the matrix type as well as its dimensions
00365 template<typename eT>
00366 inline
00367 void
00368 diskio::save_arma_ascii(const Mat<eT>& x, const std::string& final_name)
00369   {
00370   arma_extra_debug_sigprint();
00371   
00372   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00373   
00374   std::ofstream f(tmp_name.c_str());
00375   
00376   diskio::save_arma_ascii(x, tmp_name, f);
00377   
00378   const bool writing_problem = (f.good() == false);
00379   
00380   f.flush();
00381   f.close();
00382   
00383   arma_warn( writing_problem, "trouble writing ", tmp_name );
00384   
00385   if(writing_problem == false)
00386     {
00387     diskio::safe_rename(tmp_name, final_name);
00388     }
00389   }
00390 
00391 
00392 
00393 //! Save a matrix in text format (human readable),
00394 //! with a header that indicates the matrix type as well as its dimensions
00395 template<typename eT>
00396 inline
00397 void 
00398 diskio::save_arma_ascii(const Mat<eT>& x, const std::string& name, std::ofstream& f)
00399   {
00400   arma_extra_debug_sigprint();
00401   
00402   if(f.is_open() == false)
00403     {
00404     arma_debug_print("unable to write ", name);
00405     }
00406   else
00407     {
00408     const ios::fmtflags orig_flags = f.flags();
00409     
00410     f << diskio::gen_txt_header(x) << '\n';
00411     f << x.n_rows << ' ' << x.n_cols << '\n';
00412     
00413     u32 cell_width;
00414     
00415     // TODO: need sane values for complex numbers
00416     
00417     if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00418       {
00419       f.setf(ios::scientific);
00420       f.precision(8);
00421       cell_width = 16;
00422       }
00423       
00424     for(u32 row=0; row < x.n_rows; ++row)
00425       {
00426       for(u32 col=0; col < x.n_cols; ++col)
00427         {
00428         f.put(' ');
00429         
00430         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )        
00431           {
00432           f.width(cell_width);
00433           }
00434         
00435         f << x.at(row,col);
00436         }
00437       
00438       f.put('\n');
00439       }
00440     
00441     f.flags(orig_flags);
00442     }
00443   }
00444 
00445 
00446 
00447 //! Save a matrix in binary format,
00448 //! with a header that stores the matrix type as well as its dimensions
00449 template<typename eT>
00450 inline
00451 void
00452 diskio::save_arma_binary(const Mat<eT>& x, const std::string& final_name)
00453   {
00454   arma_extra_debug_sigprint();
00455   
00456   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00457   
00458   std::ofstream f(tmp_name.c_str(), std::fstream::binary);
00459   
00460   diskio::save_arma_binary(x, tmp_name, f);
00461   
00462   const bool writing_problem = (f.good() == false);
00463   
00464   f.flush();
00465   f.close();
00466   
00467   arma_warn( writing_problem, "trouble writing ", tmp_name );
00468   
00469   if(writing_problem == false)
00470     {
00471     diskio::safe_rename(tmp_name, final_name);
00472     }
00473   }
00474 
00475 
00476 
00477 //! Save a matrix in binary format,
00478 //! with a header that stores the matrix type as well as its dimensions
00479 template<typename eT>
00480 inline
00481 void
00482 diskio::save_arma_binary(const Mat<eT>& x, const std::string& name, std::ofstream& f)
00483   {
00484   arma_extra_debug_sigprint();
00485   
00486   if(f.is_open() == false)
00487     {
00488     arma_print("unable to write ", name);
00489     }
00490   else
00491     {
00492     f << diskio::gen_bin_header(x) << '\n';
00493     f << x.n_rows << ' ' << x.n_cols << '\n';
00494     
00495     f.write(reinterpret_cast<const char*>(x.mem), x.n_elem*sizeof(eT));
00496     }
00497   
00498   }
00499 
00500 
00501 //
00502 // TODO:
00503 // add functionality to save the image in a normalised format,
00504 // i.e. scaled so that every value falls in the [0,255] range.
00505 
00506 //! Save a matrix as a PGM greyscale image
00507 template<typename eT>
00508 inline
00509 void
00510 diskio::save_pgm_binary(const Mat<eT>& x, const std::string& final_name)
00511   {
00512   arma_extra_debug_sigprint();
00513   
00514   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00515   
00516   std::fstream f(tmp_name.c_str(), std::fstream::out | std::fstream::binary);
00517   
00518   if(f.is_open() == false)
00519     {
00520     arma_print("unable to write ", tmp_name);
00521     }
00522   else
00523     {
00524     f << "P5" << '\n';
00525     f << x.n_cols << ' ' << x.n_rows << '\n';
00526     f << 255 << '\n';
00527     
00528     const u32 n_elem = x.n_rows * x.n_cols;
00529     podarray<u8> tmp(n_elem);
00530     
00531     u32 i = 0;
00532     
00533     for(u32 row=0; row < x.n_rows; ++row)
00534       {
00535       for(u32 col=0; col < x.n_cols; ++col)
00536         {
00537         tmp[i] = u8( x(row,col) );  // TODO: add round() ?
00538         ++i;
00539         }
00540       }
00541     
00542     f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
00543     
00544     const bool writing_problem = (f.good() == false);
00545     
00546     arma_warn(writing_problem, "trouble writing ", tmp_name );
00547     
00548     f.flush();
00549     f.close();
00550     
00551     if(writing_problem == false)
00552       {
00553       diskio::safe_rename(tmp_name, final_name);
00554       }
00555     }
00556   
00557   }
00558 
00559 
00560 
00561 //! Save a matrix as a PGM greyscale image
00562 template<typename T>
00563 inline
00564 void
00565 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, const std::string& name)
00566   {
00567   arma_extra_debug_sigprint();
00568   
00569   const uchar_mat tmp = conv_to<uchar_mat>::from(x);
00570   diskio::save_pgm_binary(tmp,name);
00571   }
00572 
00573 
00574 
00575 //! Load a matrix as raw text (no header, human readable).
00576 //! Can read matrices saved as text in Matlab and Octave.
00577 //! NOTE: this is much slower than reading a file with a header.
00578 template<typename eT>
00579 inline
00580 void
00581 diskio::load_raw_ascii(Mat<eT>& x, const std::string& name)
00582   {
00583   arma_extra_debug_sigprint();
00584 
00585   std::fstream f;
00586   f.open(name.c_str(), std::fstream::in);
00587   
00588   bool load_okay = true;
00589   
00590   if(f.is_open() == false)
00591     {
00592     load_okay = false;
00593     arma_extra_debug_print("unable to read ", name);
00594     }
00595   else
00596     {
00597     //std::fstream::pos_type start = f.tellg();
00598     
00599     //
00600     // work out the size
00601     
00602     
00603     u32 f_n_rows = 0;
00604     u32 f_n_cols = 0;
00605     
00606     bool f_n_cols_found = false;
00607     
00608     std::string line_string;
00609     std::string token;
00610     
00611     while( (f.good() == true) && (load_okay == true) )
00612       {
00613       std::getline(f, line_string);
00614       if(line_string.size() == 0)
00615         break;
00616       
00617       std::stringstream line_stream(line_string);
00618       
00619       u32 line_n_cols = 0;
00620       while (line_stream >> token)
00621         line_n_cols++;
00622       
00623       if(f_n_cols_found == false)
00624         {
00625         f_n_cols = line_n_cols;
00626         f_n_cols_found = true;
00627         }
00628       else
00629         {
00630         if(line_n_cols != f_n_cols)
00631           {
00632           arma_print("inconsistent number of columns in ", name );
00633           load_okay = false;
00634           }
00635         }
00636       
00637       ++f_n_rows;
00638       }
00639       
00640     if(load_okay == true)
00641       {
00642       f.clear();
00643       f.seekg(0, ios::beg);
00644       //f.seekg(start);
00645       
00646       x.set_size(f_n_rows, f_n_cols);
00647     
00648       eT val;
00649       
00650       for(u32 row=0; row < x.n_rows; ++row)
00651         {
00652         for(u32 col=0; col < x.n_cols; ++col)
00653           {
00654           // f >> token;
00655           // x.at(row,col) = eT( strtod(token.c_str(), 0) );
00656           
00657           f >> val;
00658           x.at(row,col) = val;
00659           }
00660         }
00661       }
00662     
00663     if(f.good() == false)
00664       {
00665       arma_print("trouble reading ", name );
00666       load_okay = false; 
00667       }
00668     
00669     f.close();
00670     }
00671   
00672   
00673   if(load_okay == false)
00674     {
00675     x.reset();
00676     }
00677   
00678   }
00679 
00680 
00681 
00682 //! Load a matrix in text format (human readable),
00683 //! with a header that indicates the matrix type as well as its dimensions
00684 template<typename eT>
00685 inline
00686 void
00687 diskio::load_arma_ascii(Mat<eT>& x, const std::string& name)
00688   {
00689   arma_extra_debug_sigprint();
00690   
00691   std::ifstream f(name.c_str());
00692   diskio::load_arma_ascii(x, name, f);
00693   f.close();
00694   }
00695   
00696 
00697 
00698 //! Load a matrix in text format (human readable),
00699 //! with a header that indicates the matrix type as well as its dimensions
00700 template<typename eT>
00701 inline
00702 void
00703 diskio::load_arma_ascii(Mat<eT>& x, const std::string& name, std::ifstream& f)
00704   {
00705   arma_extra_debug_sigprint();
00706   
00707   bool load_okay = true;
00708   
00709   if(f.is_open() == false)
00710     {
00711     load_okay = false;
00712     arma_extra_debug_print("unable to read ", name);
00713     }
00714   else
00715     {
00716     std::string f_header;
00717     u32 f_n_rows;
00718     u32 f_n_cols;
00719     
00720     f >> f_header;
00721     f >> f_n_rows;
00722     f >> f_n_cols;
00723     
00724     if(f_header == diskio::gen_txt_header(x))
00725       {
00726       x.set_size(f_n_rows, f_n_cols);
00727       
00728       for(u32 row=0; row < x.n_rows; ++row)
00729         {
00730         for(u32 col=0; col < x.n_cols; ++col)
00731           {
00732           f >> x.at(row,col);
00733           }
00734         }
00735       
00736       if(f.good() == false)
00737         {
00738         arma_print("trouble reading ", name);
00739         load_okay = false;
00740         }
00741       }
00742     else
00743       {
00744       arma_print("incorrect header in ", name );
00745       load_okay = false;
00746       }
00747   
00748     }
00749   
00750   
00751   if(load_okay == false)
00752     {
00753     x.reset();
00754     }
00755   }
00756 
00757 
00758 
00759 //! Load a matrix in binary format,
00760 //! with a header that indicates the matrix type as well as its dimensions
00761 template<typename eT>
00762 inline
00763 void
00764 diskio::load_arma_binary(Mat<eT>& x, const std::string& name)
00765   {
00766   arma_extra_debug_sigprint();
00767   
00768   std::ifstream f;
00769   f.open(name.c_str(), std::fstream::binary);
00770   diskio::load_arma_binary(x, name, f);
00771   f.close();
00772   }
00773 
00774 
00775 
00776 template<typename eT>
00777 inline
00778 void
00779 diskio::load_arma_binary(Mat<eT>& x, const std::string& name, std::ifstream& f)
00780   {
00781   arma_extra_debug_sigprint();
00782   
00783   bool load_okay = true;
00784   
00785   if(f.is_open() == false)
00786     {
00787     load_okay = false;
00788     arma_extra_debug_print("unable to read ", name);
00789     }
00790   else
00791     {
00792     std::string f_header;
00793     u32 f_n_rows;
00794     u32 f_n_cols;
00795     
00796     f >> f_header;
00797     f >> f_n_rows;
00798     f >> f_n_cols;
00799     
00800     if(f_header == diskio::gen_bin_header(x))
00801       {
00802       //f.seekg(1, ios::cur);  // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
00803       f.get();
00804       
00805       x.set_size(f_n_rows,f_n_cols);
00806       f.read( reinterpret_cast<char *>(x.memptr()), x.n_elem*sizeof(eT));
00807       
00808       if(f.good() == false)
00809         {
00810         arma_print("trouble reading ", name);
00811         load_okay = false;
00812         }
00813       }
00814     else
00815       {
00816       arma_print("incorrect header in ", name);
00817       load_okay = false;
00818       }
00819     
00820     }
00821   
00822   if(load_okay == false)
00823     {
00824     x.reset();
00825     }
00826   }
00827 
00828 
00829 
00830 inline
00831 void
00832 diskio::pnm_skip_comments(std::fstream& f)
00833   {
00834   while( isspace(f.peek()) )
00835     {
00836     while( isspace(f.peek()) )
00837       f.get();
00838   
00839     if(f.peek() == '#')
00840       {
00841       while( (f.peek() != '\r') && (f.peek()!='\n') )
00842         f.get();
00843       }
00844     }
00845   }
00846 
00847 
00848 
00849 //! Load a PGM greyscale image as a matrix
00850 template<typename eT>
00851 inline
00852 void
00853 diskio::load_pgm_binary(Mat<eT>& x, const std::string& name)
00854   {
00855   arma_extra_debug_sigprint();
00856   
00857   std::fstream f;
00858   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
00859   
00860   bool load_okay = true;
00861   
00862   if(f.is_open() == false)
00863     {
00864     load_okay = false;
00865     arma_extra_debug_print("unable to read ", name);
00866     }
00867   else
00868     {
00869     std::string f_header;
00870     f >> f_header;
00871     
00872     if(f_header == "P5")
00873       {
00874       u32 f_n_rows = 0;
00875       u32 f_n_cols = 0;
00876       int f_maxval = 0;
00877     
00878       diskio::pnm_skip_comments(f);
00879     
00880       f >> f_n_cols;
00881       diskio::pnm_skip_comments(f);
00882     
00883       f >> f_n_rows;
00884       diskio::pnm_skip_comments(f);
00885     
00886       f >> f_maxval;
00887       f.get();
00888       
00889       if( (f_maxval > 0) || (f_maxval <= 65535) )
00890         {
00891         x.set_size(f_n_rows,f_n_cols);
00892         
00893         if(f_maxval <= 255)
00894           {
00895           const u32 n_elem = f_n_cols*f_n_rows;
00896           podarray<u8> tmp(n_elem);
00897           
00898           f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
00899           
00900           u32 i = 0;
00901           
00902           //cout << "f_n_cols = " << f_n_cols << endl;
00903           //cout << "f_n_rows = " << f_n_rows << endl;
00904           
00905           
00906           for(u32 row=0; row < f_n_rows; ++row)
00907             {
00908             for(u32 col=0; col < f_n_cols; ++col)
00909               {
00910               x.at(row,col) = eT(tmp[i]);
00911               ++i;
00912               }
00913             
00914             }
00915           }
00916         else
00917           {
00918           const u32 n_elem = f_n_cols*f_n_rows;
00919           podarray<u16> tmp(n_elem);
00920           
00921           f.read( reinterpret_cast<char *>(tmp.memptr()), n_elem*2);
00922           
00923           u32 i = 0;
00924           
00925           for(u32 row=0; row < f_n_rows; ++row)
00926             {
00927             for(u32 col=0; col < f_n_cols; ++col)
00928               {
00929               x.at(row,col) = eT(tmp[i]);
00930               ++i;
00931               }
00932             
00933             }
00934           
00935           }
00936         
00937         }
00938       
00939       if(f.good() == false)
00940         {
00941         arma_print("trouble reading ", name);
00942         load_okay = false;
00943         }
00944       }
00945     else
00946       {
00947       arma_print("unsupported header in ", name);
00948       load_okay = false;
00949       }
00950     
00951     f.close();
00952     }
00953   
00954   
00955   if(load_okay == false)
00956     {
00957     x.reset();
00958     }
00959   }
00960 
00961 
00962 
00963 //! Load a PGM greyscale image as a matrix
00964 template<typename T>
00965 inline
00966 void
00967 diskio::load_pgm_binary(Mat< std::complex<T> >& x, const std::string& name)
00968   {
00969   arma_extra_debug_sigprint();
00970   
00971   uchar_mat tmp;
00972   tmp.load(name);
00973   x = conv_to< Mat< std::complex<T> > >::from(tmp);
00974   }
00975 
00976 
00977 
00978 //! Try to load a matrix by automatically determining its type
00979 template<typename eT>
00980 inline
00981 void
00982 diskio::load_auto_detect(Mat<eT>& x, const std::string& name)
00983   {
00984   arma_extra_debug_sigprint();
00985   
00986   static const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT";
00987   static const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN";
00988   static const std::string           P5 = "P5";
00989   
00990   std::fstream f;
00991   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
00992   
00993   if(f.is_open() == false)
00994     {
00995     x.reset();
00996     arma_extra_debug_print("unable to read ", name);
00997     }
00998   else
00999     {
01000     podarray<char> raw_header(ARMA_MAT_TXT.length() + 1);
01001     
01002     f.read(raw_header.memptr(), ARMA_MAT_TXT.length());
01003     raw_header[ARMA_MAT_TXT.length()] = '\0';
01004     
01005     const std::string header = raw_header.mem;
01006     
01007     if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length()))
01008       {
01009       load_arma_ascii(x, name);
01010       }
01011     else
01012     if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length()))
01013       {
01014       load_arma_binary(x, name);
01015       }
01016     else
01017     if(P5 == header.substr(0,P5.length()))
01018       {
01019       load_pgm_binary(x, name);
01020       }
01021     else
01022       {
01023       load_raw_ascii(x, name);
01024       }
01025     
01026     f.close();
01027     }
01028   
01029   }
01030 
01031 
01032 
01033 template<typename T1>
01034 inline
01035 void
01036 diskio::save_field_arma_binary(const field<T1>& x, const std::string& final_name)
01037   {
01038   arma_extra_debug_sigprint();
01039   
01040   arma_type_check<is_Mat<T1>::value == false>::apply();
01041   
01042   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01043   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01044   
01045   if(f.is_open() == false)
01046     {
01047     arma_print("couldn't write ", tmp_name);
01048     }
01049   else
01050     {
01051     f << "ARMA_FLD_BIN" << '\n';
01052     f << x.n_rows << '\n';
01053     f << x.n_cols << '\n';
01054     
01055     for(u32 i=0; i<x.n_elem; ++i)
01056       {
01057       diskio::save_arma_binary(x[i], tmp_name, f);
01058       }
01059     
01060     const bool writing_problem = (f.good() == false);
01061     
01062     arma_warn(writing_problem, "trouble writing ", tmp_name );
01063     
01064     f.flush();
01065     f.close();
01066     
01067     if(writing_problem == false)
01068       {
01069       diskio::safe_rename(tmp_name, final_name);
01070       }
01071     
01072     }
01073   
01074   }
01075 
01076 
01077 
01078 template<typename T1>
01079 inline
01080 void
01081 diskio::load_field_arma_binary(field<T1>& x, const std::string& name)
01082   {
01083   arma_extra_debug_sigprint();
01084   
01085   arma_type_check<is_Mat<T1>::value == false>::apply();
01086   
01087   bool load_okay = true;
01088   
01089   std::ifstream f( name.c_str() );
01090   
01091   if(f.fail())
01092     {
01093     load_okay = false;
01094     arma_extra_debug_print("unable to read ", name);
01095     }
01096   else
01097     {
01098     std::string f_type;
01099     f >> f_type;
01100     
01101     if(f_type != "ARMA_FLD_BIN")
01102       {
01103       arma_print("unsupported field type in ", name);
01104       load_okay = false;
01105       }
01106     else
01107       {
01108       u32 f_n_rows;
01109       u32 f_n_cols;
01110     
01111       f >> f_n_rows;
01112       f >> f_n_cols;
01113       
01114       x.set_size(f_n_rows, f_n_cols);
01115       
01116       f.get();      
01117       
01118       for(u32 i=0; i<x.n_elem; ++i)
01119         {
01120         diskio::load_arma_binary(x[i], name, f);
01121         
01122         if(f.good() == false)
01123           {
01124           arma_print("trouble reading ", name);
01125           load_okay = false;
01126           break;
01127           }
01128         }
01129       }
01130     }
01131   
01132   f.close();
01133   
01134   
01135   if(load_okay == false)
01136     {
01137     x.reset();
01138     }
01139   }
01140 
01141 
01142 
01143 template<typename T1>
01144 inline
01145 void
01146 diskio::save_field_ppm_binary(const field<T1>& x, const std::string& final_name)
01147   {
01148   arma_extra_debug_sigprint();
01149   
01150   arma_type_check<is_Mat<T1>::value == false>::apply();
01151   typedef typename T1::elem_type eT;
01152   
01153   arma_debug_check( (x.n_elem != 3), "diskio::save_field_ppm_binary(): given field must have exactly 3 matrices of equal size" );
01154   
01155   bool same_size = true;
01156   for(u32 i=1; i<3; ++i)
01157     {
01158     if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) )
01159       {
01160       same_size = false;
01161       break;
01162       }
01163     }
01164   
01165   arma_debug_check( (same_size != true), "diskio::save_field_ppm_binary(): given field must have exactly 3 matrices of equal size" );
01166   
01167   const Mat<eT>& R = x(0);
01168   const Mat<eT>& G = x(1);
01169   const Mat<eT>& B = x(2);
01170   
01171   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01172   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01173   
01174   if(f.is_open() == false)
01175     {
01176     arma_print("couldn't write ", tmp_name);
01177     }
01178   else
01179     {
01180     f << "P6" << '\n';
01181     f << R.n_cols << '\n';
01182     f << R.n_rows << '\n';
01183     f << 255 << '\n';
01184 
01185     const u32 n_elem = 3 * R.n_rows * R.n_cols;
01186     podarray<u8> tmp(n_elem);
01187 
01188     u32 i = 0;
01189     for(u32 row=0; row < R.n_rows; ++row)
01190       {
01191       for(u32 col=0; col < R.n_cols; ++col)
01192         {
01193         tmp[i+0] = u8( R.at(row,col) );
01194         tmp[i+1] = u8( G.at(row,col) );
01195         tmp[i+2] = u8( B.at(row,col) );
01196         
01197         i+=3;
01198         }
01199       }
01200     
01201     f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
01202     
01203     const bool writing_problem = (f.good() == false);
01204     
01205     arma_warn(writing_problem, "trouble writing ", tmp_name );
01206     
01207     f.flush();
01208     f.close();
01209     
01210     if(writing_problem == false)
01211       {
01212       diskio::safe_rename(tmp_name, final_name);
01213       }
01214     
01215     }
01216   
01217   }
01218 
01219 
01220 
01221 template<typename T1>
01222 inline
01223 void
01224 diskio::load_field_ppm_binary(field<T1>& x, const std::string& name)
01225   {
01226   arma_extra_debug_sigprint();
01227   
01228   arma_type_check<is_Mat<T1>::value == false>::apply();
01229   typedef typename T1::elem_type eT;
01230   
01231   std::fstream f;
01232   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01233   
01234   bool load_okay = true;
01235   
01236   if(f.is_open() == false)
01237     {
01238     load_okay = false;
01239     arma_extra_debug_print("unable to read ", name);
01240     }
01241   else
01242     {
01243     std::string f_header;
01244     f >> f_header;
01245     
01246     if(f_header == "P6")
01247       {
01248       u32 f_n_rows = 0;
01249       u32 f_n_cols = 0;
01250       int f_maxval = 0;
01251     
01252       diskio::pnm_skip_comments(f);
01253     
01254       f >> f_n_cols;
01255       diskio::pnm_skip_comments(f);
01256     
01257       f >> f_n_rows;
01258       diskio::pnm_skip_comments(f);
01259     
01260       f >> f_maxval;
01261       f.get();
01262       
01263       if( (f_maxval > 0) || (f_maxval <= 65535) )
01264         {
01265         x.set_size(3);
01266         Mat<eT>& R = x(0);
01267         Mat<eT>& G = x(1);
01268         Mat<eT>& B = x(2);
01269         
01270         R.set_size(f_n_rows,f_n_cols);
01271         G.set_size(f_n_rows,f_n_cols);
01272         B.set_size(f_n_rows,f_n_cols);
01273         
01274         if(f_maxval <= 255)
01275           {
01276           const u32 n_elem = 3*f_n_cols*f_n_rows;
01277           podarray<u8> tmp(n_elem);
01278           
01279           f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
01280           
01281           u32 i = 0;
01282           
01283           //cout << "f_n_cols = " << f_n_cols << endl;
01284           //cout << "f_n_rows = " << f_n_rows << endl;
01285           
01286           
01287           for(u32 row=0; row < f_n_rows; ++row)
01288             {
01289             for(u32 col=0; col < f_n_cols; ++col)
01290               {
01291               R.at(row,col) = eT(tmp[i+0]);
01292               G.at(row,col) = eT(tmp[i+1]);
01293               B.at(row,col) = eT(tmp[i+2]);
01294               i+=3;
01295               }
01296             
01297             }
01298           }
01299         else
01300           {
01301           const u32 n_elem = 3*f_n_cols*f_n_rows;
01302           podarray<u16> tmp(n_elem);
01303           
01304           f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
01305           
01306           u32 i = 0;
01307           
01308           for(u32 row=0; row < f_n_rows; ++row)
01309             {
01310             for(u32 col=0; col < f_n_cols; ++col)
01311               {
01312               R.at(row,col) = eT(tmp[i+0]);
01313               G.at(row,col) = eT(tmp[i+1]);
01314               B.at(row,col) = eT(tmp[i+2]);
01315               i+=3;
01316               }
01317             
01318             }
01319           
01320           }
01321         
01322         }
01323       
01324       if(f.good() == false)
01325         {
01326         arma_print("trouble reading ", name);
01327         load_okay = false;
01328         }
01329       
01330       }
01331     else
01332       {
01333       arma_print("unsupported header in ", name);
01334       load_okay = false;
01335       }
01336     
01337     f.close();
01338     }
01339   
01340   
01341   if(load_okay == false)
01342     {
01343     x.reset();
01344     }
01345   
01346   }
01347 
01348 
01349 
01350 inline
01351 void
01352 diskio::save_field_std_string(const field<std::string>& x, const std::string& final_name)
01353   {
01354   arma_extra_debug_sigprint();
01355   
01356   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01357   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01358   
01359   if(f.is_open() == false)
01360     {
01361     arma_print("couldn't write ", tmp_name);
01362     }
01363   else
01364     {
01365     for(u32 row=0; row<x.n_rows; ++row)
01366     for(u32 col=0; col<x.n_cols; ++col)
01367       {
01368       f << x.at(row,col);
01369       
01370       if(col < x.n_cols-1)
01371         {
01372         f << ' ';
01373         }
01374       else
01375         {
01376         f << '\n';
01377         }
01378       }
01379     
01380     const bool writing_problem = (f.good() == false);
01381     
01382     arma_warn(writing_problem, "trouble writing ", tmp_name );
01383     
01384     f.flush();
01385     f.close();
01386     
01387     if(writing_problem == false)
01388       {
01389       diskio::safe_rename(tmp_name, final_name);
01390       }
01391     
01392     }
01393   
01394   }
01395 
01396 
01397 
01398 inline
01399 void
01400 diskio::load_field_std_string(field<std::string>& x, const std::string& name)
01401   {
01402   arma_extra_debug_sigprint();
01403   
01404   bool load_okay = true;
01405   
01406   std::ifstream f( name.c_str() );
01407   
01408   if(f.fail())
01409     {
01410     load_okay = false;
01411     arma_extra_debug_print("unable to read ", name);
01412     }
01413   else
01414     {
01415     //
01416     // work out the size
01417     
01418     u32 f_n_rows = 0;
01419     u32 f_n_cols = 0;
01420     
01421     bool f_n_cols_found = false;
01422     
01423     std::string line_string;
01424     std::string token;
01425     
01426     while( (f.good() == true) && (load_okay == true) )
01427       {
01428       std::getline(f, line_string);
01429       if(line_string.size() == 0)
01430         break;
01431       
01432       std::stringstream line_stream(line_string);
01433       
01434       u32 line_n_cols = 0;
01435       while (line_stream >> token)
01436         line_n_cols++;
01437       
01438       if(f_n_cols_found == false)
01439         {
01440         f_n_cols = line_n_cols;
01441         f_n_cols_found = true;
01442         }
01443       else
01444         {
01445         if(line_n_cols != f_n_cols)
01446           {
01447           load_okay = false;
01448           arma_print("inconsistent number of columns in ", name );
01449           }
01450         }
01451       
01452       ++f_n_rows;
01453       }
01454       
01455     if(load_okay == true)
01456       {
01457       f.clear();
01458       f.seekg(0, ios::beg);
01459       //f.seekg(start);
01460       
01461       x.set_size(f_n_rows, f_n_cols);
01462     
01463       for(u32 row=0; row < x.n_rows; ++row)
01464         {
01465         for(u32 col=0; col < x.n_cols; ++col)
01466           {
01467           f >> x.at(row,col);
01468           }
01469         }
01470       }
01471     
01472     if(f.good() == false)
01473       {
01474       load_okay = false; 
01475       arma_print("trouble reading ", name );
01476       }
01477     
01478     f.close();
01479     }
01480   
01481   
01482   if(load_okay == false)
01483     {
01484     x.reset();
01485     }
01486   
01487   }
01488 
01489 
01490 
01491 //! Try to load a field by automatically determining its type
01492 template<typename T1>
01493 inline
01494 void
01495 diskio::load_field_auto_detect(field<T1>& x, const std::string& name)
01496   {
01497   arma_extra_debug_sigprint();
01498   
01499   arma_type_check<is_Mat<T1>::value == false>::apply();
01500   
01501   static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN";
01502   static const std::string           P6 = "P6";
01503   
01504   std::fstream f;
01505   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01506   
01507   if(f.is_open() == false)
01508     {
01509     x.reset();
01510     arma_extra_debug_print("unable to read ", name);
01511     }
01512   else
01513     {
01514     podarray<char> raw_header(ARMA_FLD_BIN.length() + 1);
01515     
01516     f.read(raw_header.memptr(), ARMA_FLD_BIN.length());
01517     raw_header[ARMA_FLD_BIN.length()] = '\0';
01518     
01519     const std::string header = raw_header.mem;
01520     
01521     if(ARMA_FLD_BIN == header.substr(0,ARMA_FLD_BIN.length()))
01522       {
01523       load_field_arma_binary(x, name);
01524       }
01525     else
01526     if(P6 == header.substr(0,P6.length()))
01527       {
01528       load_field_ppm_binary(x, name);
01529       }
01530     else
01531       {
01532       arma_print("unsupported header in ", name);
01533       x.reset();
01534       }
01535     
01536     f.close();
01537     }
01538   
01539   }
01540 
01541 
01542 
01543 //! @}
01544