diskio_meat.hpp

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