Home | Doxygen Documentation | Tutorials | Developer Tools (restricted)

matfile/matfile_concepts/src/Devices/InputDevice.hh
Go to the documentation of this file.
00001 /*
00002     This file is part of matfile.
00003 
00004     Copyright (C) 2010-2011 Andrea Arteaga <arteagaa@student.ethz.ch>
00005 
00006     matfile is free software: you can redistribute it and/or modify
00007     it under the terms of the GNU Lesser General Public License as published
00008     by the Free Software Foundation, either version 3 of the License, or
00009     (at your option) any later version.
00010 
00011     matfile is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU Lesser General Public License for more details.
00015 
00016     You should have received a copy of the GNU Lesser General Public License
00017     along with matfile.  If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 
00020 #ifndef INPUTDEVICE_HPP_
00021 #define INPUTDEVICE_HPP_
00022 
00023 #include "basics/debug.hh"
00024 #include "basics/exceptions.hh"
00025 
00026 // Debug flags
00027 #define InputDeviceElem_D 0
00028 #define InputDeviceFind_D 0
00029 
00030 
00031 class bad_matfile : public std::exception
00032 {
00033 private:
00034   std::string what_;
00035 
00036 public:
00037   bad_matfile() {
00038     what_ = "Bad matfile";
00039   }
00040 
00041   virtual ~bad_matfile() throw() { }
00042 
00043   virtual const char* what() throw() {
00044     return what_.c_str();
00045   }
00046 };
00047 
00048 class NotExistingMatrix : public concepts::ExceptionBase
00049 {
00050 public:
00051   NotExistingMatrix
00052   (const std::string& matrix, const std::string& matfile) throw() : 
00053     concepts::ExceptionBase("", 0, "", "")
00054     , matrix_(matrix), matfile_(matfile) {
00055   }
00056 
00057   virtual ~NotExistingMatrix() throw() { }
00058 protected:
00059   std::ostream& info(std::ostream& os) const throw() {
00060     return os << '[' << file_ << ", line " << line_ << "] " << function_ 
00061               << " -- not existing matrix " << matrix_ 
00062               << " in file " << matfile_;
00063   }
00064 private:
00065   const std::string matrix_, matfile_;
00066 };
00067 
00076 class InputDevice
00077 {
00078 public:
00086   template<typename charT>
00087   InputDevice(const std::basic_string<charT>& filename);
00088 
00094   template<typename charT>
00095   InputDevice(const charT* filename);
00096 
00104   std::string description() const { return description_; }
00105 
00112   std::string subsystem() const { return subsystem_; }
00113 
00120   miINT16_t version() const { return version_; }
00121 
00131   bool inverse_endian() const { return inverse_endian_; }
00132 
00138   const std::vector<MatrixInfo>& info() const { return data_; }
00139 
00140   /* *
00141    * \brief Returns a numeric array.
00142    *
00143    * Returns the numeric array with the given name.
00144    *
00145    * \param name The name of the desidered matrix.
00146    */
00147   //DenseMatrix getNumArray(const std::string& name) const;
00148 
00149 
00155   std::vector<MatrixInfo>::iterator begin() {
00156     return data_.begin();
00157   }
00158 
00164   std::vector<MatrixInfo>::const_iterator begin() const {
00165     return data_.begin();
00166   }
00167 
00173   std::vector<MatrixInfo>::iterator end() {
00174     return data_.end();
00175   }
00176 
00182   std::vector<MatrixInfo>::const_iterator end() const {
00183     return data_.end();
00184   }
00185 
00186 
00192   template<class WrapperClass>
00193   void readArray(const std::string& name, WrapperClass& wrapper) {
00194     for (std::vector<MatrixInfo>::iterator i = begin(); i != end(); ++i) {
00195       if (i->_name == name) {
00196         std::istringstream stream(i->_buffer, std::ios::binary);
00197         detail::Reader<WrapperClass>::read(i->_buffer, wrapper);
00198         return;
00199       }
00200     }
00201   } 
00202   
00203   /*
00204    * Operator for handling Dimensions of Matrix in matfile. The Inputstring should be the name of an existing 
00205    * Matrix in in the matfile, related to the the Inputdevice. Otherwise an exceptions is thrown.
00206    */
00207   MatrixInfo operator[](const std::string) const;
00208   
00209   
00210   std::vector<MatrixInfo>::const_iterator  find(const std::string) const;
00211 
00212 private:
00213   std::string filename_;
00214 
00215   std::string description_;
00216   std::string subsystem_;
00217   miINT16_t version_;
00218   bool inverse_endian_;
00219 
00220   std::vector<MatrixInfo> data_;
00221 
00222 private:
00223   void extract_header(std::istream&);
00224   void extract_info(std::istream&);
00225     
00226   
00227 };
00228 
00229 
00230 template<typename charT>
00231 InputDevice::InputDevice(const std::basic_string<charT>& filename)
00232   : filename_(filename)
00233 {
00234   std::ifstream fs(filename.c_str(), std::ifstream::binary | std::ifstream::in);
00235 
00236   fs.seekg(0, std::ios::end);
00237   int endfile = fs.tellg();
00238 
00239   fs.seekg(0);
00240   extract_header(fs);
00241   fs.seekg(128);
00242 
00243   //Extract arrays
00244   int pos;
00245   while ((pos = fs.tellg()) != endfile) {
00246     miINT32_t tag[2];
00247     fs.read(reinterpret_cast<char*>(tag), 8);
00248     fs.seekg(pos);
00249     extract_info(fs);
00250     fs.seekg(pos + 8 + tag[1]);
00251   }
00252 }
00253 
00254 template<typename charT>
00255 InputDevice::InputDevice(const charT* filename)
00256 : filename_(filename)
00257 {
00258   std::ifstream fs(filename, std::ifstream::binary | std::ifstream::in);
00259 
00260   fs.seekg(0, std::ios::end);
00261   int endfile = fs.tellg();
00262 
00263   fs.seekg(0);
00264   extract_header(fs);
00265   fs.seekg(128);
00266 
00267   //Extract arrays
00268   int pos;
00269   while ((pos = fs.tellg()) != endfile) {
00270     miINT32_t tag[2];
00271     fs.read(reinterpret_cast<char*>(tag), 8);
00272     fs.seekg(pos);
00273     extract_info(fs);
00274     fs.seekg(pos + 8 + tag[1]);
00275   }
00276 }
00277 
00278 
00279 void InputDevice::extract_header(std::istream& fs)
00280 {
00281   //Description
00282   char descstr[117];
00283   fs.read(descstr, 116);
00284   descstr[116] = '\0';
00285   description_ = descstr;
00286 
00287   //Subsystem data offset
00288   char subsysstr[9];
00289   fs.read(subsysstr, 8);
00290   subsysstr[8] = '\0';
00291   subsystem_ = subsysstr;
00292 
00293   //Version
00294   fs.read(reinterpret_cast<char*>(&version_), 2);
00295 
00296   //Endian
00297   char e[2];
00298   fs.read(e, 2);
00299   if (e[0] == 'I' || e[1] == 'M')
00300     inverse_endian_ = false;
00301   else if(e[0] == 'M' || e[1] == 'I')
00302     inverse_endian_ = true;
00303   else
00304     throw bad_matfile();
00305 }
00306 
00307 
00308 void InputDevice::extract_info(std::istream& fs)
00309 {
00310   data_.push_back(MatrixInfo());
00311   MatrixInfo &rd = data_.back();
00312 
00313   std::string &buffer = rd._buffer;
00314 
00315   // Read tag
00316   buffer.resize(8);
00317   fs.read(&buffer[0], 8);
00318   miINT32_t *tag = reinterpret_cast<miINT32_t*>(&buffer[0]);
00319 
00320   if (tag[0] == miMATRIX) {
00321     buffer.resize(8+tag[1]);
00322     fs.read(&buffer[8], tag[1]);
00323 
00324     // Extract flags
00325     miUINT32_t *flags = reinterpret_cast<miUINT32_t*>(&buffer[16]);
00326     rd._class = *flags & 255;
00327     rd._isComplex = ((*flags & 2048) != 0);
00328 
00329     // Extract dimension
00330     std::vector<miINT32_t> &_dimensions = rd._dimensions;
00331     miINT32_t *dimTag = reinterpret_cast<miINT32_t*>(&buffer[24]);
00332     miINT32_t ndim = *(dimTag+1)/4;
00333     _dimensions.resize(ndim);
00334     memcpy(&_dimensions[0], dimTag+2, *(dimTag+1));
00335 
00336     // Extract name
00337     std::string &_name = rd._name;
00338     miINT32_t *nameTag = dimTag + 2 + (ndim+1)/2*2;
00339     miINT32_t nameLength = *(nameTag+1);
00340     _name.resize(nameLength);
00341     memcpy(&_name[0], nameTag+2, nameLength);
00342   } else if (tag[0] == miCOMPRESSED) {
00343     miINT32_t compressedSize = tag[1];
00344     std::string &compressed = rd._buffer;
00345     std::string uncompressed;
00346     compressed.resize(8+compressedSize);
00347     fs.read(&compressed[8], compressedSize);
00348 
00349     // Call zlib
00350     z_stream strm;
00351     strm.zalloc = Z_NULL;
00352     strm.zfree = Z_NULL;
00353     strm.opaque = Z_NULL;
00354     strm.avail_in = 0;
00355     strm.next_in = Z_NULL;
00356     inflateInit(&strm); //TODO: control return value
00357 
00358     uncompressed.reserve(32);
00359     strm.next_in = reinterpret_cast<Bytef*>(&compressed[8]);
00360     strm.avail_in = compressedSize;
00361     strm.next_out = reinterpret_cast<Bytef*>(&uncompressed[0]);
00362     strm.avail_out = 32;
00363     inflate(&strm, Z_NO_FLUSH); //TODO: control return value
00364 
00365     // Extract flags
00366     miUINT32_t *flags = reinterpret_cast<miUINT32_t*>(&uncompressed[16]);
00367     rd._class = *flags & 255;
00368     rd._isComplex = ((*flags & 2048) != 0);
00369 
00370     // Dimensions size
00371     miINT32_t dimSize = *reinterpret_cast<miINT32_t*>(&uncompressed[28]);
00372     strm.next_out = reinterpret_cast<Bytef*>(&uncompressed[0]);
00373     strm.avail_out = 16;
00374     inflate(&strm, Z_NO_FLUSH);
00375 
00376     // Extract dimensions
00377     std::vector<miINT32_t> &dimensions = rd._dimensions;
00378     dimensions.resize(dimSize/4);
00379     memcpy(&dimensions[0], &uncompressed[0], dimSize);
00380 
00381     // Name tag
00382     char *nameTag = &uncompressed[0] + (dimSize+7)/8*8;
00383     if (*reinterpret_cast<miINT32_t*>(nameTag) > 255) {
00384       //Short tag
00385       miINT32_t nameDimension = *reinterpret_cast<miINT16_t*>(nameTag+2);
00386       if (nameDimension > 4)
00387         throw bad_matfile();
00388       rd._name.assign(nameTag + 4, nameDimension);
00389     } else {
00390       miINT32_t nameDimension = *reinterpret_cast<miINT32_t*>(nameTag + 4);
00391       uncompressed.resize(nameDimension);
00392       strm.next_out = reinterpret_cast<Bytef*>(&uncompressed[0]);
00393       strm.avail_out = nameDimension;
00394       inflate(&strm, Z_NO_FLUSH);
00395       rd._name = uncompressed;
00396     }
00397   } else
00398     throw bad_matfile();
00399 }
00400  
00401 MatrixInfo InputDevice::operator[](const std::string matrixName) const 
00402 {
00403   std::vector<MatrixInfo>::const_iterator iter = this->find(matrixName);
00404   DEBUGL(InputDeviceElem_D, "Searching for matrix " << matrixName);
00405   
00406   if(iter == this->end())
00407     throw conceptsException
00408       (NotExistingMatrix(matrixName, filename_));
00409 
00410   return *iter;
00411 }
00412  
00413  
00414 std::vector<MatrixInfo>::const_iterator 
00415 InputDevice::find(const std::string matrixName) const 
00416 {
00417   DEBUGL(InputDeviceFind_D, "Searching for matrix " << matrixName);
00418   std::vector<MatrixInfo>::const_iterator iter = this->begin(); 
00419 
00420   while(iter != this->end() && iter->getName() != matrixName)
00421     ++iter;
00422 
00423   DEBUGL(InputDeviceFind_D, "done.");
00424   return iter;
00425 }
00426 
00427 #endif  /* INPUTDEVICE_HPP_ */

Home | Doxygen Documentation | Tutorials | Developer Tools (restricted)