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 bool
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   bool save_okay = f.good();
00426   f.close();
00427   
00428   if(save_okay == true)
00429     {
00430     std::remove(new_name.c_str());
00431     
00432     const int mv_result = std::rename(old_name.c_str(), new_name.c_str());
00433     
00434     save_okay = (mv_result == 0);
00435     }
00436   
00437   return save_okay;
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 bool
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   bool save_okay = f.is_open();
00456   
00457   if(save_okay == true)
00458     {
00459     save_okay = diskio::save_raw_ascii(x, f);
00460     
00461     f.flush();
00462     f.close();
00463     
00464     if(save_okay == true)
00465       {
00466       save_okay = diskio::safe_rename(tmp_name, final_name);
00467       }
00468     }
00469   
00470   return save_okay;
00471   }
00472 
00473 
00474 
00475 //! Save a matrix as raw text (no header, human readable).
00476 //! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements.
00477 template<typename eT>
00478 inline
00479 bool
00480 diskio::save_raw_ascii(const Mat<eT>& x, std::ostream& f)
00481   {
00482   arma_extra_debug_sigprint();
00483   
00484   u32 cell_width;
00485   
00486   // TODO: need sane values for complex numbers
00487   
00488   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00489     {
00490     f.setf(ios::scientific);
00491     f.precision(8);
00492     cell_width = 16;
00493     }
00494   
00495   for(u32 row=0; row < x.n_rows; ++row)
00496     {
00497     for(u32 col=0; col < x.n_cols; ++col)
00498       {
00499       f.put(' ');
00500       
00501       if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00502         {
00503         f.width(cell_width);
00504         }
00505       
00506       f << x.at(row,col);
00507       }
00508       
00509     f.put('\n');
00510     }
00511   
00512   return f.good();
00513   }
00514 
00515 
00516 
00517 //! Save a matrix in text format (human readable),
00518 //! with a header that indicates the matrix type as well as its dimensions
00519 template<typename eT>
00520 inline
00521 bool
00522 diskio::save_arma_ascii(const Mat<eT>& x, const std::string& final_name)
00523   {
00524   arma_extra_debug_sigprint();
00525   
00526   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00527   
00528   std::ofstream f(tmp_name.c_str());
00529   
00530   bool save_okay = f.is_open();
00531 
00532   if(save_okay == true)  
00533     {
00534     save_okay = diskio::save_arma_ascii(x, f);
00535     
00536     f.flush();
00537     f.close();
00538     
00539     if(save_okay == true)
00540       {
00541       save_okay = diskio::safe_rename(tmp_name, final_name);
00542       }
00543     }
00544   
00545   return save_okay;
00546   }
00547 
00548 
00549 
00550 //! Save a matrix in text format (human readable),
00551 //! with a header that indicates the matrix type as well as its dimensions
00552 template<typename eT>
00553 inline
00554 bool
00555 diskio::save_arma_ascii(const Mat<eT>& x, std::ostream& f)
00556   {
00557   arma_extra_debug_sigprint();
00558   
00559   const ios::fmtflags orig_flags = f.flags();
00560   
00561   f << diskio::gen_txt_header(x) << '\n';
00562   f << x.n_rows << ' ' << x.n_cols << '\n';
00563   
00564   u32 cell_width;
00565   
00566   // TODO: need sane values for complex numbers
00567   
00568   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
00569     {
00570     f.setf(ios::scientific);
00571     f.precision(8);
00572     cell_width = 16;
00573     }
00574     
00575   for(u32 row=0; row < x.n_rows; ++row)
00576     {
00577     for(u32 col=0; col < x.n_cols; ++col)
00578       {
00579       f.put(' ');
00580       
00581       if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )        
00582         {
00583         f.width(cell_width);
00584         }
00585       
00586       f << x.at(row,col);
00587       }
00588     
00589     f.put('\n');
00590     }
00591   
00592   const bool save_okay = f.good();
00593   
00594   f.flags(orig_flags);
00595   
00596   return save_okay;
00597   }
00598 
00599 
00600 
00601 //! Save a matrix in binary format,
00602 //! with a header that stores the matrix type as well as its dimensions
00603 template<typename eT>
00604 inline
00605 bool
00606 diskio::save_arma_binary(const Mat<eT>& x, const std::string& final_name)
00607   {
00608   arma_extra_debug_sigprint();
00609   
00610   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00611   
00612   std::ofstream f(tmp_name.c_str(), std::fstream::binary);
00613   
00614   bool save_okay = f.is_open();
00615   
00616   if(save_okay == true)
00617     {
00618     save_okay = diskio::save_arma_binary(x, f);
00619     
00620     f.flush();
00621     f.close();
00622     
00623     if(save_okay == true)
00624       {
00625       save_okay = diskio::safe_rename(tmp_name, final_name);
00626       }
00627     }
00628   
00629   return save_okay;
00630   }
00631 
00632 
00633 
00634 //! Save a matrix in binary format,
00635 //! with a header that stores the matrix type as well as its dimensions
00636 template<typename eT>
00637 inline
00638 bool
00639 diskio::save_arma_binary(const Mat<eT>& x, std::ostream& f)
00640   {
00641   arma_extra_debug_sigprint();
00642 
00643   f << diskio::gen_bin_header(x) << '\n';
00644   f << x.n_rows << ' ' << x.n_cols << '\n';
00645   
00646   f.write(reinterpret_cast<const char*>(x.mem), x.n_elem*sizeof(eT));
00647   
00648   return f.good();
00649   }
00650 
00651 
00652 
00653 //! Save a matrix as a PGM greyscale image
00654 template<typename eT>
00655 inline
00656 bool
00657 diskio::save_pgm_binary(const Mat<eT>& x, const std::string& final_name)
00658   {
00659   arma_extra_debug_sigprint();
00660   
00661   const std::string tmp_name = diskio::gen_tmp_name(final_name);
00662   
00663   std::fstream f(tmp_name.c_str(), std::fstream::out | std::fstream::binary);
00664   
00665   bool save_okay = f.is_open();
00666   
00667   if(save_okay == true)
00668     {
00669     save_okay = diskio::save_pgm_binary(x, f);
00670     
00671     f.flush();
00672     f.close();
00673     
00674     if(save_okay == true)
00675       {
00676       save_okay = diskio::safe_rename(tmp_name, final_name);
00677       }
00678     }
00679   
00680   return save_okay;
00681   }
00682 
00683 
00684 
00685 //
00686 // TODO:
00687 // add functionality to save the image in a normalised format,
00688 // i.e. scaled so that every value falls in the [0,255] range.
00689 
00690 //! Save a matrix as a PGM greyscale image
00691 template<typename eT>
00692 inline
00693 bool
00694 diskio::save_pgm_binary(const Mat<eT>& x, std::ostream& f)
00695   {
00696   arma_extra_debug_sigprint();
00697   
00698   f << "P5" << '\n';
00699   f << x.n_cols << ' ' << x.n_rows << '\n';
00700   f << 255 << '\n';
00701   
00702   const u32 n_elem = x.n_rows * x.n_cols;
00703   podarray<u8> tmp(n_elem);
00704   
00705   u32 i = 0;
00706   
00707   for(u32 row=0; row < x.n_rows; ++row)
00708     {
00709     for(u32 col=0; col < x.n_cols; ++col)
00710       {
00711       tmp[i] = u8( x.at(row,col) );  // TODO: add round() ?
00712       ++i;
00713       }
00714     }
00715   
00716   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
00717   
00718   return f.good();
00719   }
00720 
00721 
00722 
00723 //! Save a matrix as a PGM greyscale image
00724 template<typename T>
00725 inline
00726 bool
00727 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, const std::string& final_name)
00728   {
00729   arma_extra_debug_sigprint();
00730   
00731   const uchar_mat tmp = conv_to<uchar_mat>::from(x);
00732   
00733   return diskio::save_pgm_binary(tmp, final_name);
00734   }
00735 
00736 
00737 
00738 //! Save a matrix as a PGM greyscale image
00739 template<typename T>
00740 inline
00741 bool
00742 diskio::save_pgm_binary(const Mat< std::complex<T> >& x, std::ostream& f)
00743   {
00744   arma_extra_debug_sigprint();
00745   
00746   const uchar_mat tmp = conv_to<uchar_mat>::from(x);
00747   
00748   return diskio::save_pgm_binary(tmp, f);
00749   }
00750 
00751 
00752 
00753 //! Load a matrix as raw text (no header, human readable).
00754 //! Can read matrices saved as text in Matlab and Octave.
00755 //! NOTE: this is much slower than reading a file with a header.
00756 template<typename eT>
00757 inline
00758 bool
00759 diskio::load_raw_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg)
00760   {
00761   arma_extra_debug_sigprint();
00762 
00763   std::fstream f;
00764   f.open(name.c_str(), std::fstream::in);
00765   
00766   bool load_okay = f.is_open();
00767   
00768   if(load_okay == true)
00769     {
00770     load_okay = diskio::load_raw_ascii(x, f, err_msg);
00771     f.close();
00772     }
00773   
00774   return load_okay;
00775   }
00776 
00777 
00778 
00779 //! Load a matrix as raw text (no header, human readable).
00780 //! Can read matrices saved as text in Matlab and Octave.
00781 //! NOTE: this is much slower than reading a file with a header.
00782 template<typename eT>
00783 inline
00784 bool
00785 diskio::load_raw_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg)
00786   {
00787   arma_extra_debug_sigprint();
00788   
00789   bool load_okay = true;
00790   
00791   //std::fstream::pos_type start = f.tellg();
00792   
00793   //
00794   // work out the size
00795   
00796   u32 f_n_rows = 0;
00797   u32 f_n_cols = 0;
00798   
00799   bool f_n_cols_found = false;
00800   
00801   std::string line_string;
00802   std::string token;
00803   
00804   while( (f.good() == true) && (load_okay == true) )
00805     {
00806     std::getline(f, line_string);
00807     if(line_string.size() == 0)
00808       break;
00809     
00810     std::stringstream line_stream(line_string);
00811     
00812     u32 line_n_cols = 0;
00813     while (line_stream >> token)
00814       line_n_cols++;
00815     
00816     if(f_n_cols_found == false)
00817       {
00818       f_n_cols = line_n_cols;
00819       f_n_cols_found = true;
00820       }
00821     else
00822       {
00823       if(line_n_cols != f_n_cols)
00824         {
00825         err_msg = "inconsistent number of columns in ";
00826         load_okay = false;
00827         }
00828       }
00829     
00830     ++f_n_rows;
00831     }
00832     
00833   if(load_okay == true)
00834     {
00835     f.clear();
00836     f.seekg(0, ios::beg);
00837     //f.seekg(start);
00838     
00839     x.set_size(f_n_rows, f_n_cols);
00840   
00841     eT val;
00842     
00843     for(u32 row=0; row < x.n_rows; ++row)
00844       {
00845       for(u32 col=0; col < x.n_cols; ++col)
00846         {
00847         // f >> token;
00848         // x.at(row,col) = eT( strtod(token.c_str(), 0) );
00849         
00850         f >> val;
00851         x.at(row,col) = val;
00852         }
00853       }
00854     }
00855   
00856   if(f.good() == false)
00857     {
00858     load_okay = false;
00859     }
00860   
00861   return load_okay;
00862   }
00863 
00864 
00865 
00866 //! Load a matrix in text format (human readable),
00867 //! with a header that indicates the matrix type as well as its dimensions
00868 template<typename eT>
00869 inline
00870 bool
00871 diskio::load_arma_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg)
00872   {
00873   arma_extra_debug_sigprint();
00874   
00875   std::ifstream f(name.c_str());
00876   
00877   bool load_okay = f.is_open();
00878   
00879   if(load_okay == true)
00880     {
00881     load_okay = diskio::load_arma_ascii(x, f, err_msg);
00882     f.close();
00883     }
00884   
00885   return load_okay;
00886   }
00887 
00888 
00889 
00890 //! Load a matrix in text format (human readable),
00891 //! with a header that indicates the matrix type as well as its dimensions
00892 template<typename eT>
00893 inline
00894 bool
00895 diskio::load_arma_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg)
00896   {
00897   arma_extra_debug_sigprint();
00898   
00899   bool load_okay = true;
00900   
00901   std::string f_header;
00902   u32 f_n_rows;
00903   u32 f_n_cols;
00904   
00905   f >> f_header;
00906   f >> f_n_rows;
00907   f >> f_n_cols;
00908   
00909   if(f_header == diskio::gen_txt_header(x))
00910     {
00911     x.set_size(f_n_rows, f_n_cols);
00912     
00913     for(u32 row=0; row < x.n_rows; ++row)
00914       {
00915       for(u32 col=0; col < x.n_cols; ++col)
00916         {
00917         f >> x.at(row,col);
00918         }
00919       }
00920     
00921     load_okay = f.good();
00922     }
00923   else
00924     {
00925     load_okay = false;
00926     err_msg = "incorrect header in ";
00927     }
00928   
00929   return load_okay;
00930   }
00931 
00932 
00933 
00934 //! Load a matrix in binary format,
00935 //! with a header that indicates the matrix type as well as its dimensions
00936 template<typename eT>
00937 inline
00938 bool
00939 diskio::load_arma_binary(Mat<eT>& x, const std::string& name, std::string& err_msg)
00940   {
00941   arma_extra_debug_sigprint();
00942   
00943   std::ifstream f;
00944   f.open(name.c_str(), std::fstream::binary);
00945   
00946   bool load_okay = f.is_open();
00947   
00948   if(load_okay == true)
00949     {
00950     load_okay = diskio::load_arma_binary(x, f, err_msg);
00951     f.close();
00952     }
00953   
00954   return load_okay;
00955   }
00956 
00957 
00958 
00959 template<typename eT>
00960 inline
00961 bool
00962 diskio::load_arma_binary(Mat<eT>& x, std::istream& f, std::string& err_msg)
00963   {
00964   arma_extra_debug_sigprint();
00965   
00966   bool load_okay = true;
00967   
00968   std::string f_header;
00969   u32 f_n_rows;
00970   u32 f_n_cols;
00971   
00972   f >> f_header;
00973   f >> f_n_rows;
00974   f >> f_n_cols;
00975   
00976   if(f_header == diskio::gen_bin_header(x))
00977     {
00978     //f.seekg(1, ios::cur);  // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
00979     f.get();
00980     
00981     x.set_size(f_n_rows,f_n_cols);
00982     f.read( reinterpret_cast<char *>(x.memptr()), x.n_elem*sizeof(eT));
00983     
00984     load_okay = f.good();
00985     }
00986   else
00987     {
00988     load_okay = false;
00989     err_msg = "incorrect header in ";
00990     }
00991   
00992   return load_okay;
00993   }
00994 
00995 
00996 
00997 inline
00998 void
00999 diskio::pnm_skip_comments(std::istream& f)
01000   {
01001   while( isspace(f.peek()) )
01002     {
01003     while( isspace(f.peek()) )
01004       {
01005       f.get();
01006       }
01007   
01008     if(f.peek() == '#')
01009       {
01010       while( (f.peek() != '\r') && (f.peek()!='\n') )
01011         {
01012         f.get();
01013         }
01014       }
01015     }
01016   }
01017 
01018 
01019 
01020 //! Load a PGM greyscale image as a matrix
01021 template<typename eT>
01022 inline
01023 bool
01024 diskio::load_pgm_binary(Mat<eT>& x, const std::string& name, std::string& err_msg)
01025   {
01026   arma_extra_debug_sigprint();
01027   
01028   std::fstream f;
01029   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01030   
01031   bool load_okay = f.is_open();
01032   
01033   if(load_okay == true)
01034     {
01035     load_okay = diskio::load_pgm_binary(x, f, err_msg);
01036     f.close();
01037     }
01038   
01039   return load_okay;
01040   }
01041 
01042 
01043 
01044 //! Load a PGM greyscale image as a matrix
01045 template<typename eT>
01046 inline
01047 bool
01048 diskio::load_pgm_binary(Mat<eT>& x, std::istream& f, std::string& err_msg)
01049   {
01050   bool load_okay = true;
01051   
01052   std::string f_header;
01053   f >> f_header;
01054   
01055   if(f_header == "P5")
01056     {
01057     u32 f_n_rows = 0;
01058     u32 f_n_cols = 0;
01059     int f_maxval = 0;
01060   
01061     diskio::pnm_skip_comments(f);
01062   
01063     f >> f_n_cols;
01064     diskio::pnm_skip_comments(f);
01065   
01066     f >> f_n_rows;
01067     diskio::pnm_skip_comments(f);
01068   
01069     f >> f_maxval;
01070     f.get();
01071     
01072     if( (f_maxval > 0) || (f_maxval <= 65535) )
01073       {
01074       x.set_size(f_n_rows,f_n_cols);
01075       
01076       if(f_maxval <= 255)
01077         {
01078         const u32 n_elem = f_n_cols*f_n_rows;
01079         podarray<u8> tmp(n_elem);
01080         
01081         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
01082         
01083         u32 i = 0;
01084         
01085         //cout << "f_n_cols = " << f_n_cols << endl;
01086         //cout << "f_n_rows = " << f_n_rows << endl;
01087         
01088         
01089         for(u32 row=0; row < f_n_rows; ++row)
01090           {
01091           for(u32 col=0; col < f_n_cols; ++col)
01092             {
01093             x.at(row,col) = eT(tmp[i]);
01094             ++i;
01095             }
01096           }
01097           
01098         }
01099       else
01100         {
01101         const u32 n_elem = f_n_cols*f_n_rows;
01102         podarray<u16> tmp(n_elem);
01103         
01104         f.read( reinterpret_cast<char *>(tmp.memptr()), n_elem*2);
01105         
01106         u32 i = 0;
01107         
01108         for(u32 row=0; row < f_n_rows; ++row)
01109           {
01110           for(u32 col=0; col < f_n_cols; ++col)
01111             {
01112             x.at(row,col) = eT(tmp[i]);
01113             ++i;
01114             }
01115           }
01116         
01117         }
01118       
01119       }
01120     else
01121       {
01122       load_okay = false;
01123       err_msg = "currently no code available to handle loading ";
01124       }
01125     
01126     if(f.good() == false)
01127       {
01128       load_okay = false;
01129       }
01130     }
01131   else
01132     {
01133     load_okay = false;
01134     err_msg = "unsupported header in ";
01135     }
01136   
01137   return load_okay;
01138   }
01139 
01140 
01141 
01142 //! Load a PGM greyscale image as a matrix
01143 template<typename T>
01144 inline
01145 bool
01146 diskio::load_pgm_binary(Mat< std::complex<T> >& x, const std::string& name, std::string& err_msg)
01147   {
01148   arma_extra_debug_sigprint();
01149   
01150   uchar_mat tmp;
01151   const bool load_okay = diskio::load_pgm_binary(tmp, name, err_msg);
01152   
01153   x = conv_to< Mat< std::complex<T> > >::from(tmp);
01154   
01155   return load_okay;
01156   }
01157 
01158 
01159 
01160 //! Load a PGM greyscale image as a matrix
01161 template<typename T>
01162 inline
01163 bool
01164 diskio::load_pgm_binary(Mat< std::complex<T> >& x, std::istream& is, std::string& err_msg)
01165   {
01166   arma_extra_debug_sigprint();
01167   
01168   uchar_mat tmp;
01169   const bool load_okay = diskio::load_pgm_binary(tmp, is, err_msg);
01170   
01171   x = conv_to< Mat< std::complex<T> > >::from(tmp);
01172   
01173   return load_okay;
01174   }
01175 
01176 
01177 
01178 //! Try to load a matrix by automatically determining its type
01179 template<typename eT>
01180 inline
01181 bool
01182 diskio::load_auto_detect(Mat<eT>& x, const std::string& name, std::string& err_msg)
01183   {
01184   arma_extra_debug_sigprint();
01185   
01186   std::fstream f;
01187   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01188   
01189   bool load_okay = f.is_open();
01190   
01191   if(load_okay == true)
01192     {
01193     load_okay = diskio::load_auto_detect(x, f, err_msg);
01194     f.close();
01195     }
01196   
01197   return load_okay;
01198   }
01199 
01200 
01201 
01202 //! Try to load a matrix by automatically determining its type
01203 template<typename eT>
01204 inline
01205 bool
01206 diskio::load_auto_detect(Mat<eT>& x, std::istream& f, std::string& err_msg)
01207   {
01208   arma_extra_debug_sigprint();
01209   
01210   static const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT";
01211   static const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN";
01212   static const std::string           P5 = "P5";
01213   
01214   podarray<char> raw_header(ARMA_MAT_TXT.length() + 1);
01215   
01216   std::streampos pos = f.tellg();
01217     
01218   f.read(raw_header.memptr(), ARMA_MAT_TXT.length());
01219   raw_header[ARMA_MAT_TXT.length()] = '\0';
01220   
01221   f.clear();
01222   f.seekg(pos);
01223   
01224   const std::string header = raw_header.mem;
01225   
01226   if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length()))
01227     {
01228     return load_arma_ascii(x, f, err_msg);
01229     }
01230   else
01231   if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length()))
01232     {
01233     return load_arma_binary(x, f, err_msg);
01234     }
01235   else
01236   if(P5 == header.substr(0,P5.length()))
01237     {
01238     return load_pgm_binary(x, f, err_msg);
01239     }
01240   else
01241     {
01242     return load_raw_ascii(x, f, err_msg);
01243     }
01244   }
01245 
01246 
01247 
01248 // cubes
01249 
01250 
01251 
01252 //! Save a cube as raw text (no header, human readable).
01253 template<typename eT>
01254 inline
01255 bool
01256 diskio::save_raw_ascii(const Cube<eT>& x, const std::string& final_name)
01257   {
01258   arma_extra_debug_sigprint();
01259   
01260   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01261   
01262   std::fstream f(tmp_name.c_str(), std::fstream::out);
01263   
01264   bool save_okay = f.is_open();
01265   
01266   if(save_okay == true)
01267     {
01268     save_okay = save_raw_ascii(x, f);
01269     
01270     f.flush();
01271     f.close();
01272     
01273     if(save_okay == true)
01274       {
01275       save_okay = diskio::safe_rename(tmp_name, final_name);
01276       }
01277     }
01278   
01279   return save_okay;
01280   }
01281 
01282 
01283 
01284 //! Save a cube as raw text (no header, human readable).
01285 template<typename eT>
01286 inline
01287 bool
01288 diskio::save_raw_ascii(const Cube<eT>& x, std::ostream& f)
01289   {
01290   arma_extra_debug_sigprint();
01291   
01292   u32 cell_width;
01293   
01294   // TODO: need sane values for complex numbers
01295   
01296   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01297     {
01298     f.setf(ios::scientific);
01299     f.precision(8);
01300     cell_width = 16;
01301     }
01302   
01303   for(u32 slice=0; slice < x.n_slices; ++slice)
01304     {
01305     for(u32 row=0; row < x.n_rows; ++row)
01306       {
01307       for(u32 col=0; col < x.n_cols; ++col)
01308         {
01309         f.put(' ');
01310         
01311         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01312           {
01313           f.width(cell_width);
01314           }
01315         
01316         f << x.at(row,col,slice);
01317         }
01318         
01319       f.put('\n');
01320       }
01321     }
01322   
01323   return f.good();
01324   }
01325 
01326 
01327 
01328 //! Save a cube in text format (human readable),
01329 //! with a header that indicates the cube type as well as its dimensions
01330 template<typename eT>
01331 inline
01332 bool
01333 diskio::save_arma_ascii(const Cube<eT>& x, const std::string& final_name)
01334   {
01335   arma_extra_debug_sigprint();
01336   
01337   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01338   
01339   std::ofstream f(tmp_name.c_str());
01340   
01341   bool save_okay = f.is_open();
01342   
01343   if(save_okay == true)
01344     {
01345     save_okay = diskio::save_arma_ascii(x, f);
01346     
01347     f.flush();
01348     f.close();
01349     
01350     if(save_okay == true)
01351       {
01352       save_okay = diskio::safe_rename(tmp_name, final_name);
01353       }
01354     }
01355   
01356   return save_okay;
01357   }
01358 
01359 
01360 
01361 //! Save a cube in text format (human readable),
01362 //! with a header that indicates the cube type as well as its dimensions
01363 template<typename eT>
01364 inline
01365 bool
01366 diskio::save_arma_ascii(const Cube<eT>& x, std::ostream& f)
01367   {
01368   arma_extra_debug_sigprint();
01369   
01370   const ios::fmtflags orig_flags = f.flags();
01371   
01372   f << diskio::gen_txt_header(x) << '\n';
01373   f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
01374   
01375   u32 cell_width;
01376   
01377   // TODO: need sane values for complex numbers
01378   
01379   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01380     {
01381     f.setf(ios::scientific);
01382     f.precision(8);
01383     cell_width = 16;
01384     }
01385     
01386   for(u32 slice=0; slice < x.n_slices; ++slice)
01387     {
01388     for(u32 row=0; row < x.n_rows; ++row)
01389       {
01390       for(u32 col=0; col < x.n_cols; ++col)
01391         {
01392         f.put(' ');
01393         
01394         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )        
01395           {
01396           f.width(cell_width);
01397           }
01398         
01399         f << x.at(row,col,slice);
01400         }
01401       
01402       f.put('\n');
01403       }
01404     }
01405   
01406   const bool save_okay = f.good();
01407   
01408   f.flags(orig_flags);
01409   
01410   return save_okay;
01411   }
01412 
01413 
01414 
01415 //! Save a cube in binary format,
01416 //! with a header that stores the cube type as well as its dimensions
01417 template<typename eT>
01418 inline
01419 bool
01420 diskio::save_arma_binary(const Cube<eT>& x, const std::string& final_name)
01421   {
01422   arma_extra_debug_sigprint();
01423   
01424   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01425   
01426   std::ofstream f(tmp_name.c_str(), std::fstream::binary);
01427   
01428   bool save_okay = f.is_open();
01429   
01430   if(save_okay == true)
01431     {
01432     save_okay = diskio::save_arma_binary(x, f);
01433     
01434     f.flush();
01435     f.close();
01436     
01437     if(save_okay == true)
01438       {
01439       save_okay = diskio::safe_rename(tmp_name, final_name);
01440       }
01441     }
01442   
01443   return save_okay;
01444   }
01445 
01446 
01447 
01448 //! Save a cube in binary format,
01449 //! with a header that stores the cube type as well as its dimensions
01450 template<typename eT>
01451 inline
01452 bool
01453 diskio::save_arma_binary(const Cube<eT>& x, std::ostream& f)
01454   {
01455   arma_extra_debug_sigprint();
01456   
01457   f << diskio::gen_bin_header(x) << '\n';
01458   f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
01459   
01460   f.write(reinterpret_cast<const char*>(x.mem), x.n_elem*sizeof(eT));
01461   
01462   return f.good();
01463   }
01464 
01465 
01466 
01467 //! Load a cube as raw text (no header, human readable).
01468 //! NOTE: this is much slower than reading a file with a header.
01469 template<typename eT>
01470 inline
01471 bool
01472 diskio::load_raw_ascii(Cube<eT>& x, const std::string& name, std::string& err_msg)
01473   {
01474   arma_extra_debug_sigprint();
01475   
01476   Mat<eT> tmp;
01477   const bool load_okay = diskio::load_raw_ascii(tmp, name, err_msg);
01478   
01479   if(load_okay == true)
01480     {
01481     x.set_size(tmp.n_rows, tmp.n_cols, 1);
01482     
01483     // make sure the loaded matrix was not empty
01484     if(x.n_slices > 0)
01485       {
01486       x.slice(0) = tmp;
01487       }
01488     }
01489   
01490   return load_okay;
01491   }
01492 
01493 
01494 
01495 //! Load a cube as raw text (no header, human readable).
01496 //! NOTE: this is much slower than reading a file with a header.
01497 template<typename eT>
01498 inline
01499 bool
01500 diskio::load_raw_ascii(Cube<eT>& x, std::istream& f, std::string& err_msg)
01501   {
01502   arma_extra_debug_sigprint();
01503 
01504   Mat<eT> tmp;
01505   const bool load_okay = diskio::load_raw_ascii(tmp, f, err_msg);
01506   
01507   if(load_okay == true)
01508     {
01509     x.set_size(tmp.n_rows, tmp.n_cols, 1);
01510     
01511     // make sure the loaded matrix was not empty
01512     if(x.n_slices > 0)
01513       {
01514       x.slice(0) = tmp;
01515       }
01516     }
01517   
01518   return load_okay;
01519   }
01520 
01521 
01522 
01523 //! Load a cube in text format (human readable),
01524 //! with a header that indicates the cube type as well as its dimensions
01525 template<typename eT>
01526 inline
01527 bool
01528 diskio::load_arma_ascii(Cube<eT>& x, const std::string& name, std::string& err_msg)
01529   {
01530   arma_extra_debug_sigprint();
01531   
01532   std::ifstream f(name.c_str());
01533   
01534   bool load_okay = f.is_open();
01535   
01536   if(load_okay == true)
01537     {
01538     load_okay = diskio::load_arma_ascii(x, f, err_msg);
01539     f.close();
01540     }
01541   
01542   return load_okay;
01543   }
01544   
01545 
01546 
01547 //! Load a cube in text format (human readable),
01548 //! with a header that indicates the cube type as well as its dimensions
01549 template<typename eT>
01550 inline
01551 bool
01552 diskio::load_arma_ascii(Cube<eT>& x, std::istream& f, std::string& err_msg)
01553   {
01554   arma_extra_debug_sigprint();
01555   
01556   bool load_okay = true;
01557   
01558   std::string f_header;
01559   u32 f_n_rows;
01560   u32 f_n_cols;
01561   u32 f_n_slices;
01562   
01563   f >> f_header;
01564   f >> f_n_rows;
01565   f >> f_n_cols;
01566   f >> f_n_slices;
01567   
01568   if(f_header == diskio::gen_txt_header(x))
01569     {
01570     x.set_size(f_n_rows, f_n_cols, f_n_slices);
01571 
01572     for(u32 slice=0; slice < x.n_slices; ++slice)
01573       {
01574       for(u32 row=0; row < x.n_rows; ++row)
01575         {
01576         for(u32 col=0; col < x.n_cols; ++col)
01577           {
01578           f >> x.at(row,col,slice);
01579           }
01580         }
01581       }
01582     
01583     load_okay = f.good();
01584     }
01585   else
01586     {
01587     load_okay = false;
01588     err_msg = "incorrect header in ";
01589     }
01590   
01591   return load_okay;
01592   }
01593 
01594 
01595 
01596 //! Load a cube in binary format,
01597 //! with a header that indicates the cube type as well as its dimensions
01598 template<typename eT>
01599 inline
01600 bool
01601 diskio::load_arma_binary(Cube<eT>& x, const std::string& name, std::string& err_msg)
01602   {
01603   arma_extra_debug_sigprint();
01604   
01605   std::ifstream f;
01606   f.open(name.c_str(), std::fstream::binary);
01607   
01608   bool load_okay = f.is_open();
01609   
01610   if(load_okay == true)
01611     {
01612     load_okay = diskio::load_arma_binary(x, f, err_msg);
01613     f.close();
01614     }
01615   
01616   return load_okay;
01617   }
01618 
01619 
01620 
01621 template<typename eT>
01622 inline
01623 bool
01624 diskio::load_arma_binary(Cube<eT>& x, std::istream& f, std::string& err_msg)
01625   {
01626   arma_extra_debug_sigprint();
01627   
01628   bool load_okay = true;
01629   
01630   std::string f_header;
01631   u32 f_n_rows;
01632   u32 f_n_cols;
01633   u32 f_n_slices;
01634   
01635   f >> f_header;
01636   f >> f_n_rows;
01637   f >> f_n_cols;
01638   f >> f_n_slices;
01639   
01640   if(f_header == diskio::gen_bin_header(x))
01641     {
01642     //f.seekg(1, ios::cur);  // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
01643     f.get();
01644     
01645     x.set_size(f_n_rows, f_n_cols, f_n_slices);
01646     f.read( reinterpret_cast<char *>(x.memptr()), x.n_elem*sizeof(eT));
01647     
01648     load_okay = f.good();
01649     }
01650   else
01651     {
01652     load_okay = false;
01653     err_msg = "incorrect header in ";
01654     }
01655   
01656   return load_okay;
01657   }
01658 
01659 
01660 
01661 //! Try to load a cube by automatically determining its type
01662 template<typename eT>
01663 inline
01664 bool
01665 diskio::load_auto_detect(Cube<eT>& x, const std::string& name, std::string& err_msg)
01666   {
01667   arma_extra_debug_sigprint();
01668   
01669   std::fstream f;
01670   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01671   
01672   bool load_okay = f.is_open();
01673   
01674   if(load_okay == true)
01675     {
01676     load_okay = diskio::load_auto_detect(x, f, err_msg);
01677     f.close();
01678     }
01679   
01680   return load_okay;
01681   }
01682 
01683 
01684 
01685 //! Try to load a cube by automatically determining its type
01686 template<typename eT>
01687 inline
01688 bool
01689 diskio::load_auto_detect(Cube<eT>& x, std::istream& f, std::string& err_msg)
01690   {
01691   arma_extra_debug_sigprint();
01692   
01693   static const std::string ARMA_CUB_TXT = "ARMA_CUB_TXT";
01694   static const std::string ARMA_CUB_BIN = "ARMA_CUB_BIN";
01695   static const std::string           P6 = "P6";
01696   
01697   podarray<char> raw_header(ARMA_CUB_TXT.length() + 1);
01698   
01699   std::streampos pos = f.tellg();
01700   
01701   f.read(raw_header.memptr(), ARMA_CUB_TXT.length());
01702   raw_header[ARMA_CUB_TXT.length()] = '\0';
01703   
01704   f.clear();
01705   f.seekg(pos);
01706   
01707   const std::string header = raw_header.mem;
01708   
01709   if(ARMA_CUB_TXT == header.substr(0, ARMA_CUB_TXT.length()))
01710     {
01711     return load_arma_ascii(x, f, err_msg);
01712     }
01713   else
01714   if(ARMA_CUB_BIN == header.substr(0, ARMA_CUB_BIN.length()))
01715     {
01716     return load_arma_binary(x, f, err_msg);
01717     }
01718   else
01719   if(P6 == header.substr(0, P6.length()))
01720     {
01721     return load_ppm_binary(x, f, err_msg);
01722     }
01723   else
01724     {
01725     return load_raw_ascii(x, f, err_msg);
01726     }
01727   }
01728 
01729 
01730 
01731 
01732 
01733 // fields
01734 
01735 
01736 
01737 template<typename T1>
01738 inline
01739 bool
01740 diskio::save_arma_binary(const field<T1>& x, const std::string& final_name)
01741   {
01742   arma_extra_debug_sigprint();
01743   
01744   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01745   
01746   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01747   
01748   bool save_okay = f.is_open();
01749   
01750   if(save_okay == true)
01751     {
01752     save_okay = diskio::save_arma_binary(x, f);
01753     
01754     f.flush();
01755     f.close();
01756     
01757     if(save_okay == true)
01758       {
01759       save_okay = diskio::safe_rename(tmp_name, final_name);
01760       }
01761     }
01762   
01763   return save_okay;
01764   }
01765 
01766 
01767 
01768 template<typename T1>
01769 inline
01770 bool
01771 diskio::save_arma_binary(const field<T1>& x, std::ostream& f)
01772   {
01773   arma_extra_debug_sigprint();
01774   
01775   arma_type_check< (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) >::apply();
01776   
01777   f << "ARMA_FLD_BIN" << '\n';
01778   f << x.n_rows << '\n';
01779   f << x.n_cols << '\n';
01780   
01781   bool save_okay = true;
01782   
01783   for(u32 i=0; i<x.n_elem; ++i)
01784     {
01785     save_okay = diskio::save_arma_binary(x[i], f);
01786     
01787     if(save_okay == false)
01788       {
01789       break;
01790       }
01791     }
01792   
01793   return save_okay;
01794   }
01795 
01796 
01797 
01798 template<typename T1>
01799 inline
01800 bool
01801 diskio::load_arma_binary(field<T1>& x, const std::string& name, std::string& err_msg)
01802   {
01803   arma_extra_debug_sigprint();
01804   
01805   std::ifstream f( name.c_str(), std::fstream::binary );
01806   
01807   bool load_okay = f.is_open();
01808   
01809   if(load_okay == true)
01810     {
01811     load_okay = diskio::load_arma_binary(x, f, err_msg);
01812     f.close();
01813     }
01814   
01815   return load_okay;
01816   }
01817 
01818 
01819 
01820 template<typename T1>
01821 inline
01822 bool
01823 diskio::load_arma_binary(field<T1>& x, std::istream& f, std::string& err_msg)
01824   {
01825   arma_extra_debug_sigprint();
01826   
01827   arma_type_check< (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) >::apply();
01828   
01829   bool load_okay = true;
01830   
01831   std::string f_type;
01832   f >> f_type;
01833   
01834   if(f_type != "ARMA_FLD_BIN")
01835     {
01836     load_okay = false;
01837     err_msg = "unsupported field type in ";
01838     }
01839   else
01840     {
01841     u32 f_n_rows;
01842     u32 f_n_cols;
01843   
01844     f >> f_n_rows;
01845     f >> f_n_cols;
01846     
01847     x.set_size(f_n_rows, f_n_cols);
01848     
01849     f.get();      
01850     
01851     for(u32 i=0; i<x.n_elem; ++i)
01852       {
01853       load_okay = diskio::load_arma_binary(x[i], f, err_msg);
01854       
01855       if(load_okay == false)
01856         {
01857         break;
01858         }
01859       }
01860     }
01861   
01862   return load_okay;
01863   }
01864 
01865 
01866 
01867 inline
01868 bool
01869 diskio::save_std_string(const field<std::string>& x, const std::string& final_name)
01870   {
01871   arma_extra_debug_sigprint();
01872   
01873   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01874   
01875   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01876   
01877   bool save_okay = f.is_open();
01878   
01879   if(save_okay == true)
01880     {
01881     save_okay = diskio::save_std_string(x, f);
01882     
01883     f.flush();
01884     f.close();
01885     
01886     if(save_okay == true)
01887       {
01888       save_okay = diskio::safe_rename(tmp_name, final_name);
01889       }
01890     }
01891   
01892   return save_okay;
01893   }
01894 
01895 
01896 
01897 inline
01898 bool
01899 diskio::save_std_string(const field<std::string>& x, std::ostream& f)
01900   {
01901   arma_extra_debug_sigprint();
01902   
01903   for(u32 row=0; row<x.n_rows; ++row)
01904   for(u32 col=0; col<x.n_cols; ++col)
01905     {
01906     f << x.at(row,col);
01907     
01908     if(col < x.n_cols-1)
01909       {
01910       f << ' ';
01911       }
01912     else
01913       {
01914       f << '\n';
01915       }
01916     }
01917   
01918   return f.good();
01919   }
01920 
01921 
01922 
01923 inline
01924 bool
01925 diskio::load_std_string(field<std::string>& x, const std::string& name, std::string& err_msg)
01926   {
01927   arma_extra_debug_sigprint();
01928   
01929   std::ifstream f( name.c_str() );
01930   
01931   bool load_okay = f.is_open();
01932   
01933   if(load_okay == true)
01934     {
01935     load_okay = diskio::load_std_string(x, f, err_msg);
01936     f.close();
01937     }
01938   
01939   return load_okay;
01940   }
01941 
01942 
01943 
01944 inline
01945 bool
01946 diskio::load_std_string(field<std::string>& x, std::istream& f, std::string& err_msg)
01947   {
01948   arma_extra_debug_sigprint();
01949   
01950   bool load_okay = true;
01951   
01952   //
01953   // work out the size
01954   
01955   u32 f_n_rows = 0;
01956   u32 f_n_cols = 0;
01957   
01958   bool f_n_cols_found = false;
01959   
01960   std::string line_string;
01961   std::string token;
01962   
01963   while( (f.good() == true) && (load_okay == true) )
01964     {
01965     std::getline(f, line_string);
01966     if(line_string.size() == 0)
01967       break;
01968     
01969     std::stringstream line_stream(line_string);
01970     
01971     u32 line_n_cols = 0;
01972     while (line_stream >> token)
01973       line_n_cols++;
01974     
01975     if(f_n_cols_found == false)
01976       {
01977       f_n_cols = line_n_cols;
01978       f_n_cols_found = true;
01979       }
01980     else
01981       {
01982       if(line_n_cols != f_n_cols)
01983         {
01984         load_okay = false;
01985         err_msg = "inconsistent number of columns in ";
01986         }
01987       }
01988     
01989     ++f_n_rows;
01990     }
01991     
01992   if(load_okay == true)
01993     {
01994     f.clear();
01995     f.seekg(0, ios::beg);
01996     //f.seekg(start);
01997     
01998     x.set_size(f_n_rows, f_n_cols);
01999   
02000     for(u32 row=0; row < x.n_rows; ++row)
02001       {
02002       for(u32 col=0; col < x.n_cols; ++col)
02003         {
02004         f >> x.at(row,col);
02005         }
02006       }
02007     }
02008   
02009   if(f.good() == false)
02010     {
02011     load_okay = false; 
02012     }
02013   
02014   return load_okay;
02015   }
02016 
02017 
02018 
02019 //! Try to load a field by automatically determining its type
02020 template<typename T1>
02021 inline
02022 bool
02023 diskio::load_auto_detect(field<T1>& x, const std::string& name, std::string& err_msg)
02024   {
02025   arma_extra_debug_sigprint();
02026   
02027   std::fstream f;
02028   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02029   
02030   bool load_okay = f.is_open();
02031   
02032   if(load_okay == true)
02033     {
02034     load_okay = diskio::load_auto_detect(x, f, err_msg);
02035     f.close();
02036     }
02037   
02038   return load_okay;
02039   }
02040 
02041 
02042 
02043 //! Try to load a field by automatically determining its type
02044 template<typename T1>
02045 inline
02046 bool
02047 diskio::load_auto_detect(field<T1>& x, std::istream& f, std::string& err_msg)
02048   {
02049   arma_extra_debug_sigprint();
02050   
02051   arma_type_check<is_Mat<T1>::value == false>::apply();
02052   
02053   static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN";
02054   static const std::string           P6 = "P6";
02055   
02056   podarray<char> raw_header(ARMA_FLD_BIN.length() + 1);
02057   
02058   std::streampos pos = f.tellg();
02059   
02060   f.read(raw_header.memptr(), ARMA_FLD_BIN.length());
02061   
02062   f.clear();
02063   f.seekg(pos);
02064   
02065   raw_header[ARMA_FLD_BIN.length()] = '\0';
02066   
02067   const std::string header = raw_header.mem;
02068   
02069   if(ARMA_FLD_BIN == header.substr(0, ARMA_FLD_BIN.length()))
02070     {
02071     return load_arma_binary(x, f, err_msg);
02072     }
02073   else
02074   if(P6 == header.substr(0, P6.length()))
02075     {
02076     return load_ppm_binary(x, f, err_msg);
02077     }
02078   else
02079     {
02080     err_msg = "unsupported header in ";
02081     return false;
02082     }
02083   }
02084 
02085 
02086 
02087 //
02088 // handling of PPM images by cubes
02089 
02090 
02091 template<typename eT>
02092 inline
02093 bool
02094 diskio::load_ppm_binary(Cube<eT>& x, const std::string& name, std::string& err_msg)
02095   {
02096   arma_extra_debug_sigprint();
02097   
02098   std::fstream f;
02099   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02100   
02101   bool load_okay = f.is_open();
02102   
02103   if(load_okay == true)
02104     {
02105     load_okay = diskio::load_ppm_binary(x, f, err_msg);
02106     f.close();
02107     }
02108   
02109   return load_okay;
02110   }
02111 
02112 
02113 
02114 template<typename eT>
02115 inline
02116 bool
02117 diskio::load_ppm_binary(Cube<eT>& x, std::istream& f, std::string& err_msg)
02118   {
02119   arma_extra_debug_sigprint();
02120   
02121   bool load_okay = true;
02122   
02123   std::string f_header;
02124   f >> f_header;
02125   
02126   if(f_header == "P6")
02127     {
02128     u32 f_n_rows = 0;
02129     u32 f_n_cols = 0;
02130     int f_maxval = 0;
02131   
02132     diskio::pnm_skip_comments(f);
02133   
02134     f >> f_n_cols;
02135     diskio::pnm_skip_comments(f);
02136   
02137     f >> f_n_rows;
02138     diskio::pnm_skip_comments(f);
02139   
02140     f >> f_maxval;
02141     f.get();
02142     
02143     if( (f_maxval > 0) || (f_maxval <= 65535) )
02144       {
02145       x.set_size(f_n_rows, f_n_cols, 3);
02146       
02147       if(f_maxval <= 255)
02148         {
02149         const u32 n_elem = 3*f_n_cols*f_n_rows;
02150         podarray<u8> tmp(n_elem);
02151         
02152         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
02153         
02154         u32 i = 0;
02155         
02156         //cout << "f_n_cols = " << f_n_cols << endl;
02157         //cout << "f_n_rows = " << f_n_rows << endl;
02158         
02159         
02160         for(u32 row=0; row < f_n_rows; ++row)
02161           {
02162           for(u32 col=0; col < f_n_cols; ++col)
02163             {
02164             x.at(row,col,0) = eT(tmp[i+0]);
02165             x.at(row,col,1) = eT(tmp[i+1]);
02166             x.at(row,col,2) = eT(tmp[i+2]);
02167             i+=3;
02168             }
02169           
02170           }
02171         }
02172       else
02173         {
02174         const u32 n_elem = 3*f_n_cols*f_n_rows;
02175         podarray<u16> tmp(n_elem);
02176         
02177         f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
02178         
02179         u32 i = 0;
02180         
02181         for(u32 row=0; row < f_n_rows; ++row)
02182           {
02183           for(u32 col=0; col < f_n_cols; ++col)
02184             {
02185             x.at(row,col,0) = eT(tmp[i+0]);
02186             x.at(row,col,1) = eT(tmp[i+1]);
02187             x.at(row,col,2) = eT(tmp[i+2]);
02188             i+=3;
02189             }
02190           
02191           }
02192         
02193         }
02194       
02195       }
02196     else
02197       {
02198       load_okay = false;
02199       err_msg = "currently no code available to handle loading ";
02200       }
02201       
02202     if(f.good() == false)
02203       {
02204       load_okay = false;
02205       }
02206     
02207     }
02208   else
02209     {
02210     load_okay = false;
02211     err_msg = "unsupported header in ";
02212     }
02213   
02214   return load_okay;
02215   }
02216 
02217 
02218 
02219 template<typename eT>
02220 inline
02221 bool
02222 diskio::save_ppm_binary(const Cube<eT>& x, const std::string& final_name)
02223   {
02224   arma_extra_debug_sigprint();
02225   
02226   const std::string tmp_name = diskio::gen_tmp_name(final_name);
02227   
02228   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
02229   
02230   bool save_okay = f.is_open();
02231   
02232   if(save_okay == true)
02233     {
02234     save_okay = diskio::save_ppm_binary(x, f);
02235     
02236     f.flush();
02237     f.close();
02238     
02239     if(save_okay == true)
02240       {
02241       save_okay = diskio::safe_rename(tmp_name, final_name);
02242       }
02243     }
02244   
02245   return save_okay;
02246   }
02247 
02248 
02249 
02250 template<typename eT>
02251 inline
02252 bool
02253 diskio::save_ppm_binary(const Cube<eT>& x, std::ostream& f)
02254   {
02255   arma_extra_debug_sigprint();
02256   
02257   arma_debug_check( (x.n_slices != 3), "diskio::save_ppm_binary(): given cube must have exactly 3 slices" );
02258   
02259   const u32 n_elem = 3 * x.n_rows * x.n_cols;
02260   podarray<u8> tmp(n_elem);
02261   
02262   u32 i = 0;
02263   for(u32 row=0; row < x.n_rows; ++row)
02264     {
02265     for(u32 col=0; col < x.n_cols; ++col)
02266       {
02267       tmp[i+0] = u8( access::tmp_real( x.at(row,col,0) ) );
02268       tmp[i+1] = u8( access::tmp_real( x.at(row,col,1) ) );
02269       tmp[i+2] = u8( access::tmp_real( x.at(row,col,2) ) );
02270       
02271       i+=3;
02272       }
02273     }
02274   
02275   f << "P6" << '\n';
02276   f << x.n_cols << '\n';
02277   f << x.n_rows << '\n';
02278   f << 255 << '\n';
02279   
02280   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
02281   
02282   return f.good();
02283   }
02284 
02285 
02286 
02287 //
02288 // handling of PPM images by fields
02289 
02290 
02291 
02292 template<typename T1>
02293 inline
02294 bool
02295 diskio::load_ppm_binary(field<T1>& x, const std::string& name, std::string& err_msg)
02296   {
02297   arma_extra_debug_sigprint();
02298   
02299   std::fstream f;
02300   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02301   
02302   bool load_okay = f.is_open();
02303   
02304   if(load_okay == true)
02305     {
02306     load_okay = diskio::load_ppm_binary(x, f, err_msg);
02307     f.close();
02308     }
02309   
02310   return load_okay;
02311   }
02312 
02313 
02314 
02315 template<typename T1>
02316 inline
02317 bool
02318 diskio::load_ppm_binary(field<T1>& x, std::istream& f, std::string& err_msg)
02319   {
02320   arma_extra_debug_sigprint();
02321   
02322   arma_type_check<is_Mat<T1>::value == false>::apply();
02323   typedef typename T1::elem_type eT;
02324   
02325   bool load_okay = true;
02326   
02327   std::string f_header;
02328   f >> f_header;
02329   
02330   if(f_header == "P6")
02331     {
02332     u32 f_n_rows = 0;
02333     u32 f_n_cols = 0;
02334     int f_maxval = 0;
02335   
02336     diskio::pnm_skip_comments(f);
02337   
02338     f >> f_n_cols;
02339     diskio::pnm_skip_comments(f);
02340   
02341     f >> f_n_rows;
02342     diskio::pnm_skip_comments(f);
02343   
02344     f >> f_maxval;
02345     f.get();
02346     
02347     if( (f_maxval > 0) || (f_maxval <= 65535) )
02348       {
02349       x.set_size(3);
02350       Mat<eT>& R = x(0);
02351       Mat<eT>& G = x(1);
02352       Mat<eT>& B = x(2);
02353       
02354       R.set_size(f_n_rows,f_n_cols);
02355       G.set_size(f_n_rows,f_n_cols);
02356       B.set_size(f_n_rows,f_n_cols);
02357       
02358       if(f_maxval <= 255)
02359         {
02360         const u32 n_elem = 3*f_n_cols*f_n_rows;
02361         podarray<u8> tmp(n_elem);
02362         
02363         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
02364         
02365         u32 i = 0;
02366         
02367         //cout << "f_n_cols = " << f_n_cols << endl;
02368         //cout << "f_n_rows = " << f_n_rows << endl;
02369         
02370         
02371         for(u32 row=0; row < f_n_rows; ++row)
02372           {
02373           for(u32 col=0; col < f_n_cols; ++col)
02374             {
02375             R.at(row,col) = eT(tmp[i+0]);
02376             G.at(row,col) = eT(tmp[i+1]);
02377             B.at(row,col) = eT(tmp[i+2]);
02378             i+=3;
02379             }
02380           
02381           }
02382         }
02383       else
02384         {
02385         const u32 n_elem = 3*f_n_cols*f_n_rows;
02386         podarray<u16> tmp(n_elem);
02387         
02388         f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
02389         
02390         u32 i = 0;
02391         
02392         for(u32 row=0; row < f_n_rows; ++row)
02393           {
02394           for(u32 col=0; col < f_n_cols; ++col)
02395             {
02396             R.at(row,col) = eT(tmp[i+0]);
02397             G.at(row,col) = eT(tmp[i+1]);
02398             B.at(row,col) = eT(tmp[i+2]);
02399             i+=3;
02400             }
02401           
02402           }
02403         
02404         }
02405       
02406       }
02407     else
02408       {
02409       load_okay = false;
02410       err_msg = "currently no code available to handle loading ";
02411       }
02412     
02413     if(f.good() == false)
02414       {
02415       load_okay = false;
02416       }
02417     
02418     }
02419   else
02420     {
02421     load_okay = false;
02422     err_msg = "unsupported header in ";
02423     }
02424   
02425   return load_okay;
02426   }
02427 
02428 
02429 
02430 template<typename T1>
02431 inline
02432 bool
02433 diskio::save_ppm_binary(const field<T1>& x, const std::string& final_name)
02434   {
02435   arma_extra_debug_sigprint();
02436   
02437   const std::string tmp_name = diskio::gen_tmp_name(final_name);
02438   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
02439   
02440   bool save_okay = f.is_open();
02441   
02442   if(save_okay == true)
02443     {
02444     save_okay = diskio::save_ppm_binary(x, f);
02445     
02446     f.flush();
02447     f.close();
02448     
02449     if(save_okay == true)
02450       {
02451       save_okay = diskio::safe_rename(tmp_name, final_name);
02452       }
02453     }
02454   
02455   return save_okay;
02456   }
02457 
02458 
02459 
02460 template<typename T1>
02461 inline
02462 bool
02463 diskio::save_ppm_binary(const field<T1>& x, std::ostream& f)
02464   {
02465   arma_extra_debug_sigprint();
02466   
02467   arma_type_check<is_Mat<T1>::value == false>::apply();
02468   
02469   typedef typename T1::elem_type eT;
02470   
02471   arma_debug_check( (x.n_elem != 3), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
02472   
02473   bool same_size = true;
02474   for(u32 i=1; i<3; ++i)
02475     {
02476     if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) )
02477       {
02478       same_size = false;
02479       break;
02480       }
02481     }
02482   
02483   arma_debug_check( (same_size != true), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
02484   
02485   const Mat<eT>& R = x(0);
02486   const Mat<eT>& G = x(1);
02487   const Mat<eT>& B = x(2);
02488   
02489   f << "P6" << '\n';
02490   f << R.n_cols << '\n';
02491   f << R.n_rows << '\n';
02492   f << 255 << '\n';
02493 
02494   const u32 n_elem = 3 * R.n_rows * R.n_cols;
02495   podarray<u8> tmp(n_elem);
02496 
02497   u32 i = 0;
02498   for(u32 row=0; row < R.n_rows; ++row)
02499     {
02500     for(u32 col=0; col < R.n_cols; ++col)
02501       {
02502       tmp[i+0] = u8( access::tmp_real( R.at(row,col) ) );
02503       tmp[i+1] = u8( access::tmp_real( G.at(row,col) ) );
02504       tmp[i+2] = u8( access::tmp_real( B.at(row,col) ) );
02505       
02506       i+=3;
02507       }
02508     }
02509   
02510   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
02511   
02512   return f.good();
02513   }
02514 
02515 
02516 
02517 //! @}
02518