Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/med.git] / src / MEDMEM / MEDMEM_EnsightUtils.hxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 // File      : MEDMEM_EnsightUtils.hxx
21 // Created   : Tue May 27 12:24:11 2008
22 // Author    : Edward AGAPOV (eap)
23 //
24 #ifndef MEDMEM_EnsightUtils_HeaderFile
25 #define MEDMEM_EnsightUtils_HeaderFile
26
27 #include "MEDMEM_GenDriver.hxx"
28 #include "MEDMEM_Exception.hxx"
29 #include "MEDMEM_DriverTools.hxx"
30 #include "MEDMEM_Mesh.hxx"
31 //#include "MEDMEM_Field.hxx"
32
33 #include <set>
34 #include <float.h>
35 #include <cmath>
36
37 #ifdef WNT
38 # define isnan _isnan
39 #else
40 # include <unistd.h>
41 #endif
42
43 namespace MEDMEM {
44
45   // ==============================================================================
46   /*!
47    * \brief Functions to set writing format.
48    * Default format is EnSight6 ASCII
49    */
50   // ==============================================================================
51
52   enum EnSightFormat { ENSIGHT_6, ENSIGHT_GOLD };
53
54   void MEDMEM_EXPORT setEnSightFormatForWriting (EnSightFormat format, bool isBinary);
55
56   EnSightFormat getEnSightFormatForWriting();
57   bool          isBinaryEnSightFormatForWriting();
58
59   // ==============================================================================
60   /*!
61    * \brief To raise or not if MEDMEM-EnSight incompatibility encounters or suspected
62    *
63    * Default is to raise.
64    * To ignore incompatibility is useful for debug of EnSigt reading and
65    * for suppressing exceptions in some suspicious cases, for example writing
66    * several meshes and fields.
67    * Incompatibility exception includes "EnSight-MEDMEM compatibility problem" string.
68    * Not all incompatibility exceptions can be suppressed.
69    */
70   // ==============================================================================
71
72   void MEDMEM_EXPORT setIgnoreIncompatibility(bool toIgnore=true);
73 }
74
75 namespace MEDMEM {
76   class ENSIGHT_MESH_RDONLY_DRIVER;
77   class ENSIGHT_FIELD_RDONLY_DRIVER;
78   class ENSIGHT_MESH_WRONLY_DRIVER;
79   class ENSIGHT_FIELD_WRONLY_DRIVER;
80 }
81
82 // ==============================================================================
83 namespace MEDMEM_ENSIGHT { // INTERNAL MATTERS
84 // ==============================================================================
85
86   class _CaseFileDriver;
87   class _CaseFileDriver_User;
88   struct _InterMed;
89   struct _SubPart;
90   struct _SubPartDesc;
91   struct _Support;
92   typedef std::set< _SubPartDesc > _SupportDesc;
93
94   using namespace MED_EN;
95   using namespace MEDMEM;
96   using namespace std;
97
98   // ---------------------------------------------------------------
99   /*!
100    * \brief Prepend "EnSight-MEDMEM compatibility problem" to the text
101    *        of an exception
102    */
103   STRING compatibilityPb(const string& exceptionText);
104
105   // ---------------------------------------------------------------
106   /*!
107    * \brief To ignore incompatibility or not
108    */
109   bool   toIgnoreIncompatibility();
110
111   // ---------------------------------------------------------------
112   //!< search substring in a string
113   bool contains( const char* what, const char* inString );
114
115   // ---------------------------------------------------------------
116   /*!
117    * \brief EnSight element type name and an array to convert
118    *        med connectivity to EnSight one
119    */
120   struct TEnSightElemType
121   {
122     string             _name;
123     vector<int>        _medIndex;
124     medGeometryElement _medType;
125   };
126   // ---------------------------------------------------------------
127   /*!
128    * \brief Return EnSight type corresponding to med one
129    */
130   const TEnSightElemType& getEnSightType(medGeometryElement medType);
131
132   // ---------------------------------------------------------------
133   /*!
134    * \brief Return EnSight type having a given name
135    */
136   const TEnSightElemType& getEnSightType(const string& typeName);
137
138   // ---------------------------------------------------------------
139   /*!
140    * \brief Return true if typeName begins with "g_"
141    */
142   inline bool isGhostType(const string& typeName)
143   { return ( typeName[0] == 'g' && typeName[1] == '_'); }
144
145   // ---------------------------------------------------------------
146   /*!
147    * \brief Maximal EnSight line length
148    */
149   const int MAX_LINE_LENGTH = 80;
150
151   // ---------------------------------------------------------------
152   /*!
153    * \brief Maximal length of field name in EnSight 
154    */
155   const int MAX_FIELD_NAME_LENGTH = 19;
156
157   // ---------------------------------------------------------------
158   /*!
159    * \brief Maximal length of field name in EnSight 
160    */
161   const string ILLEGAL_FIELD_NAME_CHARACTERS = " !@#$^()[]*/+-"; // '.,' ????
162
163   // ---------------------------------------------------------------
164   /*!
165    * \brief Width of fields in ASCII file
166    */
167   const int INT_WIDTH_6 = 8;
168   const int INT_WIDTH_GOLD = 10;
169   const int FLT_WIDTH = 12;
170
171   // ---------------------------------------------------------------
172   /*!
173    * \brief EnSight space dimension
174    */
175   const int SPACE_DIM = 3;
176
177   // ---------------------------------------------------------------
178   /*!
179    * \brief Time step data boundaries in single-file mode
180    */
181   static const char* TIME_STEP_BEG = "BEGIN TIME STEP";
182   static const char* TIME_STEP_END = "END TIME STEP";
183   const size_t TIME_STEP_BEG_LEN = 15;
184   const size_t TIME_STEP_END_LEN = 13;
185   
186
187   // ---------------------------------------------------------------
188   /*!
189    * \brief Cast value to float and protect from overflow
190    */
191   static inline float _toFloat (const double & value) {
192     if ( value >  FLT_MAX ) return  FLT_MAX;
193     if ( value < -FLT_MAX ) return -FLT_MAX;
194     if ( isnan( value ))    throw MEDEXCEPTION(compatibilityPb("NaN value not allowed"));
195     return float( value );
196   }
197   static inline float _toFloat (const int & value) { return float( value ); }
198   static inline float _toFloat (const long & value) { return float( value ); }
199
200 // ==============================================================================
201 /*!
202  * \brief Reader/writer of EnSight Case file
203  *
204  * Apart from it's major job, it
205  * o assures cooperation of MED and Mesh/Field drivers so that the Case file created
206  *   by MED driver is not overwritten by Mesh driver called by MED driver.
207  */
208 // ==============================================================================
209
210 class _CaseFileDriver
211 {
212 public:
213   _CaseFileDriver(const string& fileName, const _CaseFileDriver_User* creator);
214   ~_CaseFileDriver();
215
216   void read() throw (MEDEXCEPTION);
217
218   // ---------------
219   // reading meshes
220   // ---------------
221
222   int  getNbMeshes() const;
223
224   //!< sets all data necessary for meshDriver::read()
225   void setDataFileName(const int meshIndex, ENSIGHT_MESH_RDONLY_DRIVER* meshDriver);
226
227   // ---------------
228   // reading fields
229   // ---------------
230
231   int  getNbVariables() const;
232
233   int  getNbVarSteps(const int variableIndex);
234
235   //!< return variable index by variable name, return 0 if none found
236   int  getVariableIndex(const string & varName) const;
237
238   //!< sets all data necessary for fieldDriver::read(), returns meshIndex
239   int setDataFileName(const int                    varIndex,
240                       const int                    stepIndex,
241                       ENSIGHT_FIELD_RDONLY_DRIVER* fieldDriver);
242
243   // --------
244   // writing
245   // --------
246
247   //!< add a mesh to the Case file
248   void addMesh(const ENSIGHT_MESH_WRONLY_DRIVER* meshDriver);
249
250   //!< add a field to the Case file
251   void addField(const ENSIGHT_FIELD_WRONLY_DRIVER * fieldDriver);
252
253   //!< write and set necessary data to added drivers
254   void write() throw (MEDEXCEPTION);
255
256 private:
257
258   //!< throw if Case file has not been read else return false
259   bool checkWasRead() const throw (MEDEXCEPTION);
260
261   //!< replace '*' in file name if any and return index in a file and time
262   int  fixWildCardName(const int           timeStep,
263                        const std::string & ts,
264                        const std::string & fs,
265                        std::string &       fileName,
266                        std::string &       time);
267
268   // --------------------------------------------------------------------------------
269   // GEOMETRY section
270   // model: [ts] [fs] filename [change_coords_only]
271   //        ts = time set number as specified in TIME section. This is optional.
272   //        fs = corresponding file set number as specified in FILE section below.
273   //            (Note, if you specify fs, then ts is no longer optional and must also be
274   //            specified.)
275   // filename = The filename of the appropriate file.
276   //            -> Model or measured filenames for a static geometry case, as well as match,
277   //                   boundary, and rigid_body filenames will not contain "*" wildcards.
278   //            -> Model or measured filenames for a changing geometry case will
279   //                  contain "*" wildcards.
280   // change_coords_only =         The option to indicate that the changing geometry (as
281   //                              indicated by wildcards in the filename) is coords only.
282   //                              Otherwise, changing geometry connectivity will be
283   //                              assumed.
284   struct _Model {
285     string _timeSetNumber, _fileSetNumber; //!< ts, fs
286     string _fileName;                      //!< filename
287     string _change_coords_only;
288   };
289   // --------------------------------------------------------------------------------
290   // VARIABLE section
291   // ts             = The corresponding time set number (or index) as specified in TIME
292   //                  section below. This is only required for transient constants and
293   //                  variables.
294   // fs             = The corresponding file set number (or index) as specified in FILE
295   //                  section below.
296   //                   (Note, if you specify fs, then ts is no longer optional and must
297   //                    also be specified.)
298   // description    = The variable (GUI) name (ex. Pressure, Velocity, etc.)
299   // const_value(s) = The constant value. If constants change over time, then ns (see
300   //                  TIME section below) constant values of ts.
301   // cvfilename     = The filename containing the constant values, one value per time step.
302   // filename       = The filename of the variable file. Note: only transient filenames
303   //                     contain "*" wildcards.
304   // Re_fn          = The filename for the file containing the real values of the complex
305   //                  variable.
306   // Im_fn          = The filename for the file containing the imaginary values of the
307   //                  complex variable.
308   // freq           = The corresponding harmonic frequency of the complex variable.
309   //                  For complex variables where harmonic frequency is undefined,
310   //                  simply use the text string: UNDEFINED.
311   struct _Variable {
312     string _type;                          //!< constant|scalar|etc.
313     string _name;                          //!< description
314     string _timeSetNumber, _fileSetNumber; //!< [ts], [fs]
315     string _fileNameOrData;                //!< [cv]filename|Re_fn Im_fn freq|const_value(s)
316   };
317   // --------------------------------------------------------------------------------
318   // FILE section
319   // fs = file set number. This is the number referenced in the GEOMETRY
320   //      and VARIABLE sections above.
321   // ns = number of transient steps
322   // fi = file index number in the file name (replaces "*" in the filenames)
323   struct _FileSet {
324     int                    _number;        //!< fs
325     std::list<int>         _nbStepsInFile; //!< ns
326     std::list<std::string> _fileIndex;     //!< fi
327   };
328   // --------------------------------------------------------------------------------
329   // TIME section
330   struct _TimeSet {
331     int                      _number;    //!< ts
332     std::vector<std::string> _fileIndex; //!< fn
333     std::vector<std::string> _times;     //!< times
334
335     bool operator==(const _TimeSet& ts) const
336     { return ( _fileIndex == ts._fileIndex && _times == ts._times ); }
337   };
338
339 private:
340
341   std::string               _fileName;
342   std::string               _directory;
343   EnSightFormat             _format;
344   _Model                    _model;
345   std::map< int, _Variable> _variables; //!< map order number to variable data
346   std::map< int, _TimeSet > _timeSets;  //!< map ts to time set data
347   std::map< int, _FileSet > _fileSets;  //!< map fs to file set data
348
349   const _CaseFileDriver_User* _user; //!< mesh/field driver
350
351   std::list<ENSIGHT_MESH_WRONLY_DRIVER*> _meshDrivers; //!< added meshes
352
353   typedef std::map<std::string, std::list< ENSIGHT_FIELD_WRONLY_DRIVER* > > TFieldDriversByName;
354   TFieldDriversByName _fieldDrivers; //!< added field drivers groupped by name
355
356   //!< to block all calls from a mesh/field driver governed by med driver
357   bool                      _blocked;
358 };
359
360   // ==============================================================================
361 /*!
362  * \brief Base of all Ensight drivers.
363  * It stores data passed from case file
364  */
365 // ==============================================================================
366
367 class MEDMEM_EXPORT _CaseFileDriver_User: public GENDRIVER
368 {
369 protected:
370
371   _CaseFileDriver_User(const std::string&     caseFileName="",
372                        MED_EN::med_mode_acces mode=MED_EN::RDWR);
373
374   const std::string& getCaseFileName() const { return GENDRIVER::_fileName; }
375
376   const std::string& getDataFileName() const { return _dataFileName; }
377
378   bool isGoldFormat() const { return _isGoldFormat; }
379
380   //!< returns true if there are several meshes/fields in a data file
381   bool isSingleFileMode() const { return _singleFileMode; }
382
383   //!< index of meshes/fields in a data file, zero for static mesh/feild
384   int  getIndexInDataFile() const { return _indexInDataFile; }
385
386   //!< true if there are time steps, i.e. getTime() has sense
387   bool isTransientMode() const { return _transientMode; }
388
389   //!< time of a step
390   double getTime() const { return atof(_time.c_str()); }
391
392   // -------------------------------
393   // pass mesh data to field driver
394   // -------------------------------
395
396   //!< for mesh driver to store data
397   void setInterData(_InterMed* imed);
398
399   //!< for field driver to get mesh data
400   _InterMed* getInterData();
401
402   _SubPart* getSubPart(const _SubPartDesc & descriptor) throw (MEDEXCEPTION);
403
404   _Support* getSupport(const _SupportDesc & descriptor,
405                        const medEntityMesh  entity)  throw (MEDEXCEPTION);
406
407
408 public:
409   //!< return part number to write support with, zero in failure case
410   int getPartNumber(const SUPPORT* support) const;
411
412   static bool canOpenFile(const string& fileName, med_mode_acces mode);
413
414   static void getSupportNodes(const SUPPORT* sup, map<int, int> & nodeIds);
415
416   //!< analyse if data file is binary
417   static bool isBinaryDataFile(const string& dataFileName);
418
419   static bool isTimeStepBeginning(const string& line)
420   { return ( line == TIME_STEP_BEG ); }
421
422   static bool isTimeStepEnd(const char* line)
423   { return ( strncmp( line, TIME_STEP_END, TIME_STEP_END_LEN ) == 0 ); }
424
425   static bool isToWriteEntity(const medEntityMesh entity, const GMESH* mesh);
426
427   ~_CaseFileDriver_User();
428
429   void merge( const GENDRIVER& driver);
430
431 private:
432
433   friend class _CaseFileDriver;
434
435   // members set by _CaseFileDriver::setDataFileName(...) and _CaseFileDriver::write()
436   std::string _dataFileName;
437   bool        _isGoldFormat;
438   bool        _transientMode;   //!< true if there are time steps
439   bool        _singleFileMode;  //!< only one or several meshes/fields in a data file 
440   int         _indexInDataFile; //!< which meshes/fields in a data file
441   std::string _time;            //!< time of a step
442
443   _InterMed* _imed;       //!< to be used by field driver
444   string     _imedMapKey; //!< key in the map storing mesh data for usage by field drv
445
446 };
447
448 // ==============================================================================
449 /*!
450  * \brief Descriptor of the sub-part: part number and elem type or "block" etc.
451  */
452 // ==============================================================================
453
454 struct _SubPartDesc: public std::pair<int, std::string >
455 {
456   _SubPartDesc(int                partNumber=-1,
457                const std::string& typeName="")
458     : std::pair<int, std::string > ( partNumber, typeName ) {}
459
460   const int&    partNumber() const { return this->first; }
461   const string& typeName()   const { return this->second; }
462
463   static _SubPartDesc globalCoordDesc() { return _SubPartDesc(-1,"coordinates"); }
464 };
465
466 std::ostream& operator << (std::ostream& os, const _SubPartDesc& desc);
467
468 // ==============================================================================
469 /*!
470  * \brief A type within EnSight part. It stores data needed by field driver to
471  * know nb of values of a geometric type and what place they get in MED group
472  */
473 // ==============================================================================
474
475 struct _SubPart: public _SubPartDesc
476 {
477   // _SubPart describes both nodes and elements since "block" describes the both.
478   // Mesh driver sets
479   //   for cells: myNbCells and myCellGroupIndex
480   //   for nodes: myNbNodes and myFirstNode
481   // GROUP of cells is created always,
482   // GROUP of nodes, only if nodal field support is required (see getSupport())
483
484   int                  myNbCells;        //!< nb of cells
485   int                  myCellGroupIndex; //!< cell group id in _InterMed
486   _groupe::TMailleIter myFirstCell;      //!< pointer to the first cell
487
488   int                  myNbNodes;        //!< nb of nodes
489   mutable int          myNodeGroupIndex; //!< node group id in _InterMed
490   _maille::TNoeud      myFirstNode;      //!< pointer to the first node
491
492   _SubPart(int                partNumber=-1,
493            const std::string& typeName="")
494     : _SubPartDesc(partNumber,typeName),
495       myNbCells(0), myCellGroupIndex(-1),
496       myNbNodes(0), myNodeGroupIndex(-1)
497   {}
498
499   _SubPartDesc getDescriptor() const { return _SubPartDesc( partNumber(), typeName() ); }
500 };
501
502 // ==============================================================================
503 /*!
504  * \brief EnSight variable support composed of _SubPart's 
505  */
506 // ==============================================================================
507
508 struct _Support
509 {
510   _groupe * myCellGroup; //!< cell group in _InterMed
511   _groupe * myNodeGroup; //!< node group in _InterMed
512
513   _Support(): myCellGroup(0), myNodeGroup(0) {}
514
515   void     setGroup( _groupe* g );
516   SUPPORT* medSupport( medEntityMesh entity );
517
518   int getIndex( const pair<const int,_noeud>& node);
519   int getIndex( const _groupe::TMaille&       cell);
520
521 //   medGeometryElement getType( const pair<const int,_noeud>& node);
522 //   medGeometryElement getType( const _groupe::TMaille&       cell);
523 };
524
525 // ==============================================================================
526 /*!
527  * \brief Structure to temporarily store data read from EnSight geom file
528  */
529 // ==============================================================================
530
531 struct _InterMed : public _intermediateMED
532 {
533   MESH* _medMesh;
534   bool  _isOwnMedMesh; //!< whether to delete _medMesh
535   int   _nbUsers;      //!< to know when to delete _medMesh
536
537   bool  _needSubParts; //!< true if there are fields needing _SubPart data
538
539   map< _SubPartDesc, _SubPart > _subPartDescribed;
540
541   map< _SupportDesc, _Support > _supportDescribed;
542
543   void addSubPart(const _SubPart& subPart);
544
545   ~_InterMed();
546 };
547
548 // ==============================================================================
549 /*!
550  * \brief Simple owner of C array
551  */
552 // ==============================================================================
553
554 template <typename T> struct _ValueOwner {
555   T * myValues;
556   _ValueOwner(T* values):myValues(values) {}
557   ~_ValueOwner() { if ( myValues ) delete [] myValues; }
558   operator T*() { return myValues; }
559 private:
560   _ValueOwner(const _ValueOwner& other) {} // forbidden
561 };
562 // instantiations
563 typedef _ValueOwner<char>   TStrOwner;
564 typedef _ValueOwner<int>    TIntOwner;
565 typedef _ValueOwner<double> TDblOwner;
566 typedef _ValueOwner<float>  TFltOwner;
567
568 // ==============================================================================
569 /*!
570  * \brief Iterator on values of a component
571  */
572 // ==============================================================================
573
574 template <typename T> class _ValueIterator
575 {
576 protected:
577   const T* myPtr;
578   int      myDelta;
579 public:
580   _ValueIterator() // by default next() returns zero
581     : myPtr(zeroPtr()), myDelta( 0 ) {}
582
583   _ValueIterator(const T* values, int delta): myPtr(values-delta), myDelta(delta) {}
584
585   const T & next() { myPtr += myDelta; return *myPtr; }
586
587   static const T* zeroPtr() { static T a0 = 0; return &a0; }
588 };
589
590 // ==============================================================================
591 /*!
592  * \brief Reader of ASCII files
593  */
594 // ==============================================================================
595
596 class _ASCIIFileReader
597 {
598 public:
599   _ASCIIFileReader(const string& fileName) throw (MEDEXCEPTION);
600
601   ~_ASCIIFileReader();
602
603   bool eof();
604
605   string getWord(); //!< never throws
606
607   int    getInt()  throw (MEDEXCEPTION) {
608     if ( eof() ) throw MEDEXCEPTION("Unexpected EOF");
609     return strtol(_ptr, &_ptr, 10);
610   }
611   float  getReal() throw (MEDEXCEPTION) {
612     if ( eof() ) throw MEDEXCEPTION("Unexpected EOF");
613 #ifdef WNT
614 #else
615     return strtof(_ptr, &_ptr);
616 #endif
617   }
618   //!< needed after getWord(), getInt() or getReal() to get a next line
619   void toNextLine() {
620     while (isspace(*_ptr)) if ((++_ptr)[-1]=='\n') break;
621   }
622   char*  getLine() throw (MEDEXCEPTION);
623
624   const char* getCurrentPtr() const { return _ptr; }
625
626   bool lookAt( const char* text );
627
628   bool isTimeStepBeginning();
629
630   bool isTimeStepEnd();
631
632   //!< read out given data
633   void skip(int nbVals, int nbPerLine, int valWidth);
634
635   //!< read out width chars and nbLines line-ends
636   void skip(int width, int nbLines);
637
638   template <class T>
639   char* convertReals( const int          nbValues,
640                       const char*        undefValue = 0,
641                       set<int>*          undefIndices = 0,
642                       const vector<int>* partialIndices = 0,
643                       const int          nbPartialComponents = 0)
644     throw (MEDEXCEPTION)
645   {
646     T* result = new T[ nbValues ];
647     T* ptrT = result;
648     if ( undefValue ) // fill undefIndices
649     {
650       undefIndices->clear();
651       float undef = atof( undefValue );
652       for ( int i = 0; i < nbValues; ++i, ++ptrT ) {
653         float value = getReal();
654         (*ptrT) = (T) value;
655         if ( value == undef )
656           undefIndices->insert( undefIndices->end(), i+1 );
657       }
658     }
659     else if ( partialIndices )
660     {
661       // partial variables are available in GOLD format only where
662       // values are in no-interlace
663       int shift = 1;
664       for ( int j = 1; j <= nbPartialComponents; ++j ) {
665         vector<int>::const_iterator i = partialIndices->begin(), iEnd = partialIndices->end();
666         while ( i != iEnd )
667           result[ *i++ - shift ] = (T) getReal();
668         shift += nbValues;
669       }
670     }
671     else
672     {
673       for ( int i = 0; i < nbValues; ++i, ++ptrT )
674         (*ptrT) = (T) getReal();
675     }
676     return (char*) result;
677   }
678
679   //static string strip(char* & str);
680
681   //!< divide a string into two parts
682   static int  split(const string& str,
683                     string &      part1,
684                     string &      part2,
685                     const char    separator=' ',
686                     const bool    fromBack=false);
687
688   //!< divide a string into parts, return nb of parts
689   static int  split(const string&       str,
690                     std::list<string> & parts,
691                     const char          separator=' ',
692                     const bool          fromBack=false);
693
694   //!< check if string contains only digits
695   static bool isDigit(const string& str, const bool real=false);
696
697 private:
698
699   int   _file;
700   char* _start; // buffer start
701   char* _ptr;   // beginning of not read portion
702   char* _eptr;  // end of buffer contents
703
704   bool  _isWin;
705
706 };// class _ASCIIFileReader
707
708
709 // ==============================================================================
710 /*!
711  * \brief Reader of binary files
712  */
713 // ==============================================================================
714
715 class _BinaryFileReader
716 {
717 public:
718   _BinaryFileReader(const string& fileName) throw (MEDEXCEPTION);
719
720   ~_BinaryFileReader();
721
722   void rewind(); //!< rewind the file backward
723
724   void swapBytes() //!< turn on swapping bytes
725   { _mySwapBytes = true; }
726
727   int moreValuesAvailable() const; //!< size of not read file portion in sizeof(int)
728
729   bool eof();
730
731   void skip(int size) throw (MEDEXCEPTION);
732
733   void skipTimeStepBeginning() throw (MEDEXCEPTION);
734
735   char*   getLine()      throw (MEDEXCEPTION)
736   { return get<char>(80); }
737
738   int*    getInt(int nb) throw (MEDEXCEPTION)
739   { return get<int>(nb,_mySwapBytes); }
740
741   float*  getFlt(int nb) throw (MEDEXCEPTION)
742   { return get<float>(nb,_mySwapBytes); }
743
744   ssize_t getPosition() const { return _pos; }
745
746   template <class T>
747   char* convertReals( const int          nbValues,
748                       const char*        undefValue = 0,
749                       set<int>*          undefIndices = 0,
750                       const vector<int>* partialIndices = 0,
751                       const int          nbPartialComponents = 0 )
752     throw (MEDEXCEPTION)
753   {
754     T* result = new T[ nbValues ];
755     T* ptrT = result, *endT = result + nbValues;
756     int nb = partialIndices ? partialIndices->size() * nbPartialComponents : nbValues;
757     TFltOwner fltData( getFlt( nb ));
758     float* ptrFlt = fltData;
759     if ( undefValue ) // fill undefIndices
760     {
761       undefIndices->clear();
762       float undef = atof( undefValue );
763       while ( ptrT < endT ) {
764         float value = *ptrFlt++;
765         *ptrT++ = (T) value;
766         if ( std::abs( value - undef ) <= FLT_MIN )
767           undefIndices->insert( undefIndices->end(), ptrT - result );
768       }
769     }
770     else if ( partialIndices )
771     {
772       // partial variables are available in GOLD format only where
773       // values are in no-interlace
774       int shift = 1;
775       for ( int j = 1; j <= nbPartialComponents; ++j ) {
776         vector<int>::const_iterator i = partialIndices->begin(), iEnd = partialIndices->end();
777         while ( i != iEnd )
778           result[ *i++ - shift ] = (T) *ptrFlt++;
779         shift += nbValues;
780       }
781     }
782     else
783     {
784       while ( ptrT < endT )
785         *ptrT++ = (T) *ptrFlt++;
786     }
787     return (char*) result;
788   }
789 private:
790
791   int          _file;         //!< descriptor
792   MEDEXCEPTION _exception;    //!< ready to raise exception
793   ssize_t      _pos, _maxPos; //!< current position and end position
794   bool         _mySwapBytes;  //!< to swap bytes
795
796   //!< read any data from file
797   template <typename T> T* get(int nb, bool inverseBytes=false)
798   {
799     size_t bufSize = nb * sizeof( T );
800     if ( int(bufSize) > _maxPos - _pos )
801       throw _exception;
802     T* buf = new T[ nb ];
803 #ifdef WNT
804 #else
805     ssize_t nBytesRead = ::read (_file, buf, bufSize );
806     _pos += nBytesRead;
807     if ( int(nBytesRead) < int(bufSize) ) {
808       delete buf;
809       throw _exception;
810     }
811     if ( inverseBytes ) { // swap bytes
812       int* intBuf = ((int*) buf) - 1;
813       int* bufEnd = (int*)((char*) buf + nBytesRead);
814       while ( ++intBuf < bufEnd )
815         *intBuf = MEDMEM::swapBytes( *intBuf );
816     }
817 #endif
818     return buf;
819   }
820 };
821
822 // ==============================================================================
823 /*!
824  * \brief Writer of binary files
825  */
826 // ==============================================================================
827
828 class _BinaryFileWriter
829 {
830 public:
831   _BinaryFileWriter(const string& fileName)  throw (MEDEXCEPTION);
832
833   ~_BinaryFileWriter();
834
835   //!< write a string
836   void addString(const char* str)            throw (MEDEXCEPTION);
837
838   //!< write a string
839   void addString(const string& str)          throw (MEDEXCEPTION)
840   { addString( str.c_str() ); }
841
842   //!< write an integer value
843   void addInt(const int value)               throw (MEDEXCEPTION)
844   { add( &value, 1 ); }
845   
846   //!< write integer values
847   void addInt(const int* data, int nbValues) throw (MEDEXCEPTION)
848   { add( data, nbValues ); }
849
850   //!< write integer values
851   void addInt(const vector< int >& data)     throw (MEDEXCEPTION)
852   { add( &data[0], data.size() ); }
853   
854   //!< write any data as floats
855   template <typename T>
856   void addReal(const T* data, int nbValues)  throw (MEDEXCEPTION)
857   {
858     _RealData realData( data, nbValues );
859     add( realData.values(), nbValues );
860   }
861
862   //!< write any data as floats
863   template <class TValueIterator>
864   void addReal(vector< TValueIterator >& componentIt,
865                const int                 nbValues,
866                const medModeSwitch       interlace)  throw (MEDEXCEPTION)
867   {
868     _RealData realData( componentIt, nbValues, interlace );
869     add( realData.values(), nbValues * componentIt.size() );
870   }
871
872 private:
873
874   int          _file; //!< descriptor
875   MEDEXCEPTION _exception; //!< ready to raise exception
876     
877   //!< write any data to file
878   template <typename T>
879   void add(const T* data, int nbValues) throw (MEDEXCEPTION)
880   {
881 #ifdef WNT
882 #else
883     ssize_t nbWritten = ::write( _file, (const void *) data, nbValues * sizeof(T));
884     if ( nbWritten < 0 ) throw _exception;
885 #endif
886   }
887   // ------------------------------------------------------------------------
888   /*!
889    * \brief Container of temporary data converting any data to floats
890    */
891   // ------------------------------------------------------------------------
892   class _RealData {
893     PointerOf<float> _floatData;
894   public:
895     //!< return pointer to float array
896     const float* values() { return _floatData; }
897
898     //!< convert nbValues to floats
899     template <typename T>
900     _RealData(const T* data, int nbValues)
901     {
902       if ( sizeof( T ) == sizeof( float ))
903         _floatData.set((const float*) data);
904       else {
905         _floatData.set(nbValues);
906         float* floatPtr = _floatData;
907         const T *tPtr = data, *tEnd = data + nbValues;
908         while ( tPtr < tEnd )
909           *floatPtr++ = _toFloat( *tPtr++ );
910       }
911     }
912
913     //!< convert nbValues to floats in given interlace
914     template <class TValueIterator>
915     _RealData(vector< TValueIterator >& componentIt,
916               const int                 nbValues,
917               const medModeSwitch       interlace)
918     {
919       int nbComponents = componentIt.size();
920       _floatData.set(nbValues * nbComponents);
921       float* floatPtr = _floatData;
922       if ( interlace == MED_FULL_INTERLACE && nbComponents > 1 ) {
923         for ( int i = 0; i < nbValues; ++i )
924           for ( int j = 0; j < nbComponents; ++j )
925             *floatPtr++ = _toFloat( componentIt[ j ].next() );
926       }
927       else {
928         for ( int j = 0; j < nbComponents; ++j ) {
929           TValueIterator & values = componentIt[ j ];
930           for ( int i = 0; i < nbValues; ++i )
931             *floatPtr++ = _toFloat( values.next() );
932         }
933       } 
934     }
935   }; // class _RealData
936
937 }; // class _BinaryFileWriter
938
939 }// namespace MEDMEM_ENSIGHT
940
941 #endif