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.seekg(pos);
01237   
01238   const std::string header = raw_header.mem;
01239   
01240   if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length()))
01241     {
01242     load_arma_ascii(x, name, f);
01243     }
01244   else
01245   if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length()))
01246     {
01247     load_arma_binary(x, name, f);
01248     }
01249   else
01250   if(P5 == header.substr(0,P5.length()))
01251     {
01252     load_pgm_binary(x, name, f);
01253     }
01254   else
01255     {
01256     load_raw_ascii(x, name, f);
01257     }
01258   }
01259 
01260 
01261 
01262 // cubes
01263 
01264 
01265 
01266 //! Save a cube as raw text (no header, human readable).
01267 template<typename eT>
01268 inline
01269 void
01270 diskio::save_raw_ascii(const Cube<eT>& x, const std::string& final_name)
01271   {
01272   arma_extra_debug_sigprint();
01273   
01274   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01275   
01276   std::fstream f(tmp_name.c_str(), std::fstream::out);
01277   
01278   if(f.is_open() == false)
01279     {
01280     arma_print("unable to write ", tmp_name);
01281     }
01282   else
01283     {
01284     save_raw_ascii(x, tmp_name, f);
01285     
01286     const bool writing_problem = (f.good() == false);
01287     
01288     arma_warn(writing_problem, "trouble writing ", tmp_name );
01289     
01290     f.flush();
01291     f.close();
01292     
01293     if(writing_problem == false)
01294       {
01295       diskio::safe_rename(tmp_name, final_name);
01296       }
01297     }
01298   }
01299 
01300 
01301 
01302 //! Save a cube as raw text (no header, human readable).
01303 template<typename eT>
01304 inline
01305 void
01306 diskio::save_raw_ascii(const Cube<eT>& x, const std::string& name, std::ostream& f)
01307   {
01308   arma_extra_debug_sigprint();
01309   
01310   u32 cell_width;
01311   
01312   // TODO: need sane values for complex numbers
01313   
01314   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01315     {
01316     f.setf(ios::scientific);
01317     f.precision(8);
01318     cell_width = 16;
01319     }
01320   
01321   for(u32 slice=0; slice < x.n_slices; ++slice)
01322     {
01323     for(u32 row=0; row < x.n_rows; ++row)
01324       {
01325       for(u32 col=0; col < x.n_cols; ++col)
01326         {
01327         f.put(' ');
01328         
01329         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01330           {
01331           f.width(cell_width);
01332           }
01333         
01334         f << x.at(row,col,slice);
01335         }
01336         
01337       f.put('\n');
01338       }
01339     }
01340   }
01341 
01342 
01343 
01344 //! Save a cube in text format (human readable),
01345 //! with a header that indicates the cube type as well as its dimensions
01346 template<typename eT>
01347 inline
01348 void
01349 diskio::save_arma_ascii(const Cube<eT>& x, const std::string& final_name)
01350   {
01351   arma_extra_debug_sigprint();
01352   
01353   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01354   
01355   std::ofstream f(tmp_name.c_str());
01356   
01357   if(f.is_open() == false)
01358     {
01359     arma_debug_print("unable to write ", tmp_name);
01360     }
01361   else
01362     {
01363     diskio::save_arma_ascii(x, tmp_name, f);
01364     
01365     const bool writing_problem = (f.good() == false);
01366     
01367     f.flush();
01368     f.close();
01369     
01370     arma_warn( writing_problem, "trouble writing ", tmp_name );
01371     
01372     if(writing_problem == false)
01373       {
01374       diskio::safe_rename(tmp_name, final_name);
01375       }
01376     }
01377   }
01378 
01379 
01380 
01381 //! Save a cube in text format (human readable),
01382 //! with a header that indicates the cube type as well as its dimensions
01383 template<typename eT>
01384 inline
01385 void 
01386 diskio::save_arma_ascii(const Cube<eT>& x, const std::string& name, std::ostream& f)
01387   {
01388   arma_extra_debug_sigprint();
01389   
01390   const ios::fmtflags orig_flags = f.flags();
01391   
01392   f << diskio::gen_txt_header(x) << '\n';
01393   f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
01394   
01395   u32 cell_width;
01396   
01397   // TODO: need sane values for complex numbers
01398   
01399   if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )
01400     {
01401     f.setf(ios::scientific);
01402     f.precision(8);
01403     cell_width = 16;
01404     }
01405     
01406   for(u32 slice=0; slice < x.n_slices; ++slice)
01407     {
01408     for(u32 row=0; row < x.n_rows; ++row)
01409       {
01410       for(u32 col=0; col < x.n_cols; ++col)
01411         {
01412         f.put(' ');
01413         
01414         if( (is_float<eT>::value == true) || (is_double<eT>::value == true) )        
01415           {
01416           f.width(cell_width);
01417           }
01418         
01419         f << x.at(row,col,slice);
01420         }
01421       
01422       f.put('\n');
01423       }
01424     }
01425   
01426   f.flags(orig_flags);
01427   }
01428 
01429 
01430 
01431 //! Save a cube in binary format,
01432 //! with a header that stores the cube type as well as its dimensions
01433 template<typename eT>
01434 inline
01435 void
01436 diskio::save_arma_binary(const Cube<eT>& x, const std::string& final_name)
01437   {
01438   arma_extra_debug_sigprint();
01439   
01440   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01441   
01442   std::ofstream f(tmp_name.c_str(), std::fstream::binary);
01443   
01444   if(f.is_open() == false)
01445     {
01446     arma_print("unable to write ", tmp_name);
01447     }
01448   else
01449     {
01450     diskio::save_arma_binary(x, tmp_name, f);
01451     
01452     const bool writing_problem = (f.good() == false);
01453     
01454     f.flush();
01455     f.close();
01456     
01457     arma_warn( writing_problem, "trouble writing ", tmp_name );
01458     
01459     if(writing_problem == false)
01460       {
01461       diskio::safe_rename(tmp_name, final_name);
01462       }
01463     }
01464   }
01465 
01466 
01467 
01468 //! Save a cube in binary format,
01469 //! with a header that stores the cube type as well as its dimensions
01470 template<typename eT>
01471 inline
01472 void
01473 diskio::save_arma_binary(const Cube<eT>& x, const std::string& name, std::ostream& f)
01474   {
01475   arma_extra_debug_sigprint();
01476   f << diskio::gen_bin_header(x) << '\n';
01477   f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n';
01478   
01479   f.write(reinterpret_cast<const char*>(x.mem), x.n_elem*sizeof(eT));
01480   }
01481 
01482 
01483 
01484 //! Load a cube as raw text (no header, human readable).
01485 //! NOTE: this is much slower than reading a file with a header.
01486 template<typename eT>
01487 inline
01488 void
01489 diskio::load_raw_ascii(Cube<eT>& x, const std::string& name)
01490   {
01491   arma_extra_debug_sigprint();
01492 
01493   Mat<eT> tmp;
01494   diskio::load_raw_ascii(tmp, name);
01495   
01496   x.set_size(tmp.n_rows, tmp.n_cols, 1);
01497 
01498   if(x.n_slices > 0)
01499     {
01500     x.slice(0) = tmp;
01501     }
01502   }
01503 
01504 
01505 
01506 //! Load a cube as raw text (no header, human readable).
01507 //! NOTE: this is much slower than reading a file with a header.
01508 template<typename eT>
01509 inline
01510 void
01511 diskio::load_raw_ascii(Cube<eT>& x, const std::string& name, std::istream& f)
01512   {
01513   arma_extra_debug_sigprint();
01514 
01515   Mat<eT> tmp;
01516   diskio::load_raw_ascii(tmp, name, f);
01517   
01518   x.set_size(tmp.n_rows, tmp.n_cols, 1);
01519 
01520   if(x.n_slices > 0)
01521     {
01522     x.slice(0) = tmp;
01523     }
01524   }
01525 
01526 
01527 
01528 //! Load a cube in text format (human readable),
01529 //! with a header that indicates the cube type as well as its dimensions
01530 template<typename eT>
01531 inline
01532 void
01533 diskio::load_arma_ascii(Cube<eT>& x, const std::string& name)
01534   {
01535   arma_extra_debug_sigprint();
01536   
01537   std::ifstream f(name.c_str());
01538   
01539   if(f.is_open() == false)
01540     {
01541     arma_extra_debug_print("unable to read ", name);
01542     }
01543   else
01544     {
01545     diskio::load_arma_ascii(x, name, f);
01546     f.close();
01547     }
01548   }
01549   
01550 
01551 
01552 //! Load a cube in text format (human readable),
01553 //! with a header that indicates the cube type as well as its dimensions
01554 template<typename eT>
01555 inline
01556 void
01557 diskio::load_arma_ascii(Cube<eT>& x, const std::string& name, std::istream& f)
01558   {
01559   arma_extra_debug_sigprint();
01560   
01561   bool load_okay = true;
01562   
01563   std::string f_header;
01564   u32 f_n_rows;
01565   u32 f_n_cols;
01566   u32 f_n_slices;
01567   
01568   f >> f_header;
01569   f >> f_n_rows;
01570   f >> f_n_cols;
01571   f >> f_n_slices;
01572   
01573   if(f_header == diskio::gen_txt_header(x))
01574     {
01575     x.set_size(f_n_rows, f_n_cols, f_n_slices);
01576 
01577     for(u32 slice=0; slice < x.n_slices; ++slice)
01578       {
01579       for(u32 row=0; row < x.n_rows; ++row)
01580         {
01581         for(u32 col=0; col < x.n_cols; ++col)
01582           {
01583           f >> x.at(row,col,slice);
01584           }
01585         }
01586       }
01587     
01588     if(f.good() == false)
01589       {
01590       arma_print("trouble reading ", name);
01591       load_okay = false;
01592       }
01593     }
01594   else
01595     {
01596     arma_print("incorrect header in ", name );
01597     load_okay = false;
01598     }
01599   
01600   if(load_okay == false)
01601     {
01602     x.reset();
01603     }
01604   }
01605 
01606 
01607 
01608 //! Load a cube in binary format,
01609 //! with a header that indicates the cube type as well as its dimensions
01610 template<typename eT>
01611 inline
01612 void
01613 diskio::load_arma_binary(Cube<eT>& x, const std::string& name)
01614   {
01615   arma_extra_debug_sigprint();
01616   
01617   std::ifstream f;
01618   f.open(name.c_str(), std::fstream::binary);
01619   
01620   if(f.is_open() == false)
01621     {
01622     arma_extra_debug_print("unable to read ", name);
01623     }
01624   else
01625     {
01626     diskio::load_arma_binary(x, name, f);
01627     f.close();
01628     }
01629   }
01630 
01631 
01632 
01633 template<typename eT>
01634 inline
01635 void
01636 diskio::load_arma_binary(Cube<eT>& x, const std::string& name, std::istream& f)
01637   {
01638   arma_extra_debug_sigprint();
01639   
01640   bool load_okay = true;
01641   
01642   std::string f_header;
01643   u32 f_n_rows;
01644   u32 f_n_cols;
01645   u32 f_n_slices;
01646   
01647   f >> f_header;
01648   f >> f_n_rows;
01649   f >> f_n_cols;
01650   f >> f_n_slices;
01651   
01652   if(f_header == diskio::gen_bin_header(x))
01653     {
01654     //f.seekg(1, ios::cur);  // NOTE: this may not be portable, as on a Windows machine a newline could be two characters
01655     f.get();
01656     
01657     x.set_size(f_n_rows, f_n_cols, f_n_slices);
01658     f.read( reinterpret_cast<char *>(x.memptr()), x.n_elem*sizeof(eT));
01659     
01660     if(f.good() == false)
01661       {
01662       arma_print("trouble reading ", name);
01663       load_okay = false;
01664       }
01665     }
01666   else
01667     {
01668     arma_print("incorrect header in ", name);
01669     load_okay = false;
01670     }
01671   
01672   if(load_okay == false)
01673     {
01674     x.reset();
01675     }
01676   }
01677 
01678 
01679 
01680 //! Try to load a cube by automatically determining its type
01681 template<typename eT>
01682 inline
01683 void
01684 diskio::load_auto_detect(Cube<eT>& x, const std::string& name)
01685   {
01686   arma_extra_debug_sigprint();
01687   
01688   std::fstream f;
01689   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
01690   
01691   if(f.is_open() == false)
01692     {
01693     arma_extra_debug_print("unable to read ", name);
01694     x.reset();
01695     }
01696   else
01697     {
01698     diskio::load_auto_detect(x, name, f); // Do the actual load
01699     f.close();
01700     }
01701   }
01702 
01703 
01704 
01705 //! Try to load a cube by automatically determining its type
01706 template<typename eT>
01707 inline
01708 void
01709 diskio::load_auto_detect(Cube<eT>& x, const std::string& name, std::istream& f)
01710   {
01711   arma_extra_debug_sigprint();
01712   
01713   static const std::string ARMA_CUB_TXT = "ARMA_CUB_TXT";
01714   static const std::string ARMA_CUB_BIN = "ARMA_CUB_BIN";
01715   static const std::string           P6 = "P6";
01716   
01717   podarray<char> raw_header(ARMA_CUB_TXT.length() + 1);
01718   
01719   std::streampos pos = f.tellg();
01720   
01721   f.read(raw_header.memptr(), ARMA_CUB_TXT.length());
01722   raw_header[ARMA_CUB_TXT.length()] = '\0';
01723   
01724   f.seekg(pos);
01725   
01726   const std::string header = raw_header.mem;
01727   
01728   if(ARMA_CUB_TXT == header.substr(0, ARMA_CUB_TXT.length()))
01729     {
01730     load_arma_ascii(x, name, f);
01731     }
01732   else
01733   if(ARMA_CUB_BIN == header.substr(0, ARMA_CUB_BIN.length()))
01734     {
01735     load_arma_binary(x, name, f);
01736     }
01737   else
01738   if(P6 == header.substr(0,P6.length()))
01739     {
01740     load_ppm_binary(x, name, f);
01741     }
01742   else
01743     {
01744     load_raw_ascii(x, name, f);
01745     }
01746   }
01747 
01748 
01749 
01750 
01751 
01752 // fields
01753 
01754 
01755 
01756 template<typename T1>
01757 inline
01758 void
01759 diskio::save_arma_binary(const field<T1>& x, const std::string& final_name)
01760   {
01761   arma_extra_debug_sigprint();
01762   
01763   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01764   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01765   
01766   if(f.is_open() == false)
01767     {
01768     arma_print("couldn't write ", tmp_name);
01769     }
01770   else
01771     {
01772     diskio::save_arma_binary(x, tmp_name, f);
01773 
01774     const bool writing_problem = (f.good() == false);
01775 
01776     arma_warn(writing_problem, "trouble writing ", tmp_name );
01777 
01778     f.flush();
01779     f.close();
01780 
01781     if(writing_problem == false)
01782       {
01783       diskio::safe_rename(tmp_name, final_name);
01784       }
01785     }
01786   }
01787 
01788 template<typename T1>
01789 inline
01790 void
01791 diskio::save_arma_binary(const field<T1>& x, const std::string& name, std::ostream& f)
01792   {
01793   arma_extra_debug_sigprint();
01794   
01795   arma_type_check< (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) >::apply();
01796   
01797   f << "ARMA_FLD_BIN" << '\n';
01798   f << x.n_rows << '\n';
01799   f << x.n_cols << '\n';
01800   
01801   for(u32 i=0; i<x.n_elem; ++i)
01802     {
01803     diskio::save_arma_binary(x[i], name, f);
01804     }
01805   }
01806 
01807 
01808 
01809 template<typename T1>
01810 inline
01811 void
01812 diskio::load_arma_binary(field<T1>& x, const std::string& name)
01813   {
01814   arma_extra_debug_sigprint();
01815   
01816   std::ifstream f( name.c_str(), std::fstream::binary );
01817   
01818   if(f.is_open() == false)
01819     {
01820     arma_extra_debug_print("unable to read ", name);
01821     }
01822   else
01823     {
01824     diskio::load_arma_binary(x, name, f);
01825     f.close();
01826     }
01827   }
01828 
01829 
01830 
01831 template<typename T1>
01832 inline
01833 void
01834 diskio::load_arma_binary(field<T1>& x, const std::string& name, std::istream& f)
01835   {
01836   arma_extra_debug_sigprint();
01837   
01838   arma_type_check< (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) >::apply();
01839   
01840   bool load_okay = true;
01841   
01842   std::string f_type;
01843   f >> f_type;
01844   
01845   if(f_type != "ARMA_FLD_BIN")
01846     {
01847     arma_print("unsupported field type in ", name);
01848     load_okay = false;
01849     }
01850   else
01851     {
01852     u32 f_n_rows;
01853     u32 f_n_cols;
01854   
01855     f >> f_n_rows;
01856     f >> f_n_cols;
01857     
01858     x.set_size(f_n_rows, f_n_cols);
01859     
01860     f.get();      
01861     
01862     for(u32 i=0; i<x.n_elem; ++i)
01863       {
01864       diskio::load_arma_binary(x[i], name, f);
01865       
01866       if(f.good() == false)
01867         {
01868         arma_print("trouble reading ", name);
01869         load_okay = false;
01870         break;
01871         }
01872       }
01873     }
01874 
01875   if(load_okay == false)
01876     {
01877     x.reset();
01878     }
01879   }
01880 
01881 
01882 
01883 inline
01884 void
01885 diskio::save_std_string(const field<std::string>& x, const std::string& final_name)
01886   {
01887   arma_extra_debug_sigprint();
01888   
01889   const std::string tmp_name = diskio::gen_tmp_name(final_name);
01890   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
01891   
01892   if(f.is_open() == false)
01893     {
01894     arma_print("couldn't write ", tmp_name);
01895     }
01896   else
01897     {
01898     diskio::save_std_string(x, tmp_name, f);
01899     
01900     const bool writing_problem = (f.good() == false);
01901     
01902     f.flush();
01903     f.close();
01904     
01905     if(writing_problem == false)
01906       {
01907       diskio::safe_rename(tmp_name, final_name);
01908       }
01909     }
01910   }
01911 
01912 
01913 
01914 inline
01915 void
01916 diskio::save_std_string(const field<std::string>& x, const std::string& name, std::ostream& f)
01917   {
01918   arma_extra_debug_sigprint();
01919   
01920   for(u32 row=0; row<x.n_rows; ++row)
01921   for(u32 col=0; col<x.n_cols; ++col)
01922     {
01923     f << x.at(row,col);
01924     
01925     if(col < x.n_cols-1)
01926       {
01927       f << ' ';
01928       }
01929     else
01930       {
01931       f << '\n';
01932       }
01933     }
01934   
01935   const bool writing_problem = (f.good() == false);
01936   
01937   arma_warn(writing_problem, "trouble writing ", name );
01938   }
01939 
01940 
01941 
01942 inline
01943 void
01944 diskio::load_std_string(field<std::string>& x, const std::string& name)
01945   {
01946   arma_extra_debug_sigprint();
01947   
01948   std::ifstream f( name.c_str() );
01949   
01950   if(f.is_open() == false)
01951     {
01952     arma_print("unable to read ", name);
01953     }
01954   else
01955     {
01956     diskio::load_std_string(x, name, f);
01957     
01958     f.close();
01959     }
01960   }
01961 
01962 
01963 
01964 inline
01965 void
01966 diskio::load_std_string(field<std::string>& x, const std::string& name, std::istream& f)
01967   {
01968   arma_extra_debug_sigprint();
01969   
01970   bool load_okay = true;
01971   
01972   //
01973   // work out the size
01974   
01975   u32 f_n_rows = 0;
01976   u32 f_n_cols = 0;
01977   
01978   bool f_n_cols_found = false;
01979   
01980   std::string line_string;
01981   std::string token;
01982   
01983   while( (f.good() == true) && (load_okay == true) )
01984     {
01985     std::getline(f, line_string);
01986     if(line_string.size() == 0)
01987       break;
01988     
01989     std::stringstream line_stream(line_string);
01990     
01991     u32 line_n_cols = 0;
01992     while (line_stream >> token)
01993       line_n_cols++;
01994     
01995     if(f_n_cols_found == false)
01996       {
01997       f_n_cols = line_n_cols;
01998       f_n_cols_found = true;
01999       }
02000     else
02001       {
02002       if(line_n_cols != f_n_cols)
02003         {
02004         load_okay = false;
02005         arma_print("inconsistent number of columns in ", name );
02006         }
02007       }
02008     
02009     ++f_n_rows;
02010     }
02011     
02012   if(load_okay == true)
02013     {
02014     f.clear();
02015     f.seekg(0, ios::beg);
02016     //f.seekg(start);
02017     
02018     x.set_size(f_n_rows, f_n_cols);
02019   
02020     for(u32 row=0; row < x.n_rows; ++row)
02021       {
02022       for(u32 col=0; col < x.n_cols; ++col)
02023         {
02024         f >> x.at(row,col);
02025         }
02026       }
02027     }
02028   
02029   if(f.good() == false)
02030     {
02031     load_okay = false; 
02032     arma_print("trouble reading ", name );
02033     }
02034   
02035   if(load_okay == false)
02036     {
02037     x.reset();
02038     }
02039   }
02040 
02041 
02042 
02043 //! Try to load a field by automatically determining its type
02044 template<typename T1>
02045 inline
02046 void
02047 diskio::load_auto_detect(field<T1>& x, const std::string& name)
02048   {
02049   arma_extra_debug_sigprint();
02050   
02051   std::fstream f;
02052   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02053   
02054   if(f.is_open() == false)
02055     {
02056     arma_extra_debug_print("unable to read ", name);
02057     x.reset();
02058     }
02059   else
02060     {
02061     diskio::load_auto_detect(x, name, f); // Do the actual load
02062     f.close();
02063     }
02064   }
02065 
02066 
02067 
02068 //! Try to load a field by automatically determining its type
02069 template<typename T1>
02070 inline
02071 void
02072 diskio::load_auto_detect(field<T1>& x, const std::string& name, std::istream& f)
02073   {
02074   arma_extra_debug_sigprint();
02075   
02076   arma_type_check<is_Mat<T1>::value == false>::apply();
02077   
02078   static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN";
02079   static const std::string           P6 = "P6";
02080   
02081   podarray<char> raw_header(ARMA_FLD_BIN.length() + 1);
02082   
02083   std::streampos pos = f.tellg();
02084   f.read(raw_header.memptr(), ARMA_FLD_BIN.length());
02085   f.seekg(pos);
02086 
02087   raw_header[ARMA_FLD_BIN.length()] = '\0';
02088   
02089   const std::string header = raw_header.mem;
02090   
02091   if(ARMA_FLD_BIN == header.substr(0,ARMA_FLD_BIN.length()))
02092     {
02093     load_arma_binary(x, name, f);
02094     }
02095   else
02096   if(P6 == header.substr(0,P6.length()))
02097     {
02098     load_ppm_binary(x, name, f);
02099     }
02100   else
02101     {
02102     arma_print("unsupported header in ", name);
02103     x.reset();
02104     }
02105   }
02106 
02107 
02108 
02109 //
02110 // handling of PPM images
02111 
02112 
02113 template<typename eT>
02114 inline
02115 void
02116 diskio::load_ppm_binary(Cube<eT>& x, const std::string& name)
02117   {
02118   arma_extra_debug_sigprint();
02119   
02120   std::fstream f;
02121   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02122   
02123   if(f.is_open() == false)
02124     {
02125     arma_extra_debug_print("unable to read ", name);
02126     }
02127   else
02128     {
02129     diskio::load_ppm_binary(x, name, f);
02130     f.close();
02131     }
02132   }
02133 
02134 
02135 
02136 template<typename eT>
02137 inline
02138 void
02139 diskio::load_ppm_binary(Cube<eT>& x, const std::string& name, std::istream& f)
02140   {
02141   arma_extra_debug_sigprint();
02142   
02143   bool load_okay = true;
02144   
02145   std::string f_header;
02146   f >> f_header;
02147   
02148   if(f_header == "P6")
02149     {
02150     u32 f_n_rows = 0;
02151     u32 f_n_cols = 0;
02152     int f_maxval = 0;
02153   
02154     diskio::pnm_skip_comments(f);
02155   
02156     f >> f_n_cols;
02157     diskio::pnm_skip_comments(f);
02158   
02159     f >> f_n_rows;
02160     diskio::pnm_skip_comments(f);
02161   
02162     f >> f_maxval;
02163     f.get();
02164     
02165     if( (f_maxval > 0) || (f_maxval <= 65535) )
02166       {
02167       x.set_size(f_n_rows, f_n_cols, 3);
02168       
02169       if(f_maxval <= 255)
02170         {
02171         const u32 n_elem = 3*f_n_cols*f_n_rows;
02172         podarray<u8> tmp(n_elem);
02173         
02174         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
02175         
02176         u32 i = 0;
02177         
02178         //cout << "f_n_cols = " << f_n_cols << endl;
02179         //cout << "f_n_rows = " << f_n_rows << endl;
02180         
02181         
02182         for(u32 row=0; row < f_n_rows; ++row)
02183           {
02184           for(u32 col=0; col < f_n_cols; ++col)
02185             {
02186             x.at(row,col,0) = eT(tmp[i+0]);
02187             x.at(row,col,1) = eT(tmp[i+1]);
02188             x.at(row,col,2) = eT(tmp[i+2]);
02189             i+=3;
02190             }
02191           
02192           }
02193         }
02194       else
02195         {
02196         const u32 n_elem = 3*f_n_cols*f_n_rows;
02197         podarray<u16> tmp(n_elem);
02198         
02199         f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
02200         
02201         u32 i = 0;
02202         
02203         for(u32 row=0; row < f_n_rows; ++row)
02204           {
02205           for(u32 col=0; col < f_n_cols; ++col)
02206             {
02207             x.at(row,col,0) = eT(tmp[i+0]);
02208             x.at(row,col,1) = eT(tmp[i+1]);
02209             x.at(row,col,2) = eT(tmp[i+2]);
02210             i+=3;
02211             }
02212           
02213           }
02214         
02215         }
02216       
02217       }
02218     
02219     if(f.good() == false)
02220       {
02221       arma_print("trouble reading ", name);
02222       load_okay = false;
02223       }
02224     
02225     }
02226   else
02227     {
02228     arma_print("unsupported header in ", name);
02229     load_okay = false;
02230     }
02231   
02232   if(load_okay == false)
02233     {
02234     x.reset();
02235     }
02236   }
02237 
02238 
02239 
02240 template<typename eT>
02241 inline
02242 void
02243 diskio::save_ppm_binary(const Cube<eT>& x, const std::string& final_name)
02244   {
02245   arma_extra_debug_sigprint();
02246 
02247   const std::string tmp_name = diskio::gen_tmp_name(final_name);
02248   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
02249   
02250   if(f.is_open() == false)
02251     {
02252     arma_print("couldn't write ", tmp_name);
02253     }
02254   else
02255     {
02256     diskio::save_ppm_binary(x, tmp_name, f);
02257     
02258     const bool writing_problem = (f.good() == false);
02259     f.flush();
02260     f.close();
02261     
02262     if(writing_problem == false)
02263       {
02264       diskio::safe_rename(tmp_name, final_name);
02265       }
02266     }
02267   }
02268 
02269 
02270 
02271 template<typename eT>
02272 inline
02273 void
02274 diskio::save_ppm_binary(const Cube<eT>& x, const std::string& name, std::ostream& f)
02275   {
02276   arma_extra_debug_sigprint();
02277   
02278   arma_debug_check( (x.n_slices != 3), "diskio::save_ppm_binary(): given cube must have exactly 3 slices" );
02279   
02280   const u32 n_elem = 3 * x.n_rows * x.n_cols;
02281   podarray<u8> tmp(n_elem);
02282 
02283   u32 i = 0;
02284   for(u32 row=0; row < x.n_rows; ++row)
02285     {
02286     for(u32 col=0; col < x.n_cols; ++col)
02287       {
02288       tmp[i+0] = u8( x.at(row,col,0) );
02289       tmp[i+1] = u8( x.at(row,col,1) );
02290       tmp[i+2] = u8( x.at(row,col,2) );
02291       
02292       i+=3;
02293       }
02294     }
02295   
02296   f << "P6" << '\n';
02297   f << x.n_cols << '\n';
02298   f << x.n_rows << '\n';
02299   f << 255 << '\n';
02300 
02301   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
02302   
02303   const bool writing_problem = (f.good() == false);
02304   
02305   arma_warn(writing_problem, "trouble writing ", name );
02306   }
02307 
02308 
02309 
02310 template<typename T1>
02311 inline
02312 void
02313 diskio::load_ppm_binary(field<T1>& x, const std::string& name)
02314   {
02315   arma_extra_debug_sigprint();
02316   
02317   std::fstream f;
02318   f.open(name.c_str(), std::fstream::in | std::fstream::binary);
02319   
02320   if(f.is_open() == false)
02321     {
02322     arma_extra_debug_print("unable to read ", name);
02323     }
02324   else
02325     {
02326     diskio::load_ppm_binary(x, name, f);
02327     f.close();
02328     }
02329   }  
02330 
02331 
02332 
02333 template<typename T1>
02334 inline
02335 void
02336 diskio::load_ppm_binary(field<T1>& x, const std::string& name, std::istream& f)
02337   {
02338   arma_extra_debug_sigprint();
02339   
02340   arma_type_check<is_Mat<T1>::value == false>::apply();
02341   typedef typename T1::elem_type eT;
02342   
02343   bool load_okay = true;
02344   
02345   std::string f_header;
02346   f >> f_header;
02347   
02348   if(f_header == "P6")
02349     {
02350     u32 f_n_rows = 0;
02351     u32 f_n_cols = 0;
02352     int f_maxval = 0;
02353   
02354     diskio::pnm_skip_comments(f);
02355   
02356     f >> f_n_cols;
02357     diskio::pnm_skip_comments(f);
02358   
02359     f >> f_n_rows;
02360     diskio::pnm_skip_comments(f);
02361   
02362     f >> f_maxval;
02363     f.get();
02364     
02365     if( (f_maxval > 0) || (f_maxval <= 65535) )
02366       {
02367       x.set_size(3);
02368       Mat<eT>& R = x(0);
02369       Mat<eT>& G = x(1);
02370       Mat<eT>& B = x(2);
02371       
02372       R.set_size(f_n_rows,f_n_cols);
02373       G.set_size(f_n_rows,f_n_cols);
02374       B.set_size(f_n_rows,f_n_cols);
02375       
02376       if(f_maxval <= 255)
02377         {
02378         const u32 n_elem = 3*f_n_cols*f_n_rows;
02379         podarray<u8> tmp(n_elem);
02380         
02381         f.read( reinterpret_cast<char*>(tmp.memptr()), n_elem);
02382         
02383         u32 i = 0;
02384         
02385         //cout << "f_n_cols = " << f_n_cols << endl;
02386         //cout << "f_n_rows = " << f_n_rows << endl;
02387         
02388         
02389         for(u32 row=0; row < f_n_rows; ++row)
02390           {
02391           for(u32 col=0; col < f_n_cols; ++col)
02392             {
02393             R.at(row,col) = eT(tmp[i+0]);
02394             G.at(row,col) = eT(tmp[i+1]);
02395             B.at(row,col) = eT(tmp[i+2]);
02396             i+=3;
02397             }
02398           
02399           }
02400         }
02401       else
02402         {
02403         const u32 n_elem = 3*f_n_cols*f_n_rows;
02404         podarray<u16> tmp(n_elem);
02405         
02406         f.read( reinterpret_cast<char *>(tmp.memptr()), 2*n_elem);
02407         
02408         u32 i = 0;
02409         
02410         for(u32 row=0; row < f_n_rows; ++row)
02411           {
02412           for(u32 col=0; col < f_n_cols; ++col)
02413             {
02414             R.at(row,col) = eT(tmp[i+0]);
02415             G.at(row,col) = eT(tmp[i+1]);
02416             B.at(row,col) = eT(tmp[i+2]);
02417             i+=3;
02418             }
02419           
02420           }
02421         
02422         }
02423       
02424       }
02425     
02426     if(f.good() == false)
02427       {
02428       arma_print("trouble reading ", name);
02429       load_okay = false;
02430       }
02431     
02432     }
02433   else
02434     {
02435     arma_print("unsupported header in ", name);
02436     load_okay = false;
02437     }
02438   
02439   if(load_okay == false)
02440     {
02441     x.reset();
02442     }
02443   
02444   }
02445 
02446 
02447 
02448 template<typename T1>
02449 inline
02450 void
02451 diskio::save_ppm_binary(const field<T1>& x, const std::string& final_name)
02452   {
02453   arma_extra_debug_sigprint();
02454   
02455   const std::string tmp_name = diskio::gen_tmp_name(final_name);
02456   std::ofstream f( tmp_name.c_str(), std::fstream::binary );
02457   
02458   if(f.is_open() == false)
02459     {
02460     arma_print("couldn't write ", tmp_name);
02461     }
02462   else
02463     {
02464     diskio::save_ppm_binary(x, tmp_name, f);
02465     const bool writing_problem = (f.good() == false);
02466     
02467     f.flush();
02468     f.close();
02469     
02470     if(writing_problem == false)
02471       {
02472       diskio::safe_rename(tmp_name, final_name);
02473       }
02474     }
02475   }
02476   
02477 
02478 
02479 template<typename T1>
02480 inline
02481 void
02482 diskio::save_ppm_binary(const field<T1>& x, const std::string& name, std::ostream& f)
02483   {
02484   arma_extra_debug_sigprint();
02485   
02486   arma_type_check<is_Mat<T1>::value == false>::apply();
02487   
02488   typedef typename T1::elem_type eT;
02489   
02490   arma_debug_check( (x.n_elem != 3), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
02491   
02492   bool same_size = true;
02493   for(u32 i=1; i<3; ++i)
02494     {
02495     if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) )
02496       {
02497       same_size = false;
02498       break;
02499       }
02500     }
02501   
02502   arma_debug_check( (same_size != true), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" );
02503   
02504   const Mat<eT>& R = x(0);
02505   const Mat<eT>& G = x(1);
02506   const Mat<eT>& B = x(2);
02507   
02508   f << "P6" << '\n';
02509   f << R.n_cols << '\n';
02510   f << R.n_rows << '\n';
02511   f << 255 << '\n';
02512 
02513   const u32 n_elem = 3 * R.n_rows * R.n_cols;
02514   podarray<u8> tmp(n_elem);
02515 
02516   u32 i = 0;
02517   for(u32 row=0; row < R.n_rows; ++row)
02518     {
02519     for(u32 col=0; col < R.n_cols; ++col)
02520       {
02521       tmp[i+0] = u8( access::tmp_real( R.at(row,col) ) );
02522       tmp[i+1] = u8( access::tmp_real( G.at(row,col) ) );
02523       tmp[i+2] = u8( access::tmp_real( B.at(row,col) ) );
02524       
02525       i+=3;
02526       }
02527     }
02528   
02529   f.write(reinterpret_cast<const char*>(tmp.mem), n_elem);
02530   
02531   const bool writing_problem = (f.good() == false);
02532   
02533   arma_warn(writing_problem, "trouble writing ", name );
02534   }
02535 
02536 
02537 
02538 //! @}
02539