Salome HOME
CS work : MeshGems reader/writer
[tools/medcoupling.git] / src / MEDLoader / libmesh5.cxx
1 // Copyright (C) 2021  CEA/DEN, EDF R&D
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, or (at your option) any later version.
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 /*----------------------------------------------------------*/
21 /*                                                                                                                      */
22 /*                                              LIBMESH V 5.46                                          */
23 /*                                                                                                                      */
24 /*----------------------------------------------------------*/
25 /*                                                                                                                      */
26 /*      Description:            handle .meshb file format I/O           */
27 /*      Author:                         Loic MARECHAL                                           */
28 /*      Creation date:          feb 16 2007                                                     */
29 /*      Last modification:      apr 03 2012                                                     */
30 /*                                                                                                                      */
31 /*----------------------------------------------------------*/
32
33
34 /*----------------------------------------------------------*/
35 /* Includes                                                                                                     */
36 /*----------------------------------------------------------*/
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <string.h>
42 #include <float.h>
43 #include <math.h>
44 #include <ctype.h>
45 #include "libmesh5.hxx"
46 #ifdef WIN32
47 #include <windows.h>
48 #endif
49
50 using namespace MeshFormat;
51
52
53
54 /*----------------------------------------------------------*/
55 /* Global variables                                                                                     */
56 /*----------------------------------------------------------*/
57
58 // see MeshGems/Docs/meshgems_formats_description.pdf
59 const char *GmfKwdFmt[ GmfMaxKwd + 1 ][4] =
60 {   {"Reserved", "", "", ""},
61     {"MeshVersionFormatted", "", "", "i"},
62     {"Reserved", "", "", ""},
63     {"Dimension", "", "", "i"},
64     {"Vertices", "Vertex", "i", "dri"},
65     {"Edges", "Edge", "i", "iii"},
66     {"Triangles", "Triangle", "i", "iiii"},
67     {"Quadrilaterals", "Quadrilateral", "i", "iiiii"},
68     {"Tetrahedra", "Tetrahedron", "i", "iiiii"},
69     {"Prisms", "Prism", "i", "iiiiiii"},
70     {"Hexahedra", "Hexahedron", "i", "iiiiiiiii"},
71     {"IterationsAll", "IterationAll","","i"},
72     {"TimesAll", "TimeAll","","r"},
73     {"Corners", "Corner", "i", "i"},
74     {"Ridges", "Ridge", "i", "i"},
75     {"RequiredVertices", "RequiredVertex", "i", "i"},
76     {"RequiredEdges", "RequiredEdge", "i", "i"},
77     {"RequiredTriangles", "RequiredTriangle", "i", "i"},
78     {"RequiredQuadrilaterals", "RequiredQuadrilateral", "i", "i"},
79     {"TangentAtEdgeVertices", "TangentAtEdgeVertex", "i", "iii"},
80     {"NormalAtVertices", "NormalAtVertex", "i", "ii"},
81     {"NormalAtTriangleVertices", "NormalAtTriangleVertex", "i", "iii"},
82     {"NormalAtQuadrilateralVertices", "NormalAtQuadrilateralVertex", "i", "iiii"},
83     {"AngleOfCornerBound", "", "", "r"},
84     {"TrianglesP2", "TriangleP2", "i", "iiiiiii"},
85     {"EdgesP2", "EdgeP2", "i", "iiii"},
86     {"SolAtPyramids", "SolAtPyramid", "i", "sr"},
87     {"QuadrilateralsQ2", "QuadrilateralQ2", "i", "iiiiiiiiii"},
88     {"ISolAtPyramids", "ISolAtPyramid", "i", "iiiii"},
89     {"SubDomainFromGeom", "SubDomainFromGeom", "i", "iiii"},
90     {"TetrahedraP2", "TetrahedronP2", "i", "iiiiiiiiiii"},
91     {"Fault_NearTri", "Fault_NearTri", "i", "i"},
92     {"Fault_Inter", "Fault_Inter", "i", "i"},
93     {"HexahedraQ2", "HexahedronQ2", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiii"},
94     {"ExtraVerticesAtEdges", "ExtraVerticesAtEdge", "i", "in"},
95     {"ExtraVerticesAtTriangles", "ExtraVerticesAtTriangle", "i", "in"},
96     {"ExtraVerticesAtQuadrilaterals", "ExtraVerticesAtQuadrilateral", "i", "in"},
97     {"ExtraVerticesAtTetrahedra", "ExtraVerticesAtTetrahedron", "i", "in"},
98     {"ExtraVerticesAtPrisms", "ExtraVerticesAtPrism", "i", "in"},
99     {"ExtraVerticesAtHexahedra", "ExtraVerticesAtHexahedron", "i", "in"},
100     {"VerticesOnGeometricVertices", "VertexOnGeometricVertex", "i", "iir"},
101     {"VerticesOnGeometricEdges", "VertexOnGeometricEdge", "i", "iirr"},
102     {"VerticesOnGeometricTriangles", "VertexOnGeometricTriangle", "i", "iirrr"},
103     {"VerticesOnGeometricQuadrilaterals", "VertexOnGeometricQuadrilateral", "i", "iirrr"},
104     {"EdgesOnGeometricEdges", "EdgeOnGeometricEdge", "i", "iir"},
105     {"Fault_FreeEdge", "Fault_FreeEdge", "i", "i"},
106     {"Polyhedra", "Polyhedron", "i", "iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"},
107     {"Polygons", "Polygon", "", "iiiiiiiii"},
108     {"Fault_Overlap", "Fault_Overlap", "i", "i"},
109     {"Pyramids", "Pyramid", "i", "iiiiii"},
110     {"BoundingBox", "", "", "drdr"},
111     {"Body","i", "drdrdrdr"},
112     {"PrivateTable", "PrivateTable", "i", "i"},
113     {"Fault_BadShape", "Fault_BadShape", "i", "i"},
114     {"End", "", "", ""},
115     {"TrianglesOnGeometricTriangles", "TriangleOnGeometricTriangle", "i", "iir"},
116     {"TrianglesOnGeometricQuadrilaterals", "TriangleOnGeometricQuadrilateral", "i", "iir"},
117     {"QuadrilateralsOnGeometricTriangles", "QuadrilateralOnGeometricTriangle", "i", "iir"},
118     {"QuadrilateralsOnGeometricQuadrilaterals", "QuadrilateralOnGeometricQuadrilateral", "i", "iir"},
119     {"Tangents", "Tangent", "i", "dr"},
120     {"Normals", "Normal", "i", "dr"},
121     {"TangentAtVertices", "TangentAtVertex", "i", "ii"},
122     {"SolAtVertices", "SolAtVertex", "i", "sr"},
123     {"SolAtEdges", "SolAtEdge", "i", "sr"},
124     {"SolAtTriangles", "SolAtTriangle", "i", "sr"},
125     {"SolAtQuadrilaterals", "SolAtQuadrilateral", "i", "sr"},
126     {"SolAtTetrahedra", "SolAtTetrahedron", "i", "sr"},
127     {"SolAtPrisms", "SolAtPrism", "i", "sr"},
128     {"SolAtHexahedra", "SolAtHexahedron", "i", "sr"},
129     {"DSolAtVertices", "DSolAtVertex", "i", "sr"},
130     {"ISolAtVertices", "ISolAtVertex", "i", "i"},
131     {"ISolAtEdges", "ISolAtEdge", "i", "ii"},
132     {"ISolAtTriangles", "ISolAtTriangle", "i", "iii"},
133     {"ISolAtQuadrilaterals", "ISolAtQuadrilateral", "i", "iiii"},
134     {"ISolAtTetrahedra", "ISolAtTetrahedron", "i", "iiii"},
135     {"ISolAtPrisms", "ISolAtPrism", "i", "iiiiii"},
136     {"ISolAtHexahedra", "ISolAtHexahedron", "i", "iiiiiiii"},
137     {"Iterations", "","","i"},
138     {"Time", "","","r"},
139     {"Fault_SmallTri", "Fault_SmallTri","i","i"},
140     {"CoarseHexahedra", "CoarseHexahedron", "i", "i"},
141     {"Fault_MultipleEdge", "Fault_MultipleEdge", "i", "i"}
142 };
143
144
145
146 MeshFormatParser::MeshFormatParser():GmfIniFlg(0)
147 {
148
149 }
150
151 /*----------------------------------------------------------*/
152 /* Open a mesh file in read or write mod                                        */
153 /*----------------------------------------------------------*/
154
155 int MeshFormatParser::GmfOpenMesh(const char *FilNam, int mod, ...)
156 {
157     int i, KwdCod, res, *PtrVer, *PtrDim, MshIdx=0;
158     char str[ GmfStrSiz ];
159     va_list VarArg;
160     GmfMshSct *msh;
161     char *ptr;
162     int k;
163 #if defined(WIN32) && defined(UNICODE)
164     wchar_t* encoded = 0;
165     int size_needed = 0;
166 #endif
167     if(!GmfIniFlg)
168     {
169         for(i=0; i<=MaxMsh; i++)
170             //~GmfMshTab[i] = NULL;
171             GmfMshTab[i] = nullptr;
172
173         GmfIniFlg = 1;
174     }
175
176     /*---------------------*/
177     /* MESH STRUCTURE INIT */
178     /*---------------------*/
179
180     for(i=1; i<=MaxMsh; i++)
181         if(!GmfMshTab[i])
182         {
183             MshIdx = i;
184             break;
185         }
186
187
188     if( !MshIdx || !(msh = new GmfMshSct() ) )
189         return(0);
190
191     /* Copy the FilNam into the structure */
192
193     if(strlen(FilNam) + 7 >= GmfStrSiz)
194     {
195         //~free (msh);
196         delete msh;
197         return(0);
198     }
199
200     strcpy(msh->FilNam, FilNam);
201
202     /* Store the opening mod (read or write) and guess the filetype (binary or ascii) depending on the extension */
203
204     msh->mod = mod;
205     msh->buf = (unsigned char *)msh->DblBuf;
206     msh->FltBuf = (float *)msh->DblBuf;
207     msh->IntBuf = (int *)msh->DblBuf;
208
209     k = static_cast<int>(strlen(msh->FilNam)) - 6;
210     if(k < 0)
211         k = 0;
212     ptr = msh->FilNam+k;
213     if(strstr(ptr, ".meshb"))
214         msh->typ |= (Bin | MshFil);
215     else if(strstr(ptr, ".mesh"))
216         msh->typ |= (Asc | MshFil);
217     else if(strstr(ptr, ".solb"))
218         msh->typ |= (Bin | SolFil);
219     else if(strstr(ptr, ".sol"))
220         msh->typ |= (Asc | SolFil);
221     else {
222         //~free (msh);
223         delete msh;
224         return(0);
225     }
226
227     /* Open the file in the required mod and initialise the mesh structure */
228
229     if(msh->mod == GmfRead)
230     {
231
232         /*-----------------------*/
233         /* OPEN FILE FOR READING */
234         /*-----------------------*/
235
236         va_start(VarArg, mod);
237         PtrVer = va_arg(VarArg, int *);
238         PtrDim = va_arg(VarArg, int *);
239         va_end(VarArg);
240
241         /* Create the name string and open the file */
242 #if defined(WIN32) && defined(UNICODE)
243         size_needed = MultiByteToWideChar(CP_UTF8, 0, msh->FilNam, strlen(msh->FilNam), NULL, 0);
244         //~encoded = malloc((size_needed + 1)*sizeof(wchar_t));
245         encoded = new wchar_t[size_needed + 1] ;
246         MultiByteToWideChar(CP_UTF8, 0, msh->FilNam, strlen(msh->FilNam), encoded, size_needed);
247         encoded[size_needed] = '\0';
248         if (!(msh->hdl = _wfopen(encoded, L"rb")))
249 #else
250         if (!(msh->hdl = fopen(msh->FilNam, "rb")))
251 #endif
252         {
253
254             delete msh;
255 #if defined(WIN32) && defined(UNICODE)
256
257             delete [] encoded;
258 #endif
259             return(0);
260         }
261
262 #if defined(WIN32) && defined(UNICODE)
263
264         delete [] encoded;
265 #endif
266
267         /* Read the endian coding tag, the mesh version and the mesh dimension (mandatory kwd) */
268
269         if(msh->typ & Bin)
270         {
271             fread((unsigned char *)&msh->cod, WrdSiz, 1, msh->hdl);
272
273             if( (msh->cod != 1) && (msh->cod != 16777216) )
274             {
275
276                 delete msh;
277                 return(0);
278             }
279
280             ScaWrd(msh, (unsigned char *)&msh->ver);
281
282             if( (msh->ver < 1) || (msh->ver > 3) )
283             {
284
285                 delete msh;
286                 return(0);
287             }
288
289             if( (msh->ver == 3) && (sizeof(long) == 4) )
290             {
291
292                 delete msh;
293                 return(0);
294             }
295
296             ScaWrd(msh, (unsigned char *)&KwdCod);
297
298             if(KwdCod != GmfDimension)
299             {
300
301                 delete msh;
302                 return(0);
303             }
304
305             GetPos(msh);
306             ScaWrd(msh, (unsigned char *)&msh->dim);
307         }
308         else
309         {
310             do
311             {
312                 res = fscanf(msh->hdl, "%s", str);
313             } while( (res != EOF) && strcmp(str, "MeshVersionFormatted") );
314
315             if(res == EOF)
316             {
317
318                 delete msh;
319                 return(0);
320             }
321
322             fscanf(msh->hdl, "%d", &msh->ver);
323
324             if( (msh->ver < 1) || (msh->ver > 3) )
325             {
326
327                 delete msh;
328                 return(0);
329             }
330
331             do
332             {
333                 res = fscanf(msh->hdl, "%s", str);
334             } while( (res != EOF) && strcmp(str, "Dimension") );
335
336             if(res == EOF)
337             {
338
339                 delete msh;
340                 return(0);
341             }
342
343             fscanf(msh->hdl, "%d", &msh->dim);
344         }
345
346         if( (msh->dim != 2) && (msh->dim != 3) )
347         {
348
349             delete msh;
350             return(0);
351         }
352
353         (*PtrVer) = msh->ver;
354         (*PtrDim) = msh->dim;
355
356         /*------------*/
357         /* KW READING */
358         /*------------*/
359
360         /* Read the list of kw present in the file */
361
362         if(!ScaKwdTab(msh))
363         {
364
365             delete msh;
366             return(0);
367         }
368
369         GmfMshTab[ MshIdx ] = msh;
370
371         return(MshIdx);
372     }
373     else if(msh->mod == GmfWrite)
374     {
375
376         /*-----------------------*/
377         /* OPEN FILE FOR WRITING */
378         /*-----------------------*/
379
380         msh->cod = 1;
381
382         /* Check if the user provided a valid version number and dimension */
383
384         va_start(VarArg, mod);
385         msh->ver = va_arg(VarArg, int);
386         msh->dim = va_arg(VarArg, int);
387         va_end(VarArg);
388
389         if( (msh->ver < 1) || (msh->ver > 3) )
390         {
391
392             delete msh;
393             return(0);
394         }
395
396         if( (msh->ver == 3) && (sizeof(long) == 4) )
397         {
398
399             delete msh;
400             return(0);
401         }
402
403         if( (msh->dim != 2) && (msh->dim != 3) )
404         {
405
406             delete msh;
407             return(0);
408         }
409
410         /* Create the mesh file */
411 #if defined(WIN32) && defined(UNICODE)
412         size_needed = MultiByteToWideChar(CP_UTF8, 0, msh->FilNam, strlen(msh->FilNam), NULL, 0);
413
414         encoded = new wchar_t[size_needed + 1];
415         MultiByteToWideChar(CP_UTF8, 0, msh->FilNam, strlen(msh->FilNam), encoded, size_needed);
416         encoded[size_needed] = '\0';
417         if (!(msh->hdl = _wfopen(encoded, L"wb")))
418 #else
419         if(!(msh->hdl = fopen(msh->FilNam, "wb")))
420 #endif
421         {
422
423             delete msh;
424 #if defined(WIN32) && defined(UNICODE)
425
426             delete []encoded;
427 #endif
428             return(0);
429         }
430
431 #if defined(WIN32) && defined(UNICODE)
432
433         delete []encoded;
434 #endif
435         GmfMshTab[ MshIdx ] = msh;
436
437
438         /*------------*/
439         /* KW WRITING */
440         /*------------*/
441
442         /* Write the mesh version and dimension */
443
444         if(msh->typ & Asc)
445         {
446             fprintf(msh->hdl, "%s %d\n\n", GmfKwdFmt[ GmfVersionFormatted ][0], msh->ver);
447             fprintf(msh->hdl, "%s %d\n", GmfKwdFmt[ GmfDimension ][0], msh->dim);
448         }
449         else
450         {
451             RecWrd(msh, (unsigned char *)&msh->cod);
452             RecWrd(msh, (unsigned char *)&msh->ver);
453             GmfSetKwd(MshIdx, GmfDimension, 0);
454             RecWrd(msh, (unsigned char *)&msh->dim);
455         }
456
457         return(MshIdx);
458     }
459     else
460     {
461
462         delete msh;
463         return(0);
464     }
465 }
466
467
468 /*----------------------------------------------------------*/
469 /* Close a meshfile in the right way                                            */
470 /*----------------------------------------------------------*/
471
472 int MeshFormatParser::GmfCloseMesh(int MshIdx)
473 {
474     int res = 1;
475     GmfMshSct *msh;
476
477     if( (MshIdx < 1) || (MshIdx > MaxMsh) )
478         return(0);
479
480     msh = GmfMshTab[ MshIdx ];
481     RecBlk(msh, msh->buf, 0);
482
483     /* In write down the "End" kw in write mode */
484
485     if(msh->mod == GmfWrite) {
486         if(msh->typ & Asc)
487             fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ GmfEnd ][0]);
488         else
489             GmfSetKwd(MshIdx, GmfEnd, 0);
490     }
491     /* Close the file and free the mesh structure */
492
493     if(fclose(msh->hdl))
494         res = 0;
495
496
497     delete msh;
498
499     GmfMshTab[ MshIdx ] = nullptr;
500
501     return(res);
502 }
503
504
505 /*----------------------------------------------------------*/
506 /* Read the number of lines and set the position to this kwd*/
507 /*----------------------------------------------------------*/
508
509 int MeshFormatParser::GmfStatKwd(int MshIdx, int KwdCod, ...)
510 {
511     int i, *PtrNmbTyp, *PtrSolSiz, *TypTab;
512     GmfMshSct *msh;
513     KwdSct *kwd;
514     va_list VarArg;
515
516     if( (MshIdx < 1) || (MshIdx > MaxMsh) )
517         return(0);
518
519     msh = GmfMshTab[ MshIdx ];
520
521     if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
522         return(0);
523
524     kwd = &msh->KwdTab[ KwdCod ];
525
526     if(!kwd->NmbLin)
527         return(0);
528
529     /* Read further arguments if this kw is a sol */
530
531     if(kwd->typ == SolKwd)
532     {
533         va_start(VarArg, KwdCod);
534
535         PtrNmbTyp = va_arg(VarArg, int *);
536         *PtrNmbTyp = kwd->NmbTyp;
537
538         PtrSolSiz = va_arg(VarArg, int *);
539         *PtrSolSiz = kwd->SolSiz;
540
541         TypTab = va_arg(VarArg, int *);
542
543         for(i=0; i<kwd->NmbTyp; i++)
544             TypTab[i] = kwd->TypTab[i];
545
546         va_end(VarArg);
547     }
548
549     return(kwd->NmbLin);
550 }
551
552
553 /*----------------------------------------------------------*/
554 /* Set the current file position to a given kwd                         */
555 /*----------------------------------------------------------*/
556
557 int MeshFormatParser::GmfGotoKwd(int MshIdx, int KwdCod)
558 {
559     GmfMshSct *msh;
560     KwdSct *kwd;
561
562     if( (MshIdx < 1) || (MshIdx > MaxMsh) )
563         return(0);
564
565     msh = GmfMshTab[ MshIdx ];
566
567     if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
568         return(0);
569
570     kwd = &msh->KwdTab[ KwdCod ];
571
572     if(!kwd->NmbLin)
573         return(0);
574
575     return(fseek(msh->hdl, kwd->pos, SEEK_SET));
576 }
577
578
579 /*----------------------------------------------------------*/
580 /* Write the kwd and set the number of lines                            */
581 /*----------------------------------------------------------*/
582
583 int MeshFormatParser::GmfSetKwd(int MshIdx, int KwdCod, ...)
584 {
585     int i, NmbLin=0, *TypTab;
586     long CurPos;
587     va_list VarArg;
588     GmfMshSct *msh;
589     KwdSct *kwd;
590
591     if( (MshIdx < 1) || (MshIdx > MaxMsh) )
592         return(0);
593
594     msh = GmfMshTab[ MshIdx ];
595     RecBlk(msh, msh->buf, 0);
596
597     if( (KwdCod < 1) || (KwdCod > GmfMaxKwd) )
598         return(0);
599
600     kwd = &msh->KwdTab[ KwdCod ];
601
602     /* Read further arguments if this kw has a header */
603
604     if(strlen(GmfKwdFmt[ KwdCod ][2]))
605     {
606         va_start(VarArg, KwdCod);
607         NmbLin = va_arg(VarArg, int);
608
609         if(!strcmp(GmfKwdFmt[ KwdCod ][3], "sr"))
610         {
611             kwd->NmbTyp = va_arg(VarArg, int);
612             TypTab = va_arg(VarArg, int *);
613
614             for(i=0; i<kwd->NmbTyp; i++)
615                 kwd->TypTab[i] = TypTab[i];
616         }
617
618         va_end(VarArg);
619     }
620
621     /* Setup the kwd info */
622
623     ExpFmt(msh, KwdCod);
624
625     if(!kwd->typ)
626         return(0);
627     else if(kwd->typ == InfKwd)
628         kwd->NmbLin = 1;
629     else
630         kwd->NmbLin = NmbLin;
631
632     /* Store the next kwd position in binary file */
633
634     if( (msh->typ & Bin) && msh->NexKwdPos )
635     {
636         CurPos = ftell(msh->hdl);
637         fseek(msh->hdl, msh->NexKwdPos, SEEK_SET);
638         SetPos(msh, CurPos);
639         fseek(msh->hdl, CurPos, SEEK_SET);
640     }
641
642     /* Write the header */
643
644     if(msh->typ & Asc)
645     {
646         fprintf(msh->hdl, "\n%s\n", GmfKwdFmt[ KwdCod ][0]);
647
648         if(kwd->typ != InfKwd)
649             fprintf(msh->hdl, "%d\n", kwd->NmbLin);
650
651         /* In case of solution field, write the extended header */
652
653         if(kwd->typ == SolKwd)
654         {
655             fprintf(msh->hdl, "%d ", kwd->NmbTyp);
656
657             for(i=0; i<kwd->NmbTyp; i++)
658                 fprintf(msh->hdl, "%d ", kwd->TypTab[i]);
659
660             fprintf(msh->hdl, "\n\n");
661         }
662     }
663     else
664     {
665         RecWrd(msh, (unsigned char *)&KwdCod);
666         msh->NexKwdPos = ftell(msh->hdl);
667         SetPos(msh, 0);
668
669         if(kwd->typ != InfKwd)
670             RecWrd(msh, (unsigned char *)&kwd->NmbLin);
671
672         /* In case of solution field, write the extended header at once */
673
674         if(kwd->typ == SolKwd)
675         {
676             RecWrd(msh, (unsigned char *)&kwd->NmbTyp);
677
678             for(i=0; i<kwd->NmbTyp; i++)
679                 RecWrd(msh, (unsigned char *)&kwd->TypTab[i]);
680         }
681     }
682
683     /* Reset write buffer position */
684     msh->pos = 0;
685
686     /* Estimate the total file size and check whether it crosses the 2GB threshold */
687
688     msh->siz += kwd->NmbLin * kwd->NmbWrd * WrdSiz;
689
690     if(msh->siz > static_cast<long>(2E9))
691         return(0);
692     else
693         return(kwd->NmbLin);
694 }
695
696
697 /*----------------------------------------------------------*/
698 /* Read a full line from the current kwd                                        */
699 /*----------------------------------------------------------*/
700
701 void MeshFormatParser::GmfGetLin(int MshIdx, int KwdCod, ...)
702 {
703     int i, j;
704     float *FltSolTab;
705     double *DblSolTab;
706     va_list VarArg;
707     GmfMshSct *msh = GmfMshTab[ MshIdx ];
708     KwdSct *kwd = &msh->KwdTab[ KwdCod ];
709
710     /* Start decoding the arguments */
711
712     va_start(VarArg, KwdCod);
713
714     if(kwd->typ != SolKwd)
715     {
716         int k, nb_repeat = 0;
717
718         if(msh->ver == 1)
719         {
720             if(msh->typ & Asc)
721             {
722                 for(i=0; i<kwd->SolSiz; i++)
723                     if(kwd->fmt[i] == 'r')
724                         fscanf(msh->hdl, "%f", va_arg(VarArg, float *));
725                     else if(kwd->fmt[i] == 'n') {
726                         fscanf(msh->hdl, "%d", &nb_repeat);
727                         *(va_arg(VarArg,  int *)) = nb_repeat;
728                         for(k=0; k<nb_repeat; k++)
729                             fscanf(msh->hdl, "%d", va_arg(VarArg, int *));
730                     }
731                     else
732                         fscanf(msh->hdl, "%d", va_arg(VarArg, int *));
733             }
734             else
735             {
736                 for(i=0; i<kwd->SolSiz; i++)
737                     if(kwd->fmt[i] == 'r')
738                         ScaWrd(msh, (unsigned char *)va_arg(VarArg, float *));
739                     else if(kwd->fmt[i] == 'n') {
740                         ScaWrd(msh, (unsigned char *)&nb_repeat);
741                         *(va_arg(VarArg,  int *)) = nb_repeat;
742                         for(k=0; k<nb_repeat; k++)
743                             ScaWrd(msh, (unsigned char *)va_arg(VarArg, int *));
744                     }
745                     else
746                         ScaWrd(msh, (unsigned char *)va_arg(VarArg, int *));
747             }
748         }
749         else
750         {
751             if(msh->typ & Asc)
752             {
753                 for(i=0; i<kwd->SolSiz; i++)
754                     if(kwd->fmt[i] == 'r')
755                         fscanf(msh->hdl, "%lf", va_arg(VarArg, double *));
756                     else if(kwd->fmt[i] == 'n') {
757                         fscanf(msh->hdl, "%d", &nb_repeat);
758                         *(va_arg(VarArg,  int *)) = nb_repeat;
759                         for(k=0; k<nb_repeat; k++)
760                             fscanf(msh->hdl, "%d", va_arg(VarArg, int *));
761                     }
762                     else
763                         fscanf(msh->hdl, "%d", va_arg(VarArg, int *));
764             }
765             else
766                 for(i=0; i<kwd->SolSiz; i++)
767                     if(kwd->fmt[i] == 'r')
768                         ScaDblWrd(msh, (unsigned char *)va_arg(VarArg, double *));
769                     else if(kwd->fmt[i] == 'n') {
770                         ScaWrd(msh, (unsigned char *)&nb_repeat);
771                         *(va_arg(VarArg,  int *)) = nb_repeat;
772                         for(k=0; k<nb_repeat; k++)
773                             ScaWrd(msh, (unsigned char *)va_arg(VarArg, int *));
774                     }
775                     else
776                         ScaWrd(msh, (unsigned char *)va_arg(VarArg, int *));
777         }
778     }
779     else
780     {
781         if(msh->ver == 1)
782         {
783             FltSolTab = va_arg(VarArg, float *);
784
785             if(msh->typ & Asc)
786                 for(j=0; j<kwd->SolSiz; j++)
787                     fscanf(msh->hdl, "%f", &FltSolTab[j]);
788             else
789                 ScaBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd);
790         }
791         else
792         {
793             DblSolTab = va_arg(VarArg, double *);
794
795             if(msh->typ & Asc)
796                 for(j=0; j<kwd->SolSiz; j++)
797                     fscanf(msh->hdl, "%lf", &DblSolTab[j]);
798             else
799                 for(j=0; j<kwd->SolSiz; j++)
800                     ScaDblWrd(msh, (unsigned char *)&DblSolTab[j]);
801         }
802     }
803
804     va_end(VarArg);
805 }
806
807
808 /*----------------------------------------------------------*/
809 /* Write a full line from the current kwd                                       */
810 /*----------------------------------------------------------*/
811
812 void MeshFormatParser::GmfSetLin(int MshIdx, int KwdCod, ...)
813 {
814     int i, j, pos, *IntBuf;
815     float *FltSolTab;
816     double *DblSolTab, *DblBuf;
817     va_list VarArg;
818     GmfMshSct *msh = GmfMshTab[ MshIdx ];
819     KwdSct *kwd = &msh->KwdTab[ KwdCod ];
820
821     /* Start decoding the arguments */
822
823     va_start(VarArg, KwdCod);
824
825     if(kwd->typ != SolKwd)
826     {
827         int k, nb_repeat = 0;
828
829         if(msh->ver == 1)
830         {
831             if(msh->typ & Asc)
832             {
833                 for(i=0; i<kwd->SolSiz; i++)
834                     if(kwd->fmt[i] == 'r')
835                         fprintf(msh->hdl, "%g ", (float)va_arg(VarArg, double));
836                     else if(kwd->fmt[i] == 'n') {
837                         nb_repeat = va_arg(VarArg, int);
838                         fprintf(msh->hdl, "%d ", nb_repeat);
839                         for(k=0; k<nb_repeat; k++)
840                             fprintf(msh->hdl, "%d ", va_arg(VarArg, int));
841                     }
842                     else
843                         fprintf(msh->hdl, "%d ", va_arg(VarArg, int));
844             }
845             else
846             {
847                 int size_of_block = kwd->SolSiz;
848                 for(i=0; i<kwd->SolSiz; i++)
849                     if(kwd->fmt[i] == 'r')
850                         msh->FltBuf[i] = static_cast<float>(va_arg(VarArg, double));
851                     else if(kwd->fmt[i] == 'n') {
852                         nb_repeat = va_arg(VarArg, int);
853                         msh->FltBuf[i] = static_cast<float> (nb_repeat);
854                         for(k=0; k<nb_repeat; k++) {
855                             msh->IntBuf[i+1+k] = va_arg(VarArg, int);
856                             size_of_block ++;
857                         }
858                     }
859                     else
860                         msh->IntBuf[i] = va_arg(VarArg, int);
861
862                 RecBlk(msh, msh->buf, size_of_block);
863             }
864         }
865         else
866         {
867             if(msh->typ & Asc)
868             {
869                 for(i=0; i<kwd->SolSiz; i++)
870                     if(kwd->fmt[i] == 'r')
871                         fprintf(msh->hdl, "%.15lg ", va_arg(VarArg, double));
872                     else if(kwd->fmt[i] == 'n') {
873                         nb_repeat = va_arg(VarArg, int);
874                         fprintf(msh->hdl, "%d ", nb_repeat);
875                         for(k=0; k<nb_repeat; k++)
876                             fprintf(msh->hdl, "%d ", va_arg(VarArg, int));
877                     }
878                     else
879                         fprintf(msh->hdl, "%d ", va_arg(VarArg, int));
880             }
881             else
882             {
883                 pos = 0;
884
885                 for(i=0; i<kwd->SolSiz; i++)
886                     if(kwd->fmt[i] == 'r')
887                     {
888                         DblBuf = (double *)&msh->buf[ pos ];
889                         *DblBuf = va_arg(VarArg, double);
890                         pos += 8;
891                     }
892                     else if(kwd->fmt[i] == 'n')
893                     {
894                         IntBuf = (int *)&msh->buf[ pos ];
895                         nb_repeat = va_arg(VarArg, int);
896                         *IntBuf = nb_repeat;
897                         pos += 4;
898                         for(k=0; k<nb_repeat; k++) {
899                             IntBuf = (int *)&msh->buf[ pos ];
900                             *IntBuf = va_arg(VarArg, int);
901                             pos += 4;
902                         }
903                     }
904                     else
905                     {
906                         IntBuf = (int *)&msh->buf[ pos ];
907                         *IntBuf = va_arg(VarArg, int);
908                         pos += 4;
909                     }
910                 RecBlk(msh, msh->buf, pos/4);
911             }
912         }
913     }
914     else
915     {
916         if(msh->ver == 1)
917         {
918             FltSolTab = va_arg(VarArg, float *);
919
920             if(msh->typ & Asc)
921                 for(j=0; j<kwd->SolSiz; j++)
922                     fprintf(msh->hdl, "%g ", FltSolTab[j]);
923             else
924                 RecBlk(msh, (unsigned char *)FltSolTab, kwd->NmbWrd);
925         }
926         else
927         {
928             DblSolTab = va_arg(VarArg, double *);
929
930             if(msh->typ & Asc)
931                 for(j=0; j<kwd->SolSiz; j++)
932                     fprintf(msh->hdl, "%.15lg ", DblSolTab[j]);
933             else
934                 RecBlk(msh, (unsigned char *)DblSolTab, kwd->NmbWrd);
935         }
936     }
937
938     va_end(VarArg);
939
940     if(msh->typ & Asc)
941         fprintf(msh->hdl, "\n");
942 }
943
944
945 /*----------------------------------------------------------*/
946 /* Private procedure for transmesh : copy a whole line          */
947 /*----------------------------------------------------------*/
948
949 void MeshFormatParser::GmfCpyLin(int InpIdx, int OutIdx, int KwdCod)
950 {
951     double d;
952     float f;
953     int i, a;
954     GmfMshSct *InpMsh = GmfMshTab[ InpIdx ], *OutMsh = GmfMshTab[ OutIdx ];
955     KwdSct *kwd = &InpMsh->KwdTab[ KwdCod ];
956
957     for(i=0; i<kwd->SolSiz; i++)
958     {
959         if(kwd->fmt[i] == 'r')
960         {
961             if(InpMsh->ver == 1)
962             {
963                 if(InpMsh->typ & Asc)
964                     fscanf(InpMsh->hdl, "%f", &f);
965                 else
966                     ScaWrd(InpMsh, (unsigned char *)&f);
967
968                 d = f;
969             }
970             else
971             {
972                 if(InpMsh->typ & Asc)
973                     fscanf(InpMsh->hdl, "%lf", &d);
974                 else
975                     ScaDblWrd(InpMsh, (unsigned char *)&d);
976
977                 f = (float)d;
978             }
979
980             if(OutMsh->ver == 1)
981                 if(OutMsh->typ & Asc)
982                     fprintf(OutMsh->hdl, "%g ", f);
983                 else
984                     RecWrd(OutMsh, (unsigned char *)&f);
985             else if(OutMsh->typ & Asc)
986                 fprintf(OutMsh->hdl, "%.15g ", d);
987             else
988                 RecDblWrd(OutMsh, (unsigned char *)&d);
989         }
990         else if(kwd->fmt[i] == 'n')
991         {
992             int k, nb_repeat = 0;
993
994             if(InpMsh->typ & Asc)
995                 fscanf(InpMsh->hdl, "%d", &a);
996             else
997                 ScaWrd(InpMsh, (unsigned char *)&a);
998
999             nb_repeat = a;
1000
1001             if(OutMsh->typ & Asc)
1002                 fprintf(OutMsh->hdl, "%d ", a);
1003             else
1004                 RecWrd(OutMsh, (unsigned char *)&a);
1005
1006             for(k=0; k<nb_repeat; k++) {
1007                 if(InpMsh->typ & Asc)
1008                     fscanf(InpMsh->hdl, "%d", &a);
1009                 else
1010                     ScaWrd(InpMsh, (unsigned char *)&a);
1011
1012                 if(OutMsh->typ & Asc)
1013                     fprintf(OutMsh->hdl, "%d ", a);
1014                 else
1015                     RecWrd(OutMsh, (unsigned char *)&a);
1016             }
1017         }
1018         else
1019         {
1020             if(InpMsh->typ & Asc)
1021                 fscanf(InpMsh->hdl, "%d", &a);
1022             else
1023                 ScaWrd(InpMsh, (unsigned char *)&a);
1024
1025             if(OutMsh->typ & Asc)
1026                 fprintf(OutMsh->hdl, "%d ", a);
1027             else
1028                 RecWrd(OutMsh, (unsigned char *)&a);
1029         }
1030     }
1031
1032     if(OutMsh->typ & Asc)
1033         fprintf(OutMsh->hdl, "\n");
1034 }
1035
1036
1037 /*----------------------------------------------------------*/
1038 /* Find every kw present in a meshfile                                          */
1039 /*----------------------------------------------------------*/
1040
1041 int MeshFormatParser::ScaKwdTab(GmfMshSct *msh)
1042 {
1043     int KwdCod;
1044     long  NexPos, CurPos, EndPos;
1045     char str[ GmfStrSiz ];
1046
1047     if(msh->typ & Asc)
1048     {
1049         /* Scan each string in the file until the end */
1050
1051         while(fscanf(msh->hdl, "%s", str) != EOF)
1052         {
1053             /* Fast test in order to reject quickly the numeric values */
1054
1055             if(isalpha(str[0]))
1056             {
1057                 /* Search which kwd code this string is associated with,
1058                         then get its header and save the current position in file (just before the data) */
1059                 // printf("libmesh ScaKwdTab %s\n", str);
1060                 for(KwdCod=1; KwdCod<= GmfMaxKwd; KwdCod++)
1061                     if(!strcmp(str, GmfKwdFmt[ KwdCod ][0]))
1062                     {
1063                         ScaKwdHdr(msh, KwdCod);
1064                         break;
1065                     }
1066             }
1067             else if(str[0] == '#')
1068                 while(fgetc(msh->hdl) != '\n');
1069         }
1070     }
1071     else
1072     {
1073         /* Get file size */
1074
1075         CurPos = ftell(msh->hdl);
1076         fseek(msh->hdl, 0, SEEK_END);
1077         EndPos = ftell(msh->hdl);
1078         fseek(msh->hdl, CurPos, SEEK_SET);
1079
1080         /* Jump through kwd positions in the file */
1081
1082         do
1083         {
1084             /* Get the kwd code and the next kwd position */
1085
1086             ScaWrd(msh, (unsigned char *)&KwdCod);
1087             NexPos = GetPos(msh);
1088
1089             if(NexPos > EndPos)
1090                 return(0);
1091
1092             /* Check if this kwd belongs to this mesh version */
1093
1094             if( (KwdCod >= 1) && (KwdCod <= GmfMaxKwd) )
1095                 ScaKwdHdr(msh, KwdCod);
1096
1097             /* Go to the next kwd */
1098
1099             if(NexPos)
1100                 fseek(msh->hdl, NexPos, SEEK_SET);
1101         } while(NexPos && (KwdCod != GmfEnd));
1102     }
1103
1104     return(1);
1105 }
1106
1107
1108 /*----------------------------------------------------------*/
1109 /* Read and setup the keyword's header                                          */
1110 /*----------------------------------------------------------*/
1111
1112 void MeshFormatParser::ScaKwdHdr(GmfMshSct *msh, int KwdCod)
1113 {
1114     int i;
1115     KwdSct *kwd = &msh->KwdTab[ KwdCod ];
1116
1117     if(!strcmp("i", GmfKwdFmt[ KwdCod ][2]))
1118     {
1119         if(msh->typ & Asc)
1120             fscanf(msh->hdl, "%d", &kwd->NmbLin);
1121         else
1122             ScaWrd(msh, (unsigned char *)&kwd->NmbLin);
1123     }
1124     else
1125         kwd->NmbLin = 1;
1126
1127     if(!strcmp("sr", GmfKwdFmt[ KwdCod ][3]))
1128     {
1129         if(msh->typ & Asc)
1130         {
1131             fscanf(msh->hdl, "%d", &kwd->NmbTyp);
1132
1133             for(i=0; i<kwd->NmbTyp; i++)
1134                 fscanf(msh->hdl, "%d", &kwd->TypTab[i]);
1135         }
1136         else
1137         {
1138             ScaWrd(msh, (unsigned char *)&kwd->NmbTyp);
1139
1140             for(i=0; i<kwd->NmbTyp; i++)
1141                 ScaWrd(msh, (unsigned char *)&kwd->TypTab[i]);
1142         }
1143     }
1144
1145     ExpFmt(msh, KwdCod);
1146     kwd->pos = ftell(msh->hdl);
1147 }
1148
1149
1150 /*----------------------------------------------------------*/
1151 /* Expand the compacted format and compute the line size        */
1152 /*----------------------------------------------------------*/
1153
1154 void MeshFormatParser::ExpFmt(GmfMshSct *msh, int KwdCod)
1155 {
1156     int i, j, TmpSiz=0;
1157     char chr;
1158     const char *InpFmt = GmfKwdFmt[ KwdCod ][3];
1159     KwdSct *kwd = &msh->KwdTab[ KwdCod ];
1160
1161     /* Set the kwd's type */
1162
1163     if(!strlen(GmfKwdFmt[ KwdCod ][2]))
1164         kwd->typ = InfKwd;
1165     else if(!strcmp(InpFmt, "sr"))
1166         kwd->typ = SolKwd;
1167     else
1168         kwd->typ = RegKwd;
1169
1170     /* Get the solution-field's size */
1171
1172     if(kwd->typ == SolKwd)
1173         for(i=0; i<kwd->NmbTyp; i++)
1174             switch(kwd->TypTab[i])
1175             {
1176             case GmfSca    :
1177                 TmpSiz += 1;
1178                 break;
1179             case GmfVec    :
1180                 TmpSiz += msh->dim;
1181                 break;
1182             case GmfSymMat :
1183                 TmpSiz += (msh->dim * (msh->dim+1)) / 2;
1184                 break;
1185             case GmfMat    :
1186                 TmpSiz += msh->dim * msh->dim;
1187                 break;
1188             }
1189
1190     /* Scan each character from the format string */
1191
1192     i = kwd->SolSiz = kwd->NmbWrd = 0;
1193
1194     while(i < static_cast<int>(strlen(InpFmt)) )
1195     {
1196         chr = InpFmt[ i++ ];
1197
1198         if(chr == 'd')
1199         {
1200             chr = InpFmt[i++];
1201
1202             for(j=0; j<msh->dim; j++)
1203                 kwd->fmt[ kwd->SolSiz++ ] = chr;
1204         }
1205         else if(chr == 's')
1206         {
1207             chr = InpFmt[i++];
1208
1209             for(j=0; j<TmpSiz; j++)
1210                 kwd->fmt[ kwd->SolSiz++ ] = chr;
1211         }
1212         else
1213             kwd->fmt[ kwd->SolSiz++ ] = chr;
1214     }
1215
1216     for(i=0; i<kwd->SolSiz; i++)
1217         if(kwd->fmt[i] == 'i')
1218             kwd->NmbWrd++;
1219         else if(msh->ver >= 2)
1220             kwd->NmbWrd += 2;
1221         else
1222             kwd->NmbWrd++;
1223 }
1224
1225
1226 /*----------------------------------------------------------*/
1227 /* Read a four bytes word from a mesh file                                      */
1228 /*----------------------------------------------------------*/
1229
1230 void MeshFormatParser::ScaWrd(GmfMshSct *msh, unsigned char *wrd)
1231 {
1232     unsigned char swp;
1233
1234     fread(wrd, WrdSiz, 1, msh->hdl);
1235
1236     if(msh->cod == 1)
1237         return;
1238
1239     swp = wrd[3];
1240     wrd[3] = wrd[0];
1241     wrd[0] = swp;
1242
1243     swp = wrd[2];
1244     wrd[2] = wrd[1];
1245     wrd[1] = swp;
1246 }
1247
1248
1249 /*----------------------------------------------------------*/
1250 /* Read an eight bytes word from a mesh file                            */
1251 /*----------------------------------------------------------*/
1252
1253 void MeshFormatParser::ScaDblWrd(GmfMshSct *msh, unsigned char *wrd)
1254 {
1255     int i;
1256     unsigned char swp;
1257
1258     fread(wrd, WrdSiz, 2, msh->hdl);
1259
1260     if(msh->cod == 1)
1261         return;
1262
1263     for(i=0; i<4; i++)
1264     {
1265         swp = wrd[7-i];
1266         wrd[7-i] = wrd[i];
1267         wrd[i] = swp;
1268     }
1269 }
1270
1271
1272 /*----------------------------------------------------------*/
1273 /* Read ablock of four bytes word from a mesh file                      */
1274 /*----------------------------------------------------------*/
1275
1276 void MeshFormatParser::ScaBlk(GmfMshSct *msh, unsigned char *blk, int siz)
1277 {
1278     int i, j;
1279     unsigned char swp, *wrd;
1280
1281     fread(blk, WrdSiz, siz, msh->hdl);
1282
1283     if(msh->cod == 1)
1284         return;
1285
1286     for(i=0; i<siz; i++)
1287     {
1288         wrd = &blk[ i * 4 ];
1289
1290         for(j=0; j<2; j++)
1291         {
1292             swp = wrd[ 3-j ];
1293             wrd[ 3-j ] = wrd[j];
1294             wrd[j] = swp;
1295         }
1296     }
1297 }
1298
1299
1300 /*----------------------------------------------------------*/
1301 /* Read a 4 or 8 bytes position in mesh file                            */
1302 /*----------------------------------------------------------*/
1303
1304 long MeshFormatParser::GetPos(GmfMshSct *msh)
1305 {
1306     int IntVal;
1307     long pos;
1308
1309     if(msh->ver >= 3)
1310         ScaDblWrd(msh, (unsigned char*)&pos);
1311     else
1312     {
1313         ScaWrd(msh, (unsigned char*)&IntVal);
1314         pos = IntVal;
1315     }
1316
1317     return(pos);
1318 }
1319
1320
1321 /*----------------------------------------------------------*/
1322 /* Write a four bytes word to a mesh file                                       */
1323 /*----------------------------------------------------------*/
1324
1325 void MeshFormatParser::RecWrd(GmfMshSct *msh, unsigned char *wrd)
1326 {
1327     fwrite(wrd, WrdSiz, 1, msh->hdl);
1328 }
1329
1330
1331 /*----------------------------------------------------------*/
1332 /* Write an eight bytes word to a mesh file                                     */
1333 /*----------------------------------------------------------*/
1334
1335 void MeshFormatParser::RecDblWrd(GmfMshSct *msh, unsigned char *wrd)
1336 {
1337     fwrite(wrd, WrdSiz, 2, msh->hdl);
1338 }
1339
1340
1341 /*----------------------------------------------------------*/
1342 /* Write a block of four bytes word to a mesh file                      */
1343 /*----------------------------------------------------------*/
1344
1345 void MeshFormatParser::RecBlk(GmfMshSct *msh, unsigned char *blk, int siz)
1346 {
1347     /* Copy this line-block into the main mesh buffer */
1348
1349     if(siz)
1350     {
1351         memcpy(&msh->blk[ msh->pos ], blk, siz * WrdSiz);
1352         msh->pos += siz * WrdSiz;
1353     }
1354
1355     /* When the buffer is full or this procedure is called with a 0 size, flush the cache on disk */
1356
1357     if( (msh->pos > BufSiz) || (!siz && msh->pos) )
1358     {
1359         fwrite(msh->blk, 1, msh->pos, msh->hdl);
1360         msh->pos = 0;
1361     }
1362 }
1363
1364
1365 /*----------------------------------------------------------*/
1366 /* Write a 4 or 8 bytes position in a mesh file                         */
1367 /*----------------------------------------------------------*/
1368
1369 void MeshFormatParser::SetPos(GmfMshSct *msh, long pos)
1370 {
1371     int IntVal;
1372
1373     if(msh->ver >= 3)
1374         RecDblWrd(msh, (unsigned char*)&pos);
1375     else
1376     {
1377         IntVal = static_cast<int>(pos);
1378         RecWrd(msh, (unsigned char*)&IntVal);
1379     }
1380 }