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