Salome HOME
1b683759bd8f037a7dc0be150a9fd3c3da9bec7c
[modules/med.git] / src / MEDMEM / MEDMEM_GibiMeshDriver.cxx
1 #include <algorithm>
2
3 #include "MEDMEM_GibiMeshDriver.hxx"
4
5 #include "MEDMEM_DriversDef.hxx"
6
7 #include "MEDMEM_Family.hxx"
8 #include "MEDMEM_Group.hxx"
9 #include "MEDMEM_Coordinate.hxx"
10 #include "MEDMEM_Connectivity.hxx"
11 #include "MEDMEM_Mesh.hxx"
12 #include "MEDMEM_CellModel.hxx"
13 #include "MEDMEM_define.hxx"
14 #include "MEDMEM_DriverTools.hxx"
15
16 /////
17 using namespace std;
18 using namespace MED_EN;
19 using namespace MEDMEM;
20 /////
21
22
23 /////
24 const size_t GIBI_MESH_DRIVER::nb_geometrie_gibi;
25
26 const medGeometryElement GIBI_MESH_DRIVER::geomGIBItoMED[nb_geometrie_gibi] =
27      {   /*1 */ MED_POINT1 ,/*2 */ MED_SEG2   ,/*3 */ MED_SEG3   ,/*4 */ MED_TRIA3  ,/*5 */ MED_NONE   ,
28        /*6 */ MED_TRIA6  ,/*7 */ MED_NONE   ,/*8 */ MED_QUAD4  ,/*9 */ MED_NONE   ,/*10*/ MED_QUAD8  ,
29        /*11*/ MED_NONE   ,/*12*/ MED_NONE   ,/*13*/ MED_NONE   ,/*14*/ MED_HEXA8  ,/*15*/ MED_HEXA20 ,
30        /*16*/ MED_PENTA6 ,/*17*/ MED_PENTA15,/*18*/ MED_NONE   ,/*19*/ MED_NONE   ,/*20*/ MED_NONE   ,
31        /*21*/ MED_NONE   ,/*22*/ MED_NONE   ,/*23*/ MED_TETRA4 ,/*24*/ MED_TETRA10,/*25*/ MED_PYRA5  ,
32        /*26*/ MED_PYRA13 ,/*27*/ MED_NONE   ,/*28*/ MED_NONE   ,/*29*/ MED_NONE   ,/*30*/ MED_NONE   ,
33        /*31*/ MED_NONE   ,/*32*/ MED_NONE   ,/*33*/ MED_NONE   ,/*34*/ MED_NONE   ,/*35*/ MED_NONE   ,
34        /*36*/ MED_NONE   ,/*37*/ MED_NONE   ,/*38*/ MED_NONE   ,/*39*/ MED_NONE   ,/*40*/ MED_NONE   ,
35        /*41*/ MED_NONE   ,/*42*/ MED_NONE   ,/*43*/ MED_NONE   ,/*44*/ MED_NONE   ,/*45*/ MED_NONE   ,
36        /*46*/ MED_NONE   ,/*47*/ MED_NONE   };
37 /////
38
39 // Every memory allocation made in the MedDriver members function are desallocated in the Mesh destructor 
40
41 GIBI_MESH_DRIVER::GIBI_MESH_DRIVER():
42   GENDRIVER(),
43   _ptrMesh(( MESH *)MED_NULL),
44   // A VOIR _medIdt(MED_INVALID),
45   _meshName("")
46 {
47 }
48
49 GIBI_MESH_DRIVER::GIBI_MESH_DRIVER(const string & fileName,
50                                    MESH * ptrMesh,
51                                    MED_EN::med_mode_acces accessMode): 
52   GENDRIVER(fileName,accessMode),
53   _ptrMesh(ptrMesh)
54   // A VOIR _medIdt(MED_INVALID), 
55 {
56 //   _meshName=fileName.substr(0,fileName.rfind("."));
57     // mesh name construction from fileName
58     const string ext=".sauve"; // expected extension
59     string::size_type pos=fileName.find(ext,0);
60     string::size_type pos1=fileName.rfind('/');
61     _meshName = string(fileName,pos1+1,pos-pos1-1); //get rid of directory & extension
62     SCRUTE(_meshName);
63 }
64   
65 GIBI_MESH_DRIVER::GIBI_MESH_DRIVER(const GIBI_MESH_DRIVER & driver): 
66   GENDRIVER(driver),
67   _ptrMesh(driver._ptrMesh),
68   // A VOIR _medIdt(MED_INVALID), 
69   _meshName(driver._meshName)
70 {
71 }
72
73 GIBI_MESH_DRIVER::~GIBI_MESH_DRIVER()
74 {
75 }
76
77 void GIBI_MESH_DRIVER::open()
78   throw (MEDEXCEPTION)
79 {
80     const char * LOC = "GIBI_MESH_DRIVER::open()" ;
81     BEGIN_OF(LOC);
82
83     _gibi.open(_fileName.c_str(), ios::in);
84     if(_gibi)
85         _status = MED_OPENED;
86     else
87     {
88         _status = MED_CLOSED;
89         throw MEDEXCEPTION(LOCALIZED(STRING(LOC)<<" Could not open file "<<_fileName<<" in mode ios::in"));
90     }
91   END_OF(LOC);
92 }
93   
94 void GIBI_MESH_DRIVER::close()
95   throw (MEDEXCEPTION)
96 {
97     const char * LOC = "GIBI_MESH_DRIVER::close() " ;
98     BEGIN_OF(LOC);
99     if ( _status == MED_OPENED) 
100     {
101         _gibi.close();
102         _status = MED_CLOSED;
103     }
104     END_OF(LOC);
105 }
106
107 void    GIBI_MESH_DRIVER::setMeshName(const string & meshName) { _meshName = meshName; };
108 string  GIBI_MESH_DRIVER::getMeshName() const { return _meshName; };
109
110
111 //---------------------------------- RDONLY PART -------------------------------------------------------------
112
113 GIBI_MESH_RDONLY_DRIVER::GIBI_MESH_RDONLY_DRIVER(): GIBI_MESH_DRIVER()
114 {
115 }
116
117 GIBI_MESH_RDONLY_DRIVER::GIBI_MESH_RDONLY_DRIVER(const string & fileName,
118         MESH * ptrMesh):
119 GIBI_MESH_DRIVER(fileName,ptrMesh,MED_RDONLY)
120
121     MESSAGE("GIBI_MESH_RDONLY_DRIVER::GIBI_MESH_RDONLY_DRIVER(const string & fileName, MESH * ptrMesh) has been created");
122 }
123
124     GIBI_MESH_RDONLY_DRIVER::GIBI_MESH_RDONLY_DRIVER(const GIBI_MESH_RDONLY_DRIVER & driver): 
125 GIBI_MESH_DRIVER(driver)
126 {
127 }
128
129 GIBI_MESH_RDONLY_DRIVER::~GIBI_MESH_RDONLY_DRIVER()
130 {
131     //MESSAGE("GIBI_MESH_RDONLY_DRIVER::~GIBI_MESH_RDONLY_DRIVER() has been destroyed");
132 }
133   
134 GENDRIVER * GIBI_MESH_RDONLY_DRIVER::copy(void) const
135 {
136     return new GIBI_MESH_RDONLY_DRIVER(*this);
137 }
138
139 void GIBI_MESH_RDONLY_DRIVER::read(void) throw (MEDEXCEPTION)
140 {
141     const char * LOC = "GIBI_MESH_RDONLY_DRIVER::read() : " ;
142     BEGIN_OF(LOC);
143
144     if (_status!=MED_OPENED)
145         throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << "The _idt of file " << _fileName << " is : "  
146                                                  <<  " (the file is not opened)." )) ;
147
148     // LECTURE DES DONNEES DS FICHIER GIBI
149
150     _intermediateMED medi; // structure de données intermédiaire pour conversion gibi->med
151     string buf_ligne; // pour lire une ligne
152     const char* enregistrement_type="ENREGISTREMENT DE TYPE";
153     std::vector<int> numero_noeuds; // tableau de travail (indices)
154
155
156     while ( getline(_gibi, buf_ligne) ) // boucle externe de recherche de "ENREGISTREMENT DE TYPE"
157     {
158         string::size_type pos = buf_ligne.find(enregistrement_type);
159         if ( pos==string::npos ){
160             continue; // "ENREGISTREMENT DE TYPE" non trouvé -> on lit la ligne suivante
161         }
162         // lecture du numéro d'enregistrement
163         int numero_enregistrement;
164         istringstream buf(buf_ligne.c_str()+strlen(enregistrement_type)+1);
165         buf >> numero_enregistrement;
166
167         enum { ENREG_TYPE_2=2, ENREG_TYPE_4=4}; // énumération des types d'enregistrement traités
168         int niveau, niveau_erreur;
169         unsigned space_dimension,nb_reels;
170         int numero_pile, nb_objets_nommes, nb_objets, nb_indices;
171         string s1,s2,s3,s4,s5,s6,s7; // temporary strings
172         int i1; //temporary int
173         double d1; //temporary double
174         vector<int> indices_objets_nommes;
175         vector<string> objets_nommes;
176
177         switch (numero_enregistrement)
178           {
179           case ENREG_TYPE_4:
180             MESSAGE(LOC << "---- Traitement enregistrement de type 4");
181             _gibi >> s1 >> niveau >> s2 >> s3 >> niveau_erreur >> s4 >> space_dimension;
182             if ( !_gibi || s1!="NIVEAU" || s3!="ERREUR" || s4!="DIMENSION" ) // verification mots -cles
183               throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Could not read file " << _fileName 
184                                            << " : syntax error in type 4 record"));
185             break;
186
187           case ENREG_TYPE_2:
188             {
189               MESSAGE(LOC << "---- Traitement enregistrement de type 2");
190               _gibi >> s1 >> s2 >> numero_pile >> s3 >> s4 >> s5 >> nb_objets_nommes >> s6 >> s7 >> nb_objets;
191               if ( !_gibi || s1!="PILE"   || s2!="NUMERO"       || s3!="NBRE"  // verification mots -cles
192                    || s4!="OBJETS" || s5!="NOMMES"       || s6!="NBRE"   
193                    || s7!="OBJETS" || nb_objets_nommes<0 || nb_objets<0  )
194                 {
195                   throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Could not read file " << _fileName 
196                                                << " : error in type 2 record"));
197                 }
198
199               // lecture des objets nommés et de leurs indices
200               objets_nommes.resize(nb_objets_nommes);
201               indices_objets_nommes.resize(nb_objets_nommes);
202               for (int i=0; i!=nb_objets_nommes; ++i)
203                 _gibi >> objets_nommes[i];
204
205               for (int i=0; i!=nb_objets_nommes; ++i)
206                 _gibi >> indices_objets_nommes[i];
207                 
208               // boucle interne : lecture de la pile
209               enum {PILE_SOUS_MAILLAGE=1, PILE_NOEUDS=32, PILE_COORDONNEES=33};
210               switch(numero_pile)
211                 {
212                 case PILE_SOUS_MAILLAGE:
213                   {
214                     medi.groupes.reserve(nb_objets);
215                     for (int objet=0; objet!=nb_objets; ++objet) // pour chaque groupe
216                       {
217                         unsigned type_geom_castem, nb_reference,nb_noeud,nb_elements, nb_sous_maillage;
218                         _gibi >> type_geom_castem >> nb_sous_maillage >> nb_reference >> nb_noeud >> nb_elements;
219                         
220                         // le cas type_geom_castem=0 correspond aux maillages composites
221                         if (type_geom_castem<0 || (type_geom_castem>0 && geomGIBItoMED[type_geom_castem-1]==MED_NONE) )
222                           throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Error while reading file " << _fileName 
223                                                        << "\nCastem geometric type " << type_geom_castem 
224                                                        << " does not have a correspondant MED geometric type!" ));
225
226                         // lecture des references (non utilisé pour MED)
227                         for( unsigned i=0; i!=nb_reference; ++i)
228                           _gibi >> i1;
229                         
230                         // lecture des couleurs (non utilisé pour MED)
231                         for( unsigned i=0; i!=nb_elements; ++i)
232                           _gibi >> i1;
233                         
234                         _groupe groupe;
235                         // si le groupe se compose de sous-maillages (ie groupe composite) 
236                         if (type_geom_castem==0 && nb_sous_maillage>0) 
237                           {
238                             // lecture des indices des sous-maillages, stockage.
239                             // les mailles correspondant a ces sous_maillages seront inserees a la fin du case
240                             for (unsigned i=0; i!=nb_sous_maillage; ++i)
241                               {
242                                 _gibi >> i1;
243                                 groupe.groupes.push_back(i1);
244                               }
245                           }
246                         else
247                           {
248                             pair<set<_maille>::iterator,bool> p;
249                             pair<map<int,_noeud>::iterator,bool> p_no;
250                             _noeud no;
251                             no.coord.reserve(space_dimension);
252                             no.coord.resize(space_dimension);
253                             _maille ma(geomGIBItoMED[type_geom_castem-1], nb_noeud);
254                             ma.sommets.resize(nb_noeud);
255
256                             // lecture pour chaque maille des sommets et insertions
257                             for( unsigned i=0; i!=nb_elements; ++i)
258                               {
259                                 for (unsigned n=0; n!=nb_noeud; ++n)
260                                   {
261                                     _gibi >> i1;
262                                     no.number=i1;
263                                     p_no=medi.points.insert(make_pair(i1, no));
264                                     ma.sommets[n]=p_no.first;
265                                   }
266
267                                 p=medi.maillage.insert(ma);
268                                 groupe.mailles.insert(p.first); // on stocke dans le groupe un iterateur sur la maille
269
270 //                                  cout << "   " << p.second << ": ";
271 //                                  for (unsigned n=0; n!=nb_noeud; ++n)
272 //                                      cout <<  ma.sommets[n]->second.number << " ";
273 //                                  cout << endl;
274                                 
275                               }
276                           }
277                         medi.groupes.push_back(groupe);
278                       }
279
280                     for (int i=0; i!=nb_objets_nommes; ++i)
281                       medi.groupes[indices_objets_nommes[i]-1].nom=objets_nommes[i];
282                     
283                     // scanne les groupes à la recherche de groupes composites
284                     for( std::vector<_groupe>::iterator i=medi.groupes.begin(); i!=medi.groupes.end(); ++i)
285                       {
286                         if( i->groupes.size() ) // le groupe i contient des sous-maillages
287                           {
288                             for( std::vector<int>::iterator j=i->groupes.begin(); j!=i->groupes.end(); ++j)
289                               {
290                                 // pour chacun des sous-maillages j, on recupere les iterateurs *k sur les  maille 
291                                 // contenues et on les insere dans le groupe i
292                                 std::set< std::set<_maille, std::less<_maille>,
293                                 std::allocator<_maille> >::iterator,
294                                 _mailleIteratorCompare,
295                                 std::allocator< std::set<_maille, std::less<_maille>,
296                                 std::allocator<_maille> >::iterator> >::iterator k=medi.groupes[*j-1].mailles.begin();
297                                 for( ; k!=medi.groupes[*j-1].mailles.end(); ++k)
298                                   i->mailles.insert(*k);
299                               }
300                             i->groupes.clear(); // après avoir inséré leur mailles, on efface les groupes composites
301                           }
302                       }
303                     
304                     break;
305                   }// Fin case PILE_SOUS_MAILLAGE
306                         
307                 case PILE_NOEUDS:
308                   {
309                     std::vector<int> place_noeuds;
310                     _gibi >> nb_indices;
311                     if (nb_indices != nb_objets)
312                       {
313                         throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Could not read file " << _fileName 
314                                                      << "Erreur de lecture dans enregistrement de type " << (int)ENREG_TYPE_2 
315                                                      << " (pile " << (int)PILE_NOEUDS << ")" ));
316                       }
317                     
318                     place_noeuds.resize(nb_objets);
319                     for (unsigned i=0; i!=place_noeuds.size(); ++i)
320                       _gibi >> place_noeuds[i];
321                     int max=(* std::max_element(place_noeuds.begin(),place_noeuds.end()));
322
323                     // numero_noeuds contient pour chacun des max noeuds qu'on va lire dans le case PILE_COORDONNEES
324                     // son indice dans la connectivite du maillage. Cet indice correspond egalement a la cle du map
325                     // medi.points ou l'on stocke les noeuds.
326                     numero_noeuds.resize(max,-1);
327                     for (unsigned i=0; i!=place_noeuds.size(); ++i)
328                       numero_noeuds[place_noeuds[i]-1]=i+1;
329                     break;
330                   }
331                   
332                 case PILE_COORDONNEES:
333                   _gibi >> nb_reels;
334                   // PROVISOIRE : certains fichier gibi n'ont 
335                   if (nb_reels < numero_noeuds.size()*(space_dimension))
336                     throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Could not read file " << _fileName 
337                                                  << "Erreur de lecture dans enregistrement de type " << (int)ENREG_TYPE_2 
338                                                  << " (pile " << (int)PILE_COORDONNEES << ")" ));
339
340                   for (unsigned i=0; i!=numero_noeuds.size(); ++i)
341                     {
342                       // si le noeud est utilisé dans le maillage, on lit ses coordonnées et on les stocke dans la structure
343                       if ( (numero_noeuds[i] != -1) && (medi.points.find(numero_noeuds[i])!=medi.points.end()) ) 
344                         {
345                           for (unsigned j=0; j!=space_dimension; ++j)
346                             _gibi >> medi.points[numero_noeuds[i]].coord[j];
347                           _gibi >> d1; // on ne conserve pas la densite
348                         }
349                       else // sinon, on passe au noeud suivant
350                         {
351                           for (unsigned j=0; j!=space_dimension+1; ++j)
352                             _gibi >> d1;
353                         }
354                     }
355                   break;
356
357                 } // Fin switch numero_pile
358               break;
359             } // Fin case ENREG_TYPE_2
360           }
361
362     } //  fin de la boucle while de lecture externe
363
364     // impression résultats
365     MESSAGE(LOC << "GIBI_MESH_RDONLY_DRIVER::read : RESULTATS STRUCTURE INTERMEDIAIRES : ");
366     MESSAGE(LOC <<  medi );
367
368             // TRANSFORMATION EN STRUCTURES MED
369     if ( ! _ptrMesh->isEmpty() )
370     {
371         throw MEDEXCEPTION(LOCALIZED(STRING(LOC)<<"Mesh object not empty : can't fill it!"));
372     }
373     else if ( medi.maillage.size()==0 || medi.groupes.size()==0 || medi.points.size()==0)
374     {
375         throw MEDEXCEPTION(LOCALIZED(STRING(LOC) << " Error while reading file " << _fileName 
376                     << " The data read are not completed " ) ) ;
377     }
378     else
379     {
380         _ptrMesh->_name = _meshName;
381         _ptrMesh->_spaceDimension = medi.points.begin()->second.coord.size();
382         _ptrMesh->_meshDimension = medi.maillage.rbegin()->dimension();
383         _ptrMesh->_numberOfNodes = medi.points.size();
384         _ptrMesh->_isAGrid = 0;
385         _ptrMesh->_coordinate = medi.getCoordinate();
386
387         //Construction des groupes
388         vector<GROUP *> groupCell, groupFace, groupEdge, groupNode;
389         medi.getGroups(groupCell, groupFace, groupEdge, groupNode, _ptrMesh);
390         _ptrMesh->_groupCell = groupCell;
391         _ptrMesh->_groupFace = groupFace;
392         _ptrMesh->_groupEdge = groupEdge;
393         _ptrMesh->_groupNode = groupNode;
394
395         // appele en dernier car cette fonction detruit le maillage intermediaire!
396         _ptrMesh->_connectivity = medi.getConnectivity(); 
397
398         // calcul de la connectivite d-1 complete, avec renumerotation des groupes
399         //if (_ptrMesh->_spaceDimension==3)
400         //    _ptrMesh->_connectivity->updateGroup(_ptrMesh->_groupFace) ;
401         //else if (_ptrMesh->_spaceDimension==2)
402         //    _ptrMesh->_connectivity->updateGroup(_ptrMesh->_groupEdge) ;
403         
404         // Creation des familles à partir des groupes
405         // NC : Cet appel pourra être différé quand la gestion de la cohérence famille/groupes sera assurée
406         _ptrMesh->createFamilies();
407     }
408
409
410
411     END_OF(LOC);
412 }
413
414 void GIBI_MESH_RDONLY_DRIVER::write( void ) const
415   throw (MEDEXCEPTION)
416 {
417   throw MEDEXCEPTION("GIBI_MESH_RDONLY_DRIVER::write : Can't write with a RDONLY driver !");
418 }
419
420
421 /*--------------------- WRONLY PART -------------------------------*/
422
423 GIBI_MESH_WRONLY_DRIVER::GIBI_MESH_WRONLY_DRIVER():GIBI_MESH_DRIVER()
424 {
425 }
426   
427 GIBI_MESH_WRONLY_DRIVER::GIBI_MESH_WRONLY_DRIVER(const string & fileName,
428                                                  MESH * ptrMesh):
429   GIBI_MESH_DRIVER(fileName,ptrMesh,MED_WRONLY)
430 {
431   MESSAGE("GIBI_MESH_WRONLY_DRIVER::GIBI_MESH_WRONLY_DRIVER(const string & fileName, MESH * ptrMesh) has been created");
432 }
433
434 GIBI_MESH_WRONLY_DRIVER::GIBI_MESH_WRONLY_DRIVER(const GIBI_MESH_WRONLY_DRIVER & driver): 
435   GIBI_MESH_DRIVER(driver)
436 {
437 }
438
439 GIBI_MESH_WRONLY_DRIVER::~GIBI_MESH_WRONLY_DRIVER()
440 {
441   //MESSAGE("GIBI_MESH_WRONLY_DRIVER::GIBI_MESH_WRONLY_DRIVER(const string & fileName, MESH * ptrMesh) has been destroyed");
442 }
443
444 GENDRIVER * GIBI_MESH_WRONLY_DRIVER::copy(void) const
445 {
446   return new GIBI_MESH_WRONLY_DRIVER(*this);
447 }
448
449 void GIBI_MESH_WRONLY_DRIVER::read (void)
450   throw (MEDEXCEPTION)
451 {
452   throw MEDEXCEPTION("GIBI_MESH_WRONLY_DRIVER::read : Can't read with a WRONLY driver !");
453 }
454
455 void GIBI_MESH_WRONLY_DRIVER::write(void) const
456   throw (MEDEXCEPTION)
457
458   const char * LOC = "void GIBI_MESH_WRONLY_DRIVER::write(void) const : ";
459   BEGIN_OF(LOC);
460
461   throw MEDEXCEPTION(LOCALIZED(STRING(LOC)<< "Write Driver isn\'t implemented"));
462
463   END_OF(LOC);
464
465
466
467
468 /*--------------------- RDWR PART -------------------------------*/
469
470 GIBI_MESH_RDWR_DRIVER::GIBI_MESH_RDWR_DRIVER():GIBI_MESH_DRIVER()
471 {
472 }
473
474 GIBI_MESH_RDWR_DRIVER::GIBI_MESH_RDWR_DRIVER(const string & fileName,
475                                            MESH * ptrMesh):
476   GIBI_MESH_DRIVER(fileName,ptrMesh,MED_RDWR)
477 {
478   MESSAGE("GIBI_MESH_RDWR_DRIVER::GIBI_MESH_RDWR_DRIVER(const string & fileName, MESH * ptrMesh) has been created");
479 }
480
481 GIBI_MESH_RDWR_DRIVER::GIBI_MESH_RDWR_DRIVER(const GIBI_MESH_RDWR_DRIVER & driver): 
482   GIBI_MESH_RDONLY_DRIVER::GIBI_MESH_DRIVER(driver)
483 {
484 }
485
486 GIBI_MESH_RDWR_DRIVER::~GIBI_MESH_RDWR_DRIVER() {
487   //MESSAGE("GIBI_MESH_RDWR_DRIVER::GIBI_MESH_RDWR_DRIVER(const string & fileName, MESH * ptrMesh) has been destroyed");
488
489   
490 GENDRIVER * GIBI_MESH_RDWR_DRIVER::copy(void) const
491 {
492   return new GIBI_MESH_RDWR_DRIVER(*this);
493 }
494
495 void GIBI_MESH_RDWR_DRIVER::write(void) const
496   throw (MEDEXCEPTION)
497 {
498   GIBI_MESH_WRONLY_DRIVER::write();
499 }
500 void GIBI_MESH_RDWR_DRIVER::read (void)
501   throw (MEDEXCEPTION)
502 {
503   GIBI_MESH_RDONLY_DRIVER::read();
504 }