diskio_meat.hpp

Go to the documentation of this file.
00001 // Copyright (C) 2010 NICTA and the authors listed below
00002 // http://nicta.com.au
00003 // 
00004 // Authors:
00005 // - Conrad Sanderson (conradsand at ieee dot org)
00006 // - Ian Cullinan (ian dot cullinan at nicta dot com dot au)
00007 // 
00008 // This file is part of the Armadillo C++ library.
00009 // It is provided without any warranty of fitness
00010 // for any purpose. You can redistribute this file
00011 // and/or modify it under the terms of the GNU
00012 // Lesser General Public License (LGPL) as published
00013 // by the Free Software Foundation, either version 3
00014 // of the License or (at your option) any later version.
00015 // (see http://www.opensource.org/licenses for more info)
00016 
00017 
00018 //! \addtogroup diskio
00019 //! @{
00020 
00021 
00022 //! Generate the first line of the header used for saving matrices in text format.
00023 //! Format: "ARMA_MAT_TXT_ABXYZ".
00024 //! A is one of: I (for integral types) or F (for floating point types).
00025 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
00026 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
00027 template<typename eT>
00028 inline
00029 std::string
00030 diskio::gen_txt_header(const Mat<eT>& x)
00031   {
00032   arma_type_check<diskio::is_supported_type<eT>::value == false>::apply();
00033 
00034   if(is_u8<eT>::value == true)
00035     {
00036     return std::string("ARMA_MAT_TXT_IU001");
00037     }
00038   else
00039   if(is_s8<eT>::value == true)
00040     {
00041     return std::string("ARMA_MAT_TXT_IS001");
00042     }
00043   else
00044   if(is_u16<eT>::value == true)
00045     {
00046     return std::string("ARMA_MAT_TXT_IU002");
00047     }
00048   else
00049   if(is_s16<eT>::value == true)
00050     {
00051     return std::string("ARMA_MAT_TXT_IS002");
00052     }
00053   else
00054   if(is_u32<eT>::value == true)
00055     {
00056     return std::string("ARMA_MAT_TXT_IU004");
00057     }
00058   else
00059   if(is_s32<eT>::value == true)
00060     {
00061     return std::string("ARMA_MAT_TXT_IS004");
00062     }
00063   else
00064   if(is_float<eT>::value == true)
00065     {
00066     return std::string("ARMA_MAT_TXT_FN004");
00067     }
00068   else
00069   if(is_double<eT>::value == true)
00070     {
00071     return std::string("ARMA_MAT_TXT_FN008");
00072     }
00073   else
00074   if(is_complex_float<eT>::value == true)
00075     {
00076     return std::string("ARMA_MAT_TXT_FC008");
00077     }
00078   else
00079   if(is_complex_double<eT>::value == true)
00080     {
00081     return std::string("ARMA_MAT_TXT_FC016");
00082     }
00083   else
00084     {
00085     return std::string();
00086     }
00087   
00088   }
00089 
00090 
00091 
00092 //! Generate the first line of the header used for saving matrices in binary format.
00093 //! Format: "ARMA_MAT_BIN_ABXYZ".
00094 //! A is one of: I (for integral types) or F (for floating point types).
00095 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
00096 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
00097 template<typename eT>
00098 inline
00099 std::string
00100 diskio::gen_bin_header(const Mat<eT>& x)
00101   {
00102   arma_type_check<diskio::is_supported_type<eT>::value == false>::apply();
00103   
00104   if(is_u8<eT>::value == true)
00105     {
00106     return std::string("ARMA_MAT_BIN_IU001");
00107     }
00108   else
00109   if(is_s8<eT>::value == true)
00110     {
00111     return std::string("ARMA_MAT_BIN_IS001");
00112     }
00113   else
00114   if(is_u16<eT>::value == true)
00115     {
00116     return std::string("ARMA_MAT_BIN_IU002");
00117     }
00118   else
00119   if(is_s16<eT>::value == true)
00120     {
00121     return std::string("ARMA_MAT_BIN_IS002");
00122     }
00123   else
00124   if(is_u32<eT>::value == true)
00125     {
00126     return std::string("ARMA_MAT_BIN_IU004");
00127     }
00128   else
00129   if(is_s32<eT>::value == true)
00130     {
00131     return std::string("ARMA_MAT_BIN_IS004");
00132     }
00133   else
00134   if(is_float<eT>::value == true)
00135     {
00136     return std::string("ARMA_MAT_BIN_FN004");
00137     }
00138   else
00139   if(is_double<eT>::value == true)
00140     {
00141     return std::string("ARMA_MAT_BIN_FN008");
00142     }
00143   else
00144   if(is_complex_float<eT>::value == true)
00145     {
00146     return std::string("ARMA_MAT_BIN_FC008");
00147     }
00148   else
00149   if(is_complex_double<eT>::value == true)
00150     {
00151     return std::string("ARMA_MAT_BIN_FC016");
00152     }
00153   else
00154     {
00155     return std::string();
00156     }
00157   
00158   }
00159 
00160 
00161 
00162 //! Generate the first line of the header used for saving cubes in text format.
00163 //! Format: "ARMA_CUB_TXT_ABXYZ".
00164 //! A is one of: I (for integral types) or F (for floating point types).
00165 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
00166 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
00167 template<typename eT>
00168 inline
00169 std::string
00170 diskio::gen_txt_header(const Cube<eT>& x)
00171   {
00172   arma_type_check<diskio::is_supported_type<eT>::value == false>::apply();
00173 
00174   if(is_u8<eT>::value == true)
00175     {
00176     return std::string("ARMA_CUB_TXT_IU001");
00177     }
00178   else
00179   if(is_s8<eT>::value == true)
00180     {
00181     return std::string("ARMA_CUB_TXT_IS001");
00182     }
00183   else
00184   if(is_u16<eT>::value == true)
00185     {
00186     return std::string("ARMA_CUB_TXT_IU002");
00187     }
00188   else
00189   if(is_s16<eT>::value == true)
00190     {
00191     return std::string("ARMA_CUB_TXT_IS002");
00192     }
00193   else
00194   if(is_u32<eT>::value == true)
00195     {
00196     return std::string("ARMA_CUB_TXT_IU004");
00197     }
00198   else
00199   if(is_s32<eT>::value == true)
00200     {
00201     return std::string("ARMA_CUB_TXT_IS004");
00202     }
00203   else
00204   if(is_float<eT>::value == true)
00205     {
00206     return std::string("ARMA_CUB_TXT_FN004");
00207     }
00208   else
00209   if(is_double<eT>::value == true)
00210     {
00211     return std::string("ARMA_CUB_TXT_FN008");
00212     }
00213   else
00214   if(is_complex_float<eT>::value == true)
00215     {
00216     return std::string("ARMA_CUB_TXT_FC008");
00217     }
00218   else
00219   if(is_complex_double<eT>::value == true)
00220     {
00221     return std::string("ARMA_CUB_TXT_FC016");
00222     }
00223   else
00224     {
00225     return std::string();
00226     }
00227   
00228   }
00229 
00230 
00231 
00232 //! Generate the first line of the header used for saving cubes in binary format.
00233 //! Format: "ARMA_CUB_BIN_ABXYZ".
00234 //! A is one of: I (for integral types) or F (for floating point types).
00235 //! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types).
00236 //! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes.
00237 template<typename eT>
00238 inline
00239 std::string
00240 diskio::gen_bin_header(const Cube<eT>& x)
00241   {
00242   arma_type_check<diskio::is_supported_type<eT>::value == false>::apply();
00243   
00244   if(is_u8<eT>::value == true)
00245     {
00246     return std::string("ARMA_CUB_BIN_IU001");
00247     }
00248   else
00249   if(is_s8<eT>::value == true)
00250     {
00251     return std::string("ARMA_CUB_BIN_IS001");
00252     }
00253   else
00254   if(is_u16<eT>::value == true)
00255     {
00256     return std::string("ARMA_CUB_BIN_IU002");
00257     }
00258   else
00259   if(is_s16<eT>::value == true)
00260     {
00261     return std::string("ARMA_CUB_BIN_IS002");
00262     }
00263   else
00264   if(is_u32<eT>::value == true)
00265     {
00266     return std::string("ARMA_CUB_BIN_IU004");
00267     }
00268   else
00269   if(is_s32<eT>::value == true)
00270     {
00271     return std::string("ARMA_CUB_BIN_IS004");
00272     }
00273   else
00274   if(is_float<eT>::value == true)
00275     {
00276     return std::string("ARMA_CUB_BIN_FN004");
00277     }
00278   else
00279   if(is_double<eT>::value == true)
00280     {
00281     return std::string("ARMA_CUB_BIN_FN008");
00282     }
00283   else
00284   if(is_complex_float<eT>::value == true)
00285     {
00286     return std::string("ARMA_CUB_BIN_FC008");
00287     }
00288   else
00289   if(is_complex_double<eT>::value == true)
00290     {
00291     return std::string("ARMA_CUB_BIN_FC016");
00292     }
00293   else
00294     {
00295     return std::string();
00296     }
00297   
00298   }
00299 
00300 
00301 
00302 inline
00303 char
00304 diskio::conv_to_hex_char(const u8 x)
00305   {
00306   char out;
00307 
00308   switch(x)
00309     {
00310     case  0: out = '0'; break;
00311     case  1: out = '1'; break;
00312     case  2: out = '2'; break;
00313     case  3: out = '3'; break;
00314     case  4: out = '4'; break;
00315     case  5: out = '5'; break;
00316     case  6: out = '6'; break;
00317     case  7: out = '7'; break;
00318     case  8: out = '8'; break;
00319     case  9: out = '9'; break;
00320     case 10: out = 'a'; break;
00321     case 11: out = 'b'; break;
00322     case 12: out = 'c'; break;
00323     case 13: out = 'd'; break;
00324     case 14: out = 'e'; break;
00325     case 15: out = 'f'; break;
00326     default: out = '-'; break;
00327     }
00328 
00329   return out;  
00330   }
00331 
00332 
00333 
00334 inline
00335 void
00336 diskio::conv_to_hex(char* out, const u8 x)
00337   {
00338   const u8 a = x / 16;
00339   const u8 b = x - 16*a;
00340 
00341   out[0] = conv_to_hex_char(a);
00342   out[1] = conv_to_hex_char(b);
00343   }
00344 
00345 
00346 
00347 //! Append a quasi-random string to the given filename.
00348 //! The rand() function is deliberately not used,
00349 //! as rand() has an internal state that changes
00350 //! from call to call. Such states should not be
00351 //! modified in scientific applications, where the
00352 //! results should be reproducable and not affected 
00353 //! by saving data.
00354 inline
00355 std::string
00356 diskio::gen_tmp_name(const std::string& x)
00357   {
00358   const std::string* ptr_x     = &x;
00359   const u8*          ptr_ptr_x = reinterpret_cast<const u8*>(&ptr_x);
00360   
00361   const char* extra      = ".tmp_";
00362   const u32   extra_size = 5;
00363   
00364   const u32   tmp_size   = 2*sizeof(u8*) + 2*2;
00365         char  tmp[tmp_size];
00366   
00367   u32 char_count = 0;
00368   
00369   for(u32 i=0; i<sizeof(u8*); ++i)
00370     {
00371     conv_to_hex(&tmp[char_count], ptr_ptr_x[i]);
00372     char_count += 2;
00373     }
00374   
00375   const u32 x_size = x.size();
00376   u8 sum = 0;
00377   
00378   for(u32 i=0; i<x_size; ++i)
00379     {
00380     sum += u8(x[i]);
00381     }
00382   
00383   conv_to_hex(&tmp[char_count], sum);
00384   char_count += 2;
00385   
00386   conv_to_hex(&tmp[char_count], u8(x_size));
00387   
00388   
00389   std::string out;
00390   out.resize(x_size + extra_size + tmp_size);
00391   
00392   
00393   for(u32 i=0; i<x_size; ++i)
00394     {
00395     out[i] = x[i];
00396     }
00397   
00398   for(u32 i=0; i<extra_size; ++i)
00399     {
00400     out[x_size + i] = extra[i];
00401     }
00402   
00403   for(u32 i=0; i<tmp_size; ++i)
00404     {
00405     out[x_size + extra_size + i] = tmp[i];
00406     }
00407   
00408   return out;
00409   }
00410 
00411 
00412 
00413 //! Safely rename a file.
00414 //! Before renaming, test if we can write to the final file.
00415 //! This should prevent:
00416 //! (i)  overwriting files that have been write protected,
00417 //! (ii) overwriting directories.
00418 inline
00419 void
00420 diskio::safe_rename(const std::string& old_name, const std::string& new_name)
00421   {
00422   std::fstream f(new_name.c_str(), std::fstream::out | std::fstream::app);
00423   f.put(' ');
00424   
00425   const bool writing_problem = (f.good() == false);
00426   f.close();
00427   
00428   arma_warn( writing_problem, "trouble writing ", new_name );
00429   
00430   if(writing_problem == false)
00431     {
00432     std::remove(new_name.c_str());
00433     
00434     const int mv_result = std::rename(old_name.c_str(), new_name.c_str());
00435     arma_warn( (mv_result != 0), "trouble writing ", new_name );
00436     }
00437   
00438   }
00439 
00440 
00441 
00442 //! Save a matrix as raw text (no header, human readable).
00443 //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
00444 template<typename eT>
00445 inline
00446 void
00447 diskio::save_raw_ascii(const Mat<eT>& x, const std::string& final_name)
00448   {
00449   arma_extra_debug_sigprint();
00450   
00451   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00452   
00453   std::fstream f(tmp_name.c_str(), std::fstream::out);
00454   
00455   if(f.is_open() == false)
00456     {
00457     arma_print("unable to write ", tmp_name);
00458     }
00459   else
00460     {
00461     diskio::save_raw_ascii(x, tmp_name, f);
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 
00478 //! Save a matrix as raw text (no header, human readable).
00479 //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
00480 template<typename eT>
00481 inline
00482 void
00483 diskio::save_raw_ascii(const Mat<eT>& x, const std::string& name, std::ostream& f)
00484   {
00485   arma_extra_debug_sigprint();
00486   
00487   u32 cell_width;
00488   
00489   // TODO: need sane values for complex numbers
00490   
00491   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00492     {
00493     f.setf(ios::scientific);
00494     f.precision(8);
00495     cell_width = 16;
00496     }
00497   
00498   for(u32 row=0; row < x.n_rows; ++row)
00499     {
00500     for(u32 col=0; col < x.n_cols; ++col)
00501       {
00502       f.put(' ');
00503       
00504       if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00505         {
00506         f.width(cell_width);
00507         }
00508       
00509       f << x.at(row,col);
00510       }
00511       
00512     f.put('\n');
00513     }
00514   }
00515 
00516 
00517 
00518 //! Save a matrix in text format (human readable),
00519 //! with a header that indicates the matrix type as well as its dimensions
00520 template<typename eT>
00521 inline
00522 void
00523 diskio::save_arma_ascii(const Mat<eT>& x, const std::string& final_name)
00524   {
00525   arma_extra_debug_sigprint();
00526   
00527   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00528   
00529   std::ofstream f(tmp_name.c_str());
00530   
00531   if(f.is_open() == false)
00532     {
00533     arma_debug_print("unable to write ", tmp_name);
00534     }
00535   else
00536     {
00537     diskio::save_arma_ascii(x, tmp_name, f);
00538     
00539     const bool writing_problem = (f.good() == false);
00540     
00541     f.flush();
00542     f.close();
00543     
00544     arma_warn( writing_problem, "trouble writing ", tmp_name );
00545     
00546     if(writing_problem == false)
00547       {
00548       diskio::safe_rename(tmp_name, final_name);
00549       }
00550     }
00551   }
00552 
00553 
00554 
00555 //! Save a matrix in text format (human readable),
00556 //! with a header that indicates the matrix type as well as its dimensions
00557 template<typename eT>
00558 inline
00559 void 
00560 diskio::save_arma_ascii(const Mat<eT>& x, const std::string& name, std::ostream& f)
00561   {
00562   arma_extra_debug_sigprint();
00563   
00564   const ios::fmtflags orig_flags = f.flags();
00565   
00566   f << diskio::gen_txt_header(x) << '\n';
00567   f << x.n_rows << ' ' << x.n_cols << '\n';
00568   
00569   u32 cell_width;
00570   
00571   // TODO: need sane values for complex numbers
00572   
00573   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00574     {
00575     f.setf(ios::scientific);
00576     f.precision(8);
00577     cell_width = 16;
00578     }
00579     
00580   for(u32 row=0; row < x.n_rows; ++row)
00581     {
00582     for(u32 col=0; col < x.n_cols; ++col)
00583       {
00584       f.put(' ');
00585       
00586       if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )        
00587         {
00588         f.width(cell_width);
00589         }
00590       
00591       f << x.at(row,col);
00592       }
00593     
00594     f.put('\n');
00595     }
00596   
00597   f.flags(orig_flags);
00598   }
00599 
00600 
00601 
00602 //! Save a matrix in binary format,
00603 //! with a header that stores the matrix type as well as its dimensions
00604 template<typename eT>
00605 inline
00606 void
00607 diskio::save_arma_binary(const Mat<eT>& x, const std::string& final_name)
00608   {
00609   arma_extra_debug_sigprint();
00610   
00611   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00612   
00613   std::ofstream f(tmp_name.c_str(), std::fstream::binary);
00614   
00615   if(f.is_open() == false)
00616     {
00617     arma_print("unable to write ", tmp_name);
00618     }
00619   else
00620     {  
00621     diskio::save_arma_binary(x, tmp_name, f);
00622     
00623     const bool writing_problem = (f.good() == false);
00624     
00625     f.flush();
00626     f.close();
00627     
00628     arma_warn( writing_problem, "trouble writing ", tmp_name );
00629     
00630     if(writing_problem == false)
00631       {
00632       diskio::safe_rename(tmp_name, final_name);
00633       }
00634     }
00635   }
00636 
00637 
00638 
00639 //! Save a matrix in binary format,
00640 //! with a header that stores the matrix type as well as its dimensions
00641 template<typename eT>
00642 inline
00643 void
00644 diskio::save_arma_binary(const Mat<eT>& x, const std::string& name, std::ostream& f)
00645   {
00646   arma_extra_debug_sigprint();
00647 
00648   f << diskio::gen_bin_header(x) << '\n';
00649   f << x.n_rows << ' ' << x.n_cols << '\n';
00650   
00651   f.write(reinterpret_cast<const char*>(x.mem), x.n_elem*sizeof(eT));
00652   }
00653 
00654 
00655 
00656 //! Save a matrix as a PGM greyscale image
00657 template<typename eT>
00658 inline
00659 void
00660 diskio::save_pgm_binary(const Mat<eT>& x, const std::string& final_name)
00661   {
00662   arma_extra_debug_sigprint();
00663   
00664   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00665   
00666   std::fstream f(tmp_name.c_str(), std::fstream::out | std::fstream::binary);
00667   
00668   if(f.is_open() == false)
00669     {
00670     arma_print("unable to write ", tmp_name);
00671     }
00672   else
00673     {
00674     diskio::save_pgm_binary(x, tmp_name, f);
00675     
00676     const bool writing_problem = (f.good() == false);
00677     
00678     arma_warn(writing_problem, "trouble writing ", tmp_name );
00679     
00680     f.flush();
00681     f.close();
00682     
00683     if(writing_problem == false)
00684       {
00685       diskio::safe_rename(tmp_name, final_name);
00686       }
00687     }
00688   }
00689 
00690 
00691 
00692 //
00693 // TODO:
00694 // add functionality to save the image in a normalised format,
00695 // i.e. scaled so that every value falls in the [0,255] range.
00696 
00697 //! Save a matrix as a PGM greyscale image
00698 template<typename eT>
00699 inline
00700 void
00701 diskio::save_pgm_binary(const Mat<eT>& x, const std::string& name, std::ostream& f)
00702   {
00703   arma_extra_debug_sigprint();
00704   
00705   f << "P5" << '\n';
00706   f << x.n_cols << ' ' << x.n_rows << '\n';
00707   f << 255 << '\n';
00708   
00709   const u32 n_elem = x.n_rows * x.n_cols;
00710   podarray<u8> tmp(n_elem);
00711   
00712   u32 i = 0;
00713   
00714   for(u32 row=0; row < x.n_rows; ++row)
00715     {
00716     for(u32 col=0; col < x.n_cols; ++col)
00717       {
00718       tmp[i] = u8( x(row,col) );  // TODO: add round() ?
00719       ++i;
00720       }
00721     }
00722   
00723   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
00724   }
00725 
00726 
00727 
00728 //! Save a matrix as a PGM greyscale image
00729 template<typename T>
00730 inline
00731 void
00732 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, const std::string& final_name)
00733   {
00734   arma_extra_debug_sigprint();
00735   
00736   const uchar_mat tmp = conv_to<uchar_mat>::from(x);
00737   diskio::save_pgm_binary(tmp, final_name);
00738   }
00739 
00740 
00741 
00742 //! Save a matrix as a PGM greyscale image
00743 template<typename T>
00744 inline
00745 void
00746 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, const std::string& name, std::ostream& f)
00747   {
00748   arma_extra_debug_sigprint();
00749   
00750   const uchar_mat tmp = conv_to<uchar_mat>::from(x);
00751   diskio::save_pgm_binary(tmp, name, f);
00752   }
00753 
00754 
00755 
00756 //! Load a matrix as raw text (no header, human readable).
00757 //! Can read matrices saved as text in Matlab and Octave.
00758 //! NOTE: this is much slower than reading a file with a header.
00759 template<typename eT>
00760 inline
00761 void
00762 diskio::load_raw_ascii(Mat<eT>& x, const std::string& name)
00763   {
00764   arma_extra_debug_sigprint();
00765 
00766   std::fstream f;
00767   f.open(name.c_str(), std::fstream::in);
00768   
00769   if(f.is_open() == false)
00770     {
00771     x.reset();
00772     arma_extra_debug_print("unable to read ", name);
00773     }
00774   else
00775     {
00776     diskio::load_raw_ascii(x, name, f);
00777     f.close();
00778     }
00779   }
00780 
00781 //! Load a matrix as raw text (no header, human readable).
00782 //! Can read matrices saved as text in Matlab and Octave.
00783 //! NOTE: this is much slower than reading a file with a header.
00784 template<typename eT>
00785 inline
00786 void
00787 diskio::load_raw_ascii(Mat<eT>& x, const std::string& name, std::istream& f)
00788   {
00789   arma_extra_debug_sigprint();
00790 
00791   bool load_okay = true;
00792   
00793   //std::fstream::pos_type start = f.tellg();
00794   
00795   //
00796   // work out the size
00797   
00798   u32 f_n_rows = 0;
00799   u32 f_n_cols = 0;
00800   
00801   bool f_n_cols_found = false;
00802   
00803   std::string line_string;
00804   std::string token;
00805   
00806   while( (f.good() == true) && (load_okay == true) )
00807     {
00808     std::getline(f, line_string);
00809     if(line_string.size() == 0)
00810       break;
00811     
00812     std::stringstream line_stream(line_string);
00813     
00814     u32 line_n_cols = 0;
00815     while (line_stream >> token)
00816       line_n_cols++;
00817     
00818     if(f_n_cols_found == false)
00819       {
00820       f_n_cols = line_n_cols;
00821       f_n_cols_found = true;
00822       }
00823     else
00824       {
00825       if(line_n_cols != f_n_cols)
00826         {
00827         arma_print("inconsistent number of columns in ", name );
00828         load_okay = false;
00829         }
00830       }
00831     
00832     ++f_n_rows;
00833     }
00834     
00835   if(load_okay == true)
00836     {
00837     f.clear();
00838     f.seekg(0, ios::beg);
00839     //f.seekg(start);
00840     
00841     x.set_size(f_n_rows, f_n_cols);
00842   
00843     eT val;
00844     
00845     for(u32 row=0; row < x.n_rows; ++row)
00846       {
00847       for(u32 col=0; col < x.n_cols; ++col)
00848         {
00849         // f >> token;
00850         // x.at(row,col) = eT( strtod(token.c_str(), 0) );
00851         
00852         f >> val;
00853         x.at(row,col) = val;
00854         }
00855       }
00856     }
00857   
00858   if(f.good() == false)
00859     {
00860     arma_print("trouble reading ", name );
00861     load_okay = false; 
00862     }
00863   
00864   if(load_okay == false)
00865     {
00866     x.reset();
00867     }
00868   }
00869 
00870 
00871 
00872 //! Load a matrix in text format (human readable),
00873 //! with a header that indicates the matrix type as well as its dimensions
00874 template<typename eT>
00875 inline
00876 void
00877 diskio::load_arma_ascii(Mat<eT>& x, const std::string& name)
00878   {
00879   arma_extra_debug_sigprint();
00880   
00881   std::ifstream f(name.c_str());
00882   if(f.is_open() == false)
00883     {
00884     x.reset();
00885     arma_extra_debug_print("unable to read ", name);
00886     }
00887   else
00888     {
00889     diskio::load_arma_ascii(x, name, f);
00890     f.close();
00891     }
00892   }
00893   
00894 
00895 
00896 //! Load a matrix in text format (human readable),
00897 //! with a header that indicates the matrix type as well as its dimensions
00898 template<typename eT>
00899 inline
00900 void
00901 diskio::load_arma_ascii(Mat<eT>& x, const std::string& name, std::istream& f)
00902   {
00903   arma_extra_debug_sigprint();
00904   
00905   bool load_okay = true;
00906   
00907   std::string f_header;
00908   u32 f_n_rows;
00909   u32 f_n_cols;
00910   
00911   f >> f_header;
00912   f >> f_n_rows;
00913   f >> f_n_cols;
00914   
00915   if(f_header == diskio::gen_txt_header(x))
00916     {
00917     x.set_size(f_n_rows, f_n_cols);
00918     
00919     for(u32 row=0; row < x.n_rows; ++row)
00920       {
00921       for(u32 col=0; col < x.n_cols; ++col)
00922         {
00923         f >> x.at(row,col);
00924         }
00925       }
00926     
00927     if(f.good() == false)
00928       {
00929       arma_print("trouble reading ", name);
00930       load_okay = false;
00931       }
00932     }
00933   else
00934     {
00935     arma_print("incorrect header in ", name );
00936     load_okay = false;
00937     } 
00938   
00939   if(load_okay == false)
00940     {
00941     x.reset();
00942     }
00943   }
00944 
00945 
00946 
00947 //! Load a matrix in binary format,
00948 //! with a header that indicates the matrix type as well as its dimensions
00949 template<typename eT>
00950 inline
00951 void
00952 diskio::load_arma_binary(Mat<eT>& x, const std::string& name)
00953   {
00954   arma_extra_debug_sigprint();
00955   
00956   std::ifstream f;
00957   f.open(name.c_str(), std::fstream::binary);
00958   
00959   if(f.is_open() == false)
00960     {
00961     x.reset();
00962     arma_extra_debug_print("unable to read ", name);
00963     }
00964   else
00965     {
00966     diskio::load_arma_binary(x, name, f);
00967     f.close();
00968     }
00969   }
00970 
00971 
00972 
00973 template<typename eT>
00974 inline
00975 void
00976 diskio::load_arma_binary(Mat<eT>& x, const std::string& name, std::istream& f)
00977   {
00978   arma_extra_debug_sigprint();
00979   
00980   bool load_okay = true;
00981   
00982   std::string f_header;
00983   u32 f_n_rows;
00984   u32 f_n_cols;
00985   
00986   f >> f_header;
00987   f >> f_n_rows;
00988   f >> f_n_cols;
00989   
00990   if(f_header == diskio::gen_bin_header(x))
00991     {
00992     //f.seekg(1, ios::cur);  // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
00993     f.get();
00994     
00995     x.set_size(f_n_rows,f_n_cols);
00996     f.read( reinterpret_cast<char *>(x.memptr()), x.n_elem*sizeof(eT));
00997     
00998     if(f.good() == false)
00999       {
01000       arma_print("trouble reading ", name);
01001       load_okay = false;
01002       }
01003     }
01004   else
01005     {
01006     arma_print("incorrect header in ", name);
01007     load_okay = false;
01008     }
01009   
01010   if(load_okay == false)
01011     {
01012     x.reset();
01013     }
01014   }
01015 
01016 
01017 
01018 inline
01019 void
01020 diskio::pnm_skip_comments(std::istream& f)
01021   {
01022   while( isspace(f.peek()) )
01023     {
01024     while( isspace(f.peek()) )
01025       {
01026       f.get();
01027       }
01028   
01029     if(f.peek() == '#')
01030       {
01031       while( (f.peek() != '\r') && (f.peek()!='\n') )
01032         {
01033         f.get();
01034         }
01035       }
01036     }
01037   }
01038 
01039 
01040 
01041 //! Load a PGM greyscale image as a matrix
01042 template<typename eT>
01043 inline
01044 void
01045 diskio::load_pgm_binary(Mat<eT>& x, const std::string& name)
01046   {
01047   arma_extra_debug_sigprint();
01048   
01049   std::fstream f;
01050   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01051   
01052   if(f.is_open() == false)
01053     {
01054     arma_extra_debug_print("unable to read ", name);
01055     x.reset();
01056     }
01057   else
01058     {
01059     diskio::load_pgm_binary(x, name, f); // Do the actual load
01060     f.close();
01061     }
01062   }
01063 
01064 
01065 
01066 //! Load a PGM greyscale image as a matrix
01067 template<typename eT>
01068 inline
01069 void
01070 diskio::load_pgm_binary(Mat<eT>& x, const std::string& name, std::istream& f)
01071   {
01072   bool load_okay = true;
01073   
01074   std::string f_header;
01075   f >> f_header;
01076   
01077   if(f_header == "P5")
01078     {
01079     u32 f_n_rows = 0;
01080     u32 f_n_cols = 0;
01081     int f_maxval = 0;
01082   
01083     diskio::pnm_skip_comments(f);
01084   
01085     f >> f_n_cols;
01086     diskio::pnm_skip_comments(f);
01087   
01088     f >> f_n_rows;
01089     diskio::pnm_skip_comments(f);
01090   
01091     f >> f_maxval;
01092     f.get();
01093     
01094     if( (f_maxval > 0) || (f_maxval <= 65535) )
01095       {
01096       x.set_size(f_n_rows,f_n_cols);
01097       
01098       if(f_maxval <= 255)
01099         {
01100         const u32 n_elem = f_n_cols*f_n_rows;
01101         podarray<u8> tmp(n_elem);
01102         
01103         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
01104         
01105         u32 i = 0;
01106         
01107         //cout << "f_n_cols = " << f_n_cols << endl;
01108         //cout << "f_n_rows = " << f_n_rows << endl;
01109         
01110         
01111         for(u32 row=0; row < f_n_rows; ++row)
01112           {
01113           for(u32 col=0; col < f_n_cols; ++col)
01114             {
01115             x.at(row,col) = eT(tmp[i]);
01116             ++i;
01117             }
01118           }
01119           
01120         }
01121       else
01122         {
01123         const u32 n_elem = f_n_cols*f_n_rows;
01124         podarray<u16> tmp(n_elem);
01125         
01126         f.read( reinterpret_cast<char *>(tmp.memptr()), n_elem*2);
01127         
01128         u32 i = 0;
01129         
01130         for(u32 row=0; row < f_n_rows; ++row)
01131           {
01132           for(u32 col=0; col < f_n_cols; ++col)
01133             {
01134             x.at(row,col) = eT(tmp[i]);
01135             ++i;
01136             }
01137           }
01138         
01139         }
01140       
01141       }
01142     
01143     if(f.good() == false)
01144       {
01145       arma_print("trouble reading ", name);
01146       load_okay = false;
01147       }
01148     }
01149   else
01150     {
01151     arma_print("unsupported header in ", name);
01152     load_okay = false;
01153     }
01154   
01155   if(load_okay == false)
01156     {
01157     x.reset();
01158     }
01159   }
01160 
01161 
01162 
01163 //! Load a PGM greyscale image as a matrix
01164 template<typename T>
01165 inline
01166 void
01167 diskio::load_pgm_binary(Mat< std::complex<T> >& x, const std::string& name)
01168   {
01169   arma_extra_debug_sigprint();
01170   
01171   uchar_mat tmp;
01172   diskio::load_pgm_binary(tmp, name);
01173   x = conv_to< Mat< std::complex<T> > >::from(tmp);
01174   }
01175 
01176 
01177 
01178 //! Load a PGM greyscale image as a matrix
01179 template<typename T>
01180 inline
01181 void
01182 diskio::load_pgm_binary(Mat< std::complex<T> >& x, const std::string& name, std::istream& is)
01183   {
01184   arma_extra_debug_sigprint();
01185   
01186   uchar_mat tmp;
01187   diskio::load_pgm_binary(tmp, name, is);
01188   x = conv_to< Mat< std::complex<T> > >::from(tmp);
01189   }
01190 
01191 
01192 
01193 //! Try to load a matrix by automatically determining its type
01194 template<typename eT>
01195 inline
01196 void
01197 diskio::load_auto_detect(Mat<eT>& x, const std::string& name)
01198   {
01199   arma_extra_debug_sigprint();
01200   
01201   std::fstream f;
01202   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01203   
01204   if(f.is_open() == false)
01205     {
01206     arma_extra_debug_print("unable to read ", name);
01207     x.reset();
01208     }
01209   else
01210     {
01211     diskio::load_auto_detect(x, name, f); // Do the actual load
01212     f.close();
01213     }
01214   }
01215 
01216 
01217 //! Try to load a matrix by automatically determining its type
01218 template<typename eT>
01219 inline
01220 void
01221 diskio::load_auto_detect(Mat<eT>& x, const std::string& name, std::istream& f)
01222   {
01223   arma_extra_debug_sigprint();
01224   
01225   static const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT";
01226   static const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN";
01227   static const std::string           P5 = "P5";
01228   
01229   podarray<char> raw_header(ARMA_MAT_TXT.length() + 1);
01230   
01231   std::streampos pos = f.tellg();
01232     
01233   f.read(raw_header.memptr(), ARMA_MAT_TXT.length());
01234   raw_header[ARMA_MAT_TXT.length()] = '\0';
01235   
01236   f.clear();
01237   f.seekg(pos);
01238   
01239   const std::string header = raw_header.mem;
01240   
01241   if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length()))
01242     {
01243     load_arma_ascii(x, name, f);
01244     }
01245   else
01246   if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length()))
01247     {
01248     load_arma_binary(x, name, f);
01249     }
01250   else
01251   if(P5 == header.substr(0,P5.length()))
01252     {
01253     load_pgm_binary(x, name, f);
01254     }
01255   else
01256     {
01257     load_raw_ascii(x, name, f);
01258     }
01259   }
01260 
01261 
01262 
01263 // cubes
01264 
01265 
01266 
01267 //! Save a cube as raw text (no header, human readable).
01268 template<typename eT>
01269 inline
01270 void
01271 diskio::save_raw_ascii(const Cube<eT>& x, const std::string& final_name)
01272   {
01273   arma_extra_debug_sigprint();
01274   
01275   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01276   
01277   std::fstream f(tmp_name.c_str(), std::fstream::out);
01278   
01279   if(f.is_open() == false)
01280     {
01281     arma_print("unable to write ", tmp_name);
01282     }
01283   else
01284     {
01285     save_raw_ascii(x, tmp_name, f);
01286     
01287     const bool writing_problem = (f.good() == false);
01288     
01289     arma_warn(writing_problem, "trouble writing ", tmp_name );
01290     
01291     f.flush();
01292     f.close();
01293     
01294     if(writing_problem == false)
01295       {
01296       diskio::safe_rename(tmp_name, final_name);
01297       }
01298     }
01299   }
01300 
01301 
01302 
01303 //! Save a cube as raw text (no header, human readable).
01304 template<typename eT>
01305 inline
01306 void
01307 diskio::save_raw_ascii(const Cube<eT>& x, const std::string& name, std::ostream& f)
01308   {
01309   arma_extra_debug_sigprint();
01310   
01311   u32 cell_width;
01312   
01313   // TODO: need sane values for complex numbers
01314   
01315   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01316     {
01317     f.setf(ios::scientific);
01318     f.precision(8);
01319     cell_width = 16;
01320     }
01321   
01322   for(u32 slice=0; slice < x.n_slices; ++slice)
01323     {
01324     for(u32 row=0; row < x.n_rows; ++row)
01325       {
01326       for(u32 col=0; col < x.n_cols; ++col)
01327         {
01328         f.put(' ');
01329         
01330         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01331           {
01332           f.width(cell_width);
01333           }
01334         
01335         f << x.at(row,col,slice);
01336         }
01337         
01338       f.put('\n');
01339       }
01340     }
01341   }
01342 
01343 
01344 
01345 //! Save a cube in text format (human readable),
01346 //! with a header that indicates the cube type as well as its dimensions
01347 template<typename eT>
01348 inline
01349 void
01350 diskio::save_arma_ascii(const Cube<eT>& x, const std::string& final_name)
01351   {
01352   arma_extra_debug_sigprint();
01353   
01354   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01355   
01356   std::ofstream f(tmp_name.c_str());
01357   
01358   if(f.is_open() == false)
01359     {
01360     arma_debug_print("unable to write ", tmp_name);
01361     }
01362   else
01363     {
01364     diskio::save_arma_ascii(x, tmp_name, f);
01365     
01366     const bool writing_problem = (f.good() == false);
01367     
01368     f.flush();
01369     f.close();
01370     
01371     arma_warn( writing_problem, "trouble writing ", tmp_name );
01372     
01373     if(writing_problem == false)
01374       {
01375       diskio::safe_rename(tmp_name, final_name);
01376       }
01377     }
01378   }
01379 
01380 
01381 
01382 //! Save a cube in text format (human readable),
01383 //! with a header that indicates the cube type as well as its dimensions
01384 template<typename eT>
01385 inline
01386 void 
01387 diskio::save_arma_ascii(const Cube<eT>& x, const std::string& name, std::ostream& f)
01388   {
01389   arma_extra_debug_sigprint();
01390   
01391   const ios::fmtflags orig_flags = f.flags();
01392   
01393   f << diskio::gen_txt_header(x) << '\n';
01394   f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
01395   
01396   u32 cell_width;
01397   
01398   // TODO: need sane values for complex numbers
01399   
01400   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01401     {
01402     f.setf(ios::scientific);
01403     f.precision(8);
01404     cell_width = 16;
01405     }
01406     
01407   for(u32 slice=0; slice < x.n_slices; ++slice)
01408     {
01409     for(u32 row=0; row < x.n_rows; ++row)
01410       {
01411       for(u32 col=0; col < x.n_cols; ++col)
01412         {
01413         f.put(' ');
01414         
01415         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )        
01416           {
01417           f.width(cell_width);
01418           }
01419         
01420         f << x.at(row,col,slice);
01421         }
01422       
01423       f.put('\n');
01424       }
01425     }
01426   
01427   f.flags(orig_flags);
01428   }
01429 
01430 
01431 
01432 //! Save a cube in binary format,
01433 //! with a header that stores the cube type as well as its dimensions
01434 template<typename eT>
01435 inline
01436 void
01437 diskio::save_arma_binary(const Cube<eT>& x, const std::string& final_name)
01438   {
01439   arma_extra_debug_sigprint();
01440   
01441   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01442   
01443   std::ofstream f(tmp_name.c_str(), std::fstream::binary);
01444   
01445   if(f.is_open() == false)
01446     {
01447     arma_print("unable to write ", tmp_name);
01448     }
01449   else
01450     {
01451     diskio::save_arma_binary(x, tmp_name, f);
01452     
01453     const bool writing_problem = (f.good() == false);
01454     
01455     f.flush();
01456     f.close();
01457     
01458     arma_warn( writing_problem, "trouble writing ", tmp_name );
01459     
01460     if(writing_problem == false)
01461       {
01462       diskio::safe_rename(tmp_name, final_name);
01463       }
01464     }
01465   }
01466 
01467 
01468 
01469 //! Save a cube in binary format,
01470 //! with a header that stores the cube type as well as its dimensions
01471 template<typename eT>
01472 inline
01473 void
01474 diskio::save_arma_binary(const Cube<eT>& x, const std::string& name, std::ostream& f)
01475   {
01476   arma_extra_debug_sigprint();
01477   f << diskio::gen_bin_header(x) << '\n';
01478   f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
01479   
01480   f.write(reinterpret_cast<const char*>(x.mem), x.n_elem*sizeof(eT));
01481   }
01482 
01483 
01484 
01485 //! Load a cube as raw text (no header, human readable).
01486 //! NOTE: this is much slower than reading a file with a header.
01487 template<typename eT>
01488 inline
01489 void
01490 diskio::load_raw_ascii(Cube<eT>& x, const std::string& name)
01491   {
01492   arma_extra_debug_sigprint();
01493 
01494   Mat<eT> tmp;
01495   diskio::load_raw_ascii(tmp, name);
01496   
01497   x.set_size(tmp.n_rows, tmp.n_cols, 1);
01498 
01499   if(x.n_slices > 0)
01500     {
01501     x.slice(0) = tmp;
01502     }
01503   }
01504 
01505 
01506 
01507 //! Load a cube as raw text (no header, human readable).
01508 //! NOTE: this is much slower than reading a file with a header.
01509 template<typename eT>
01510 inline
01511 void
01512 diskio::load_raw_ascii(Cube<eT>& x, const std::string& name, std::istream& f)
01513   {
01514   arma_extra_debug_sigprint();
01515 
01516   Mat<eT> tmp;
01517   diskio::load_raw_ascii(tmp, name, f);
01518   
01519   x.set_size(tmp.n_rows, tmp.n_cols, 1);
01520 
01521   if(x.n_slices > 0)
01522     {
01523     x.slice(0) = tmp;
01524     }
01525   }
01526 
01527 
01528 
01529 //! Load a cube in text format (human readable),
01530 //! with a header that indicates the cube type as well as its dimensions
01531 template<typename eT>
01532 inline
01533 void
01534 diskio::load_arma_ascii(Cube<eT>& x, const std::string& name)
01535   {
01536   arma_extra_debug_sigprint();
01537   
01538   std::ifstream f(name.c_str());
01539   
01540   if(f.is_open() == false)
01541     {
01542     arma_extra_debug_print("unable to read ", name);
01543     }
01544   else
01545     {
01546     diskio::load_arma_ascii(x, name, f);
01547     f.close();
01548     }
01549   }
01550   
01551 
01552 
01553 //! Load a cube in text format (human readable),
01554 //! with a header that indicates the cube type as well as its dimensions
01555 template<typename eT>
01556 inline
01557 void
01558 diskio::load_arma_ascii(Cube<eT>& x, const std::string& name, std::istream& f)
01559   {
01560   arma_extra_debug_sigprint();
01561   
01562   bool load_okay = true;
01563   
01564   std::string f_header;
01565   u32 f_n_rows;
01566   u32 f_n_cols;
01567   u32 f_n_slices;
01568   
01569   f >> f_header;
01570   f >> f_n_rows;
01571   f >> f_n_cols;
01572   f >> f_n_slices;
01573   
01574   if(f_header == diskio::gen_txt_header(x))
01575     {
01576     x.set_size(f_n_rows, f_n_cols, f_n_slices);
01577 
01578     for(u32 slice=0; slice < x.n_slices; ++slice)
01579       {
01580       for(u32 row=0; row < x.n_rows; ++row)
01581         {
01582         for(u32 col=0; col < x.n_cols; ++col)
01583           {
01584           f >> x.at(row,col,slice);
01585           }
01586         }
01587       }
01588     
01589     if(f.good() == false)
01590       {
01591       arma_print("trouble reading ", name);
01592       load_okay = false;
01593       }
01594     }
01595   else
01596     {
01597     arma_print("incorrect header in ", name );
01598     load_okay = false;
01599     }
01600   
01601   if(load_okay == false)
01602     {
01603     x.reset();
01604     }
01605   }
01606 
01607 
01608 
01609 //! Load a cube in binary format,
01610 //! with a header that indicates the cube type as well as its dimensions
01611 template<typename eT>
01612 inline
01613 void
01614 diskio::load_arma_binary(Cube<eT>& x, const std::string& name)
01615   {
01616   arma_extra_debug_sigprint();
01617   
01618   std::ifstream f;
01619   f.open(name.c_str(), std::fstream::binary);
01620   
01621   if(f.is_open() == false)
01622     {
01623     arma_extra_debug_print("unable to read ", name);
01624     }
01625   else
01626     {
01627     diskio::load_arma_binary(x, name, f);
01628     f.close();
01629     }
01630   }
01631 
01632 
01633 
01634 template<typename eT>
01635 inline
01636 void
01637 diskio::load_arma_binary(Cube<eT>& x, const std::string& name, std::istream& f)
01638   {
01639   arma_extra_debug_sigprint();
01640   
01641   bool load_okay = true;
01642   
01643   std::string f_header;
01644   u32 f_n_rows;
01645   u32 f_n_cols;
01646   u32 f_n_slices;
01647   
01648   f >> f_header;
01649   f >> f_n_rows;
01650   f >> f_n_cols;
01651   f >> f_n_slices;
01652   
01653   if(f_header == diskio::gen_bin_header(x))
01654     {
01655     //f.seekg(1, ios::cur);  // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
01656     f.get();
01657     
01658     x.set_size(f_n_rows, f_n_cols, f_n_slices);
01659     f.read( reinterpret_cast<char *>(x.memptr()), x.n_elem*sizeof(eT));
01660     
01661     if(f.good() == false)
01662       {
01663       arma_print("trouble reading ", name);
01664       load_okay = false;
01665       }
01666     }
01667   else
01668     {
01669     arma_print("incorrect header in ", name);
01670     load_okay = false;
01671     }
01672   
01673   if(load_okay == false)
01674     {
01675     x.reset();
01676     }
01677   }
01678 
01679 
01680 
01681 //! Try to load a cube by automatically determining its type
01682 template<typename eT>
01683 inline
01684 void
01685 diskio::load_auto_detect(Cube<eT>& x, const std::string& name)
01686   {
01687   arma_extra_debug_sigprint();
01688   
01689   std::fstream f;
01690   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01691   
01692   if(f.is_open() == false)
01693     {
01694     arma_extra_debug_print("unable to read ", name);
01695     x.reset();
01696     }
01697   else
01698     {
01699     diskio::load_auto_detect(x, name, f); // Do the actual load
01700     f.close();
01701     }
01702   }
01703 
01704 
01705 
01706 //! Try to load a cube by automatically determining its type
01707 template<typename eT>
01708 inline
01709 void
01710 diskio::load_auto_detect(Cube<eT>& x, const std::string& name, std::istream& f)
01711   {
01712   arma_extra_debug_sigprint();
01713   
01714   static const std::string ARMA_CUB_TXT = "ARMA_CUB_TXT";
01715   static const std::string ARMA_CUB_BIN = "ARMA_CUB_BIN";
01716   static const std::string           P6 = "P6";
01717   
01718   podarray<char> raw_header(ARMA_CUB_TXT.length() + 1);
01719   
01720   std::streampos pos = f.tellg();
01721   
01722   f.read(raw_header.memptr(), ARMA_CUB_TXT.length());
01723   raw_header[ARMA_CUB_TXT.length()] = '\0';
01724   
01725   f.clear();
01726   f.seekg(pos);
01727   
01728   const std::string header = raw_header.mem;
01729   
01730   if(ARMA_CUB_TXT == header.substr(0, ARMA_CUB_TXT.length()))
01731     {
01732     load_arma_ascii(x, name, f);
01733     }
01734   else
01735   if(ARMA_CUB_BIN == header.substr(0, ARMA_CUB_BIN.length()))
01736     {
01737     load_arma_binary(x, name, f);
01738     }
01739   else
01740   if(P6 == header.substr(0,P6.length()))
01741     {
01742     load_ppm_binary(x, name, f);
01743     }
01744   else
01745     {
01746     load_raw_ascii(x, name, f);
01747     }
01748   }
01749 
01750 
01751 
01752 
01753 
01754 // fields
01755 
01756 
01757 
01758 template<typename T1>
01759 inline
01760 void
01761 diskio::save_arma_binary(const field<T1>& x, const std::string& final_name)
01762   {
01763   arma_extra_debug_sigprint();
01764   
01765   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01766   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01767   
01768   if(f.is_open() == false)
01769     {
01770     arma_print("couldn't write ", tmp_name);
01771     }
01772   else
01773     {
01774     diskio::save_arma_binary(x, tmp_name, f);
01775 
01776     const bool writing_problem = (f.good() == false);
01777 
01778     arma_warn(writing_problem, "trouble writing ", tmp_name );
01779 
01780     f.flush();
01781     f.close();
01782 
01783     if(writing_problem == false)
01784       {
01785       diskio::safe_rename(tmp_name, final_name);
01786       }
01787     }
01788   }
01789 
01790 template<typename T1>
01791 inline
01792 void
01793 diskio::save_arma_binary(const field<T1>& x, const std::string& name, std::ostream& f)
01794   {
01795   arma_extra_debug_sigprint();
01796   
01797   arma_type_check< (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) >::apply();
01798   
01799   f << "ARMA_FLD_BIN" << '\n';
01800   f << x.n_rows << '\n';
01801   f << x.n_cols << '\n';
01802   
01803   for(u32 i=0; i<x.n_elem; ++i)
01804     {
01805     diskio::save_arma_binary(x[i], name, f);
01806     }
01807   }
01808 
01809 
01810 
01811 template<typename T1>
01812 inline
01813 void
01814 diskio::load_arma_binary(field<T1>& x, const std::string& name)
01815   {
01816   arma_extra_debug_sigprint();
01817   
01818   std::ifstream f( name.c_str(), std::fstream::binary );
01819   
01820   if(f.is_open() == false)
01821     {
01822     arma_extra_debug_print("unable to read ", name);
01823     }
01824   else
01825     {
01826     diskio::load_arma_binary(x, name, f);
01827     f.close();
01828     }
01829   }
01830 
01831 
01832 
01833 template<typename T1>
01834 inline
01835 void
01836 diskio::load_arma_binary(field<T1>& x, const std::string& name, std::istream& f)
01837   {
01838   arma_extra_debug_sigprint();
01839   
01840   arma_type_check< (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) >::apply();
01841   
01842   bool load_okay = true;
01843   
01844   std::string f_type;
01845   f >> f_type;
01846   
01847   if(f_type != "ARMA_FLD_BIN")
01848     {
01849     arma_print("unsupported field type in ", name);
01850     load_okay = false;
01851     }
01852   else
01853     {
01854     u32 f_n_rows;
01855     u32 f_n_cols;
01856   
01857     f >> f_n_rows;
01858     f >> f_n_cols;
01859     
01860     x.set_size(f_n_rows, f_n_cols);
01861     
01862     f.get();      
01863     
01864     for(u32 i=0; i<x.n_elem; ++i)
01865       {
01866       diskio::load_arma_binary(x[i], name, f);
01867       
01868       if(f.good() == false)
01869         {
01870         arma_print("trouble reading ", name);
01871         load_okay = false;
01872         break;
01873         }
01874       }
01875     }
01876 
01877   if(load_okay == false)
01878     {
01879     x.reset();
01880     }
01881   }
01882 
01883 
01884 
01885 inline
01886 void
01887 diskio::save_std_string(const field<std::string>& x, const std::string& final_name)
01888   {
01889   arma_extra_debug_sigprint();
01890   
01891   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01892   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01893   
01894   if(f.is_open() == false)
01895     {
01896     arma_print("couldn't write ", tmp_name);
01897     }
01898   else
01899     {
01900     diskio::save_std_string(x, tmp_name, f);
01901     
01902     const bool writing_problem = (f.good() == false);
01903     
01904     f.flush();
01905     f.close();
01906     
01907     if(writing_problem == false)
01908       {
01909       diskio::safe_rename(tmp_name, final_name);
01910       }
01911     }
01912   }
01913 
01914 
01915 
01916 inline
01917 void
01918 diskio::save_std_string(const field<std::string>& x, const std::string& name, std::ostream& f)
01919   {
01920   arma_extra_debug_sigprint();
01921   
01922   for(u32 row=0; row<x.n_rows; ++row)
01923   for(u32 col=0; col<x.n_cols; ++col)
01924     {
01925     f << x.at(row,col);
01926     
01927     if(col < x.n_cols-1)
01928       {
01929       f << ' ';
01930       }
01931     else
01932       {
01933       f << '\n';
01934       }
01935     }
01936   
01937   const bool writing_problem = (f.good() == false);
01938   
01939   arma_warn(writing_problem, "trouble writing ", name );
01940   }
01941 
01942 
01943 
01944 inline
01945 void
01946 diskio::load_std_string(field<std::string>& x, const std::string& name)
01947   {
01948   arma_extra_debug_sigprint();
01949   
01950   std::ifstream f( name.c_str() );
01951   
01952   if(f.is_open() == false)
01953     {
01954     arma_print("unable to read ", name);
01955     }
01956   else
01957     {
01958     diskio::load_std_string(x, name, f);
01959     
01960     f.close();
01961     }
01962   }
01963 
01964 
01965 
01966 inline
01967 void
01968 diskio::load_std_string(field<std::string>& x, const std::string& name, std::istream& f)
01969   {
01970   arma_extra_debug_sigprint();
01971   
01972   bool load_okay = true;
01973   
01974   //
01975   // work out the size
01976   
01977   u32 f_n_rows = 0;
01978   u32 f_n_cols = 0;
01979   
01980   bool f_n_cols_found = false;
01981   
01982   std::string line_string;
01983   std::string token;
01984   
01985   while( (f.good() == true) && (load_okay == true) )
01986     {
01987     std::getline(f, line_string);
01988     if(line_string.size() == 0)
01989       break;
01990     
01991     std::stringstream line_stream(line_string);
01992     
01993     u32 line_n_cols = 0;
01994     while (line_stream >> token)
01995       line_n_cols++;
01996     
01997     if(f_n_cols_found == false)
01998       {
01999       f_n_cols = line_n_cols;
02000       f_n_cols_found = true;
02001       }
02002     else
02003       {
02004       if(line_n_cols != f_n_cols)
02005         {
02006         load_okay = false;
02007         arma_print("inconsistent number of columns in ", name );
02008         }
02009       }
02010     
02011     ++f_n_rows;
02012     }
02013     
02014   if(load_okay == true)
02015     {
02016     f.clear();
02017     f.seekg(0, ios::beg);
02018     //f.seekg(start);
02019     
02020     x.set_size(f_n_rows, f_n_cols);
02021   
02022     for(u32 row=0; row < x.n_rows; ++row)
02023       {
02024       for(u32 col=0; col < x.n_cols; ++col)
02025         {
02026         f >> x.at(row,col);
02027         }
02028       }
02029     }
02030   
02031   if(f.good() == false)
02032     {
02033     load_okay = false; 
02034     arma_print("trouble reading ", name );
02035     }
02036   
02037   if(load_okay == false)
02038     {
02039     x.reset();
02040     }
02041   }
02042 
02043 
02044 
02045 //! Try to load a field by automatically determining its type
02046 template<typename T1>
02047 inline
02048 void
02049 diskio::load_auto_detect(field<T1>& x, const std::string& name)
02050   {
02051   arma_extra_debug_sigprint();
02052   
02053   std::fstream f;
02054   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02055   
02056   if(f.is_open() == false)
02057     {
02058     arma_extra_debug_print("unable to read ", name);
02059     x.reset();
02060     }
02061   else
02062     {
02063     diskio::load_auto_detect(x, name, f); // Do the actual load
02064     f.close();
02065     }
02066   }
02067 
02068 
02069 
02070 //! Try to load a field by automatically determining its type
02071 template<typename T1>
02072 inline
02073 void
02074 diskio::load_auto_detect(field<T1>& x, const std::string& name, std::istream& f)
02075   {
02076   arma_extra_debug_sigprint();
02077   
02078   arma_type_check<is_Mat<T1>::value == false>::apply();
02079   
02080   static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN";
02081   static const std::string           P6 = "P6";
02082   
02083   podarray<char> raw_header(ARMA_FLD_BIN.length() + 1);
02084   
02085   std::streampos pos = f.tellg();
02086   
02087   f.read(raw_header.memptr(), ARMA_FLD_BIN.length());
02088   
02089   f.clear();
02090   f.seekg(pos);
02091   
02092   raw_header[ARMA_FLD_BIN.length()] = '\0';
02093   
02094   const std::string header = raw_header.mem;
02095   
02096   if(ARMA_FLD_BIN == header.substr(0,ARMA_FLD_BIN.length()))
02097     {
02098     load_arma_binary(x, name, f);
02099     }
02100   else
02101   if(P6 == header.substr(0,P6.length()))
02102     {
02103     load_ppm_binary(x, name, f);
02104     }
02105   else
02106     {
02107     arma_print("unsupported header in ", name);
02108     x.reset();
02109     }
02110   }
02111 
02112 
02113 
02114 //
02115 // handling of PPM images
02116 
02117 
02118 template<typename eT>
02119 inline
02120 void
02121 diskio::load_ppm_binary(Cube<eT>& x, const std::string& name)
02122   {
02123   arma_extra_debug_sigprint();
02124   
02125   std::fstream f;
02126   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02127   
02128   if(f.is_open() == false)
02129     {
02130     arma_extra_debug_print("unable to read ", name);
02131     }
02132   else
02133     {
02134     diskio::load_ppm_binary(x, name, f);
02135     f.close();
02136     }
02137   }
02138 
02139 
02140 
02141 template<typename eT>
02142 inline
02143 void
02144 diskio::load_ppm_binary(Cube<eT>& x, const std::string& name, std::istream& f)
02145   {
02146   arma_extra_debug_sigprint();
02147   
02148   bool load_okay = true;
02149   
02150   std::string f_header;
02151   f >> f_header;
02152   
02153   if(f_header == "P6")
02154     {
02155     u32 f_n_rows = 0;
02156     u32 f_n_cols = 0;
02157     int f_maxval = 0;
02158   
02159     diskio::pnm_skip_comments(f);
02160   
02161     f >> f_n_cols;
02162     diskio::pnm_skip_comments(f);
02163   
02164     f >> f_n_rows;
02165     diskio::pnm_skip_comments(f);
02166   
02167     f >> f_maxval;
02168     f.get();
02169     
02170     if( (f_maxval > 0) || (f_maxval <= 65535) )
02171       {
02172       x.set_size(f_n_rows, f_n_cols, 3);
02173       
02174       if(f_maxval <= 255)
02175         {
02176         const u32 n_elem = 3*f_n_cols*f_n_rows;
02177         podarray<u8> tmp(n_elem);
02178         
02179         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
02180         
02181         u32 i = 0;
02182         
02183         //cout << "f_n_cols = " << f_n_cols << endl;
02184         //cout << "f_n_rows = " << f_n_rows << endl;
02185         
02186         
02187         for(u32 row=0; row < f_n_rows; ++row)
02188           {
02189           for(u32 col=0; col < f_n_cols; ++col)
02190             {
02191             x.at(row,col,0) = eT(tmp[i+0]);
02192             x.at(row,col,1) = eT(tmp[i+1]);
02193             x.at(row,col,2) = eT(tmp[i+2]);
02194             i+=3;
02195             }
02196           
02197           }
02198         }
02199       else
02200         {
02201         const u32 n_elem = 3*f_n_cols*f_n_rows;
02202         podarray<u16> tmp(n_elem);
02203         
02204         f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
02205         
02206         u32 i = 0;
02207         
02208         for(u32 row=0; row < f_n_rows; ++row)
02209           {
02210           for(u32 col=0; col < f_n_cols; ++col)
02211             {
02212             x.at(row,col,0) = eT(tmp[i+0]);
02213             x.at(row,col,1) = eT(tmp[i+1]);
02214             x.at(row,col,2) = eT(tmp[i+2]);
02215             i+=3;
02216             }
02217           
02218           }
02219         
02220         }
02221       
02222       }
02223     
02224     if(f.good() == false)
02225       {
02226       arma_print("trouble reading ", name);
02227       load_okay = false;
02228       }
02229     
02230     }
02231   else
02232     {
02233     arma_print("unsupported header in ", name);
02234     load_okay = false;
02235     }
02236   
02237   if(load_okay == false)
02238     {
02239     x.reset();
02240     }
02241   }
02242 
02243 
02244 
02245 template<typename eT>
02246 inline
02247 void
02248 diskio::save_ppm_binary(const Cube<eT>& x, const std::string& final_name)
02249   {
02250   arma_extra_debug_sigprint();
02251 
02252   const std::string tmp_name = diskio::gen_tmp_name(final_name);
02253   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
02254   
02255   if(f.is_open() == false)
02256     {
02257     arma_print("couldn't write ", tmp_name);
02258     }
02259   else
02260     {
02261     diskio::save_ppm_binary(x, tmp_name, f);
02262     
02263     const bool writing_problem = (f.good() == false);
02264     f.flush();
02265     f.close();
02266     
02267     if(writing_problem == false)
02268       {
02269       diskio::safe_rename(tmp_name, final_name);
02270       }
02271     }
02272   }
02273 
02274 
02275 
02276 template<typename eT>
02277 inline
02278 void
02279 diskio::save_ppm_binary(const Cube<eT>& x, const std::string& name, std::ostream& f)
02280   {
02281   arma_extra_debug_sigprint();
02282   
02283   arma_debug_check( (x.n_slices != 3), "diskio::save_ppm_binary(): given cube must have exactly 3 slices" );
02284   
02285   const u32 n_elem = 3 * x.n_rows * x.n_cols;
02286   podarray<u8> tmp(n_elem);
02287 
02288   u32 i = 0;
02289   for(u32 row=0; row < x.n_rows; ++row)
02290     {
02291     for(u32 col=0; col < x.n_cols; ++col)
02292       {
02293       tmp[i+0] = u8( x.at(row,col,0) );
02294       tmp[i+1] = u8( x.at(row,col,1) );
02295       tmp[i+2] = u8( x.at(row,col,2) );
02296       
02297       i+=3;
02298       }
02299     }
02300   
02301   f << "P6" << '\n';
02302   f << x.n_cols << '\n';
02303   f << x.n_rows << '\n';
02304   f << 255 << '\n';
02305 
02306   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
02307   
02308   const bool writing_problem = (f.good() == false);
02309   
02310   arma_warn(writing_problem, "trouble writing ", name );
02311   }
02312 
02313 
02314 
02315 template<typename T1>
02316 inline
02317 void
02318 diskio::load_ppm_binary(field<T1>& x, const std::string& name)
02319   {
02320   arma_extra_debug_sigprint();
02321   
02322   std::fstream f;
02323   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02324   
02325   if(f.is_open() == false)
02326     {
02327     arma_extra_debug_print("unable to read ", name);
02328     }
02329   else
02330     {
02331     diskio::load_ppm_binary(x, name, f);
02332     f.close();
02333     }
02334   }  
02335 
02336 
02337 
02338 template<typename T1>
02339 inline
02340 void
02341 diskio::load_ppm_binary(field<T1>& x, const std::string& name, std::istream& f)
02342   {
02343   arma_extra_debug_sigprint();
02344   
02345   arma_type_check<is_Mat<T1>::value == false>::apply();
02346   typedef typename T1::elem_type eT;
02347   
02348   bool load_okay = true;
02349   
02350   std::string f_header;
02351   f >> f_header;
02352   
02353   if(f_header == "P6")
02354     {
02355     u32 f_n_rows = 0;
02356     u32 f_n_cols = 0;
02357     int f_maxval = 0;
02358   
02359     diskio::pnm_skip_comments(f);
02360   
02361     f >> f_n_cols;
02362     diskio::pnm_skip_comments(f);
02363   
02364     f >> f_n_rows;
02365     diskio::pnm_skip_comments(f);
02366   
02367     f >> f_maxval;
02368     f.get();
02369     
02370     if( (f_maxval > 0) || (f_maxval <= 65535) )
02371       {
02372       x.set_size(3);
02373       Mat<eT>& R = x(0);
02374       Mat<eT>& G = x(1);
02375       Mat<eT>& B = x(2);
02376       
02377       R.set_size(f_n_rows,f_n_cols);
02378       G.set_size(f_n_rows,f_n_cols);
02379       B.set_size(f_n_rows,f_n_cols);
02380       
02381       if(f_maxval <= 255)
02382         {
02383         const u32 n_elem = 3*f_n_cols*f_n_rows;
02384         podarray<u8> tmp(n_elem);
02385         
02386         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
02387         
02388         u32 i = 0;
02389         
02390         //cout << "f_n_cols = " << f_n_cols << endl;
02391         //cout << "f_n_rows = " << f_n_rows << endl;
02392         
02393         
02394         for(u32 row=0; row < f_n_rows; ++row)
02395           {
02396           for(u32 col=0; col < f_n_cols; ++col)
02397             {
02398             R.at(row,col) = eT(tmp[i+0]);
02399             G.at(row,col) = eT(tmp[i+1]);
02400             B.at(row,col) = eT(tmp[i+2]);
02401             i+=3;
02402             }
02403           
02404           }
02405         }
02406       else
02407         {
02408         const u32 n_elem = 3*f_n_cols*f_n_rows;
02409         podarray<u16> tmp(n_elem);
02410         
02411         f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
02412         
02413         u32 i = 0;
02414         
02415         for(u32 row=0; row < f_n_rows; ++row)
02416           {
02417           for(u32 col=0; col < f_n_cols; ++col)
02418             {
02419             R.at(row,col) = eT(tmp[i+0]);
02420             G.at(row,col) = eT(tmp[i+1]);
02421             B.at(row,col) = eT(tmp[i+2]);
02422             i+=3;
02423             }
02424           
02425           }
02426         
02427         }
02428       
02429       }
02430     
02431     if(f.good() == false)
02432       {
02433       arma_print("trouble reading ", name);
02434       load_okay = false;
02435       }
02436     
02437     }
02438   else
02439     {
02440     arma_print("unsupported header in ", name);
02441     load_okay = false;
02442     }
02443   
02444   if(load_okay == false)
02445     {
02446     x.reset();
02447     }
02448   
02449   }
02450 
02451 
02452 
02453 template<typename T1>
02454 inline
02455 void
02456 diskio::save_ppm_binary(const field<T1>& x, const std::string& final_name)
02457   {
02458   arma_extra_debug_sigprint();
02459   
02460   const std::string tmp_name = diskio::gen_tmp_name(final_name);
02461   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
02462   
02463   if(f.is_open() == false)
02464     {
02465     arma_print("couldn't write ", tmp_name);
02466     }
02467   else
02468     {
02469     diskio::save_ppm_binary(x, tmp_name, f);
02470     const bool writing_problem = (f.good() == false);
02471     
02472     f.flush();
02473     f.close();
02474     
02475     if(writing_problem == false)
02476       {
02477       diskio::safe_rename(tmp_name, final_name);
02478       }
02479     }
02480   }
02481   
02482 
02483 
02484 template<typename T1>
02485 inline
02486 void
02487 diskio::save_ppm_binary(const field<T1>& x, const std::string& name, std::ostream& f)
02488   {
02489   arma_extra_debug_sigprint();
02490   
02491   arma_type_check<is_Mat<T1>::value == false>::apply();
02492   
02493   typedef typename T1::elem_type eT;
02494   
02495   arma_debug_check( (x.n_elem != 3), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
02496   
02497   bool same_size = true;
02498   for(u32 i=1; i<3; ++i)
02499     {
02500     if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) )
02501       {
02502       same_size = false;
02503       break;
02504       }
02505     }
02506   
02507   arma_debug_check( (same_size != true), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
02508   
02509   const Mat<eT>& R = x(0);
02510   const Mat<eT>& G = x(1);
02511   const Mat<eT>& B = x(2);
02512   
02513   f << "P6" << '\n';
02514   f << R.n_cols << '\n';
02515   f << R.n_rows << '\n';
02516   f << 255 << '\n';
02517 
02518   const u32 n_elem = 3 * R.n_rows * R.n_cols;
02519   podarray<u8> tmp(n_elem);
02520 
02521   u32 i = 0;
02522   for(u32 row=0; row < R.n_rows; ++row)
02523     {
02524     for(u32 col=0; col < R.n_cols; ++col)
02525       {
02526       tmp[i+0] = u8( access::tmp_real( R.at(row,col) ) );
02527       tmp[i+1] = u8( access::tmp_real( G.at(row,col) ) );
02528       tmp[i+2] = u8( access::tmp_real( B.at(row,col) ) );
02529       
02530       i+=3;
02531       }
02532     }
02533   
02534   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
02535   
02536   const bool writing_problem = (f.good() == false);
02537   
02538   arma_warn(writing_problem, "trouble writing ", name );
02539   }
02540 
02541 
02542 
02543 //! @}
02544