Salome HOME
version 5_1_4 HOMARD_SRC
[modules/homard.git] / src / HOMARD / HOMARD_DriverTools.cxx
1 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 //
4 //  This library is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU Lesser General Public
6 //  License as published by the Free Software Foundation; either
7 //  version 2.1 of the License.
8 //
9 //  This library is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 //  Lesser General Public License for more details.
13 //
14 //  You should have received a copy of the GNU Lesser General Public
15 //  License along with this library; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
19 //
20 // ----------------------------------------------------------------------------
21 //
22 //  File   : HOMARD_DriverTools.cxx
23 //  Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
24 //
25 // ----------------------------------------------------------------------------
26
27 #include "HOMARD_DriverTools.hxx"
28 #include "HOMARD_Boundary.hxx"
29 #include "HOMARD_Cas.hxx"
30 #include "HOMARD_Hypothesis.hxx"
31 #include "HOMARD_Iteration.hxx"
32 #include "HOMARD_Zone.hxx"
33 #include <sstream>
34 #include <cstdlib>
35 #include "utilities.h"
36
37 namespace HOMARD
38 {
39
40   const char* const SEPARATOR = "|";
41
42   /*!
43     \brief Read next chunk of data from the string
44     \internal
45     
46     The function tries to read next chunk of the data from the input string \a str.
47     The parameter \a start specifies the start position of next chunk. If the operation
48     read the chunk successfully, after its completion this parameter will refer to the
49     start position of the next chunk. The function returns resulting chunk as a string.
50     The status of the operation is returned via \a ok parameter.
51     
52     \param str source data stream string
53     \param start start position to get next chunk
54     \param ok in this variable the status of the chunk reading operation is returned
55     \return next chunk read from the string
56   */
57   static std::string getNextChunk( const std::string& str, std::string::size_type& start, bool& ok )
58   {
59     std::string chunk = "";
60     ok = false;
61     if ( start <= str.size() ) {
62       std::string::size_type end = str.find( separator(), start );
63       chunk = str.substr( start, end == std::string::npos ? std::string::npos : end-start );
64       start = end == std::string::npos ? str.size()+1 : end + separator().size();
65       ok = true;
66     }
67     return chunk;
68   }
69
70   /*!
71     \brief Get persistence signature
72     \param type persistence entity type
73     \return persistence signature
74   */
75   std::string GetSignature( SignatureType type )
76   {
77     std::string signature = "";
78     switch ( type ) {
79     case Case:       signature = "CASE"; break;
80     case Zone:       signature = "ZONE"; break;
81     case Hypothesis: signature = "HYPO"; break;
82     case Iteration:  signature = "ITER"; break;
83     case Boundary:   signature = "BOUNDARY"; break;
84     default: break;
85     }
86     signature += separator();
87     return signature;
88   }
89
90   /*!
91     \brief Get data separator
92     \return string that is used to separate data entities in the stream
93   */
94   std::string separator()
95   {
96     return std::string( SEPARATOR );
97   }
98
99 // =======================
100 // Case
101 // =======================
102   /*!
103     \brief Dump case to the string
104     \param cas case being dumped
105     \return string representation of the case
106   */
107   std::string Dump( const HOMARD_Cas& cas )
108   {
109     std::stringstream os;
110     // ...
111     MESSAGE( ". Dump du cas "<<cas.GetName());
112     os << cas.GetName();
113     os << separator() << cas.GetDirName();
114     os << separator() << cas.GetConfType();
115
116     std::vector<double> coor = cas.GetBoundingBox();
117     os << separator() << coor.size();
118     for ( int i = 0; i < coor.size(); i++ )
119           os << separator() << coor[i];
120
121     std::list<std::string> ListString = cas.GetIterations();
122     os << separator() << ListString.size();
123     std::list<std::string>::const_iterator it;
124     for ( it = ListString.begin(); it != ListString.end(); ++it )
125           os << separator() << *it;
126
127     ListString = cas.GetGroups();
128     os << separator() << ListString.size();
129     for ( it = ListString.begin(); it != ListString.end(); ++it )
130          os << separator() << *it;
131     ListString = cas.GetBoundaryGroup();
132     os << separator() << ListString.size();
133     for ( it = ListString.begin(); it != ListString.end(); ++it )
134          os << separator() << *it;
135     return os.str();
136   }
137 //
138 // Iteration
139 // ==========
140 //
141   /*!
142     \brief Dump iteration to the string
143     \param iteration iteration being dumped
144     \return string representation of the iteration
145   */
146   std::string Dump( const HOMARD_Iteration& iteration )
147   {
148     std::stringstream os;
149     // ...
150     MESSAGE( ". Dump de l'iteration "<<iteration.GetName());
151     os << iteration.GetName();
152     os << separator() << iteration.GetEtat();
153     os << separator() << iteration.GetNumber();
154     os << separator() << iteration.GetMeshFile();
155     os << separator() << iteration.GetMessFile();
156     os << separator() << iteration.GetMeshName();
157     os << separator() << iteration.GetFieldFile();
158     os << separator() << iteration.GetTimeStep();
159     os << separator() << iteration.GetRank();
160     os << separator() << iteration.GetIterParent();
161     //
162     std::list<std::string> ListString = iteration.GetIterations();
163     os << separator() << ListString.size();
164     std::list<std::string>::const_iterator it;
165     for ( it = ListString.begin(); it != ListString.end(); ++it )
166       os << separator() << *it;
167
168     os << separator() << iteration.GetHypoName();
169     os << separator() << iteration.GetCaseName();
170     os << separator() << iteration.GetDirName();
171     return os.str();
172   }
173 //
174 // hypothese
175 // ==============================
176   /*!
177     \brief Dump hypothesis to the string
178     \param hypothesis hypothesis being dumped
179     \return string representation of the hypothesis
180   */
181   std::string Dump( const HOMARD_Hypothesis& hypothesis )
182   {
183     std::stringstream os;
184     // ...
185     MESSAGE( ". Dump de l'hypothese "<<hypothesis.GetName());
186     os << hypothesis.GetName();
187     os << separator() << hypothesis.GetCaseCreation();
188     os << separator() << hypothesis.GetAdapType();
189     os << separator() << hypothesis.GetRefinType();
190     os << separator() << hypothesis.GetUnRefType();
191     os << separator() << hypothesis.GetFieldName();
192     os << separator() << hypothesis.GetRefinThrType();
193     os << separator() << hypothesis.GetThreshR();
194     os << separator() << hypothesis.GetUnRefThrType();
195     os << separator() << hypothesis.GetThreshC();
196     os << separator() << hypothesis.GetUseCompI();
197     os << separator() << hypothesis.GetTypeFieldInterp();
198
199
200     std::list<std::string> ListString = hypothesis.GetIterations();
201     std::list<std::string>::const_iterator it;
202     os << separator() << ListString.size();
203     for ( it = ListString.begin(); it != ListString.end(); ++it )
204          os << separator() << *it;
205
206     ListString = hypothesis.GetZones();
207     os << separator() << ListString.size();
208     for ( it = ListString.begin(); it != ListString.end(); ++it )
209           os << separator() << *it;
210
211     ListString = hypothesis.GetListComp();
212     os << separator() << ListString.size();
213     for ( it = ListString.begin(); it != ListString.end(); ++it )
214          os << separator() << *it;
215
216     ListString = hypothesis.GetGroups();
217     os << separator() << ListString.size();
218     for ( it = ListString.begin(); it != ListString.end(); ++it )
219           os << separator() << *it;
220
221     ListString = hypothesis.GetListFieldInterp();
222     os << separator() << ListString.size();
223     for ( it = ListString.begin(); it != ListString.end(); ++it )
224           os << separator() << *it;
225     return os.str();
226   }
227 //
228 // Zone
229 // =========================
230
231   /*!
232     \brief Dump zone to the string
233     \param zone zone being dumped
234     \return string representation of the zone
235   */
236   std::string Dump( const HOMARD_Zone& zone )
237   {
238     std::stringstream os;
239     os << zone.GetName();
240     os << separator() << zone.GetZoneType();
241
242     std::vector<double> box = zone.GetBox();
243     for ( int i = 0; i < box.size(); i++ )
244       os << separator() << ( i < box.size() ? box[i] : 0. );
245
246     std::vector<double> sphere = zone.GetSphere();
247     for ( int i = 0; i < 4; i++ )
248       os << separator() << ( i < sphere.size() ? sphere[i] : 0. );
249
250     std::vector<double> limit = zone.GetLimit();
251     for ( int i = 0; i < 3; i++ )
252       os << separator() << ( i < limit.size() ? limit[i] : 0. );
253
254     std::list<std::string> hypos = zone.GetHypo();
255     os << separator() << hypos.size();
256     std::list<std::string>::const_iterator it;
257     for ( it = hypos.begin(); it != hypos.end(); ++it )
258       os << separator() << *it;
259     return os.str();  
260
261
262   }
263 //
264 // 1.5. Archivage d'une frontiere
265 // ==============================
266
267   /*!
268     \brief Dump boundary to the string
269     \param boundary boundary being dumped
270     \return string representation of the boundary
271   */
272   std::string Dump( const HOMARD_Boundary& boundary )
273   {
274     std::stringstream os;
275
276     os << boundary.GetName() ;
277     os << separator() << boundary.GetBoundaryType() ;
278     os << separator() << boundary.GetCaseCreation() ;
279     os << separator() << boundary.GetMeshFile();
280     os << separator() << boundary.GetMeshName();
281
282     std::vector<double> coor = boundary.GetLimit();
283     for ( int i = 0; i < coor.size(); i++ )
284           os << separator() << coor[i];
285
286     coor = boundary.GetCylinder() ; 
287     for ( int i = 0; i < coor.size(); i++ )
288           os << separator() << coor[i];
289
290     coor = boundary.GetSphere() ; 
291     for ( int i = 0; i < coor.size(); i++ )
292           os << separator() << coor[i];
293     return os.str();
294
295     std::list<std::string> ListString = boundary.GetGroups();
296     std::list<std::string>::const_iterator it;
297     os << separator() << ListString.size();
298     for ( it = ListString.begin(); it != ListString.end(); ++it )
299           os << separator() << *it;
300
301   }
302
303 //
304 // Restauration des objets
305 // ==========================
306 // Case
307 // ==========================
308 //
309   /*!
310     \brief Restore case from the string
311     \param cas case being restored
312     \param stream string representation of the case
313     \return \c true if case is correctly restored or \c false otherwise
314   */
315   bool Restore( HOMARD_Cas& cas, const std::string& stream )
316   {
317     std::string::size_type start = 0;
318     std::string chunk, chunkNext;
319     bool ok;
320     // ...
321     chunk = getNextChunk( stream, start, ok );
322     if ( !ok ) return false;
323     cas.SetName( chunk.c_str() );
324
325     chunk = getNextChunk( stream, start, ok );
326     if ( !ok ) return false;
327     cas.SetDirName( chunk.c_str() );
328
329     chunk = getNextChunk( stream, start, ok );
330     if ( !ok ) return false;
331     cas.SetConfType( atoi( chunk.c_str() ) );
332
333     chunk = getNextChunk( stream, start, ok );
334     if ( !ok ) return false;
335
336     int size = atoi( chunk.c_str() );
337     std::vector<double> boite;
338     boite.resize( size );
339     for ( int i = 0; i < size; i++ ) {
340       chunk = getNextChunk( stream, start, ok );
341       if ( !ok ) return false;
342       boite[i] = strtod( chunk.c_str(), 0 );
343     }
344     cas.SetBoundingBox( boite );
345
346     chunk = getNextChunk( stream, start, ok );
347     if ( !ok ) return false;
348
349     size = atoi( chunk.c_str() );
350     for ( int i = 0; i < size; i++ ) {
351       chunk = getNextChunk( stream, start, ok );
352       if ( !ok ) return false;
353       cas.AddIteration( chunk.c_str() );
354     }
355
356     chunk = getNextChunk( stream, start, ok );
357     if ( !ok ) return false;
358     size = atoi( chunk.c_str() );
359     for ( int i = 0; i < size; i++ ) 
360     {
361       chunk = getNextChunk( stream, start, ok );
362       if ( !ok ) return false;
363       cas.AddGroup( chunk.c_str() );
364     }
365
366     chunk = getNextChunk( stream, start, ok );
367     if ( !ok ) return false;
368     size = atoi( chunk.c_str() );
369     for ( int i = 0; i < size; i++ ) {
370       chunk = getNextChunk( stream, start, ok );
371       if ( !ok ) return false;
372       i++;
373       chunkNext = getNextChunk( stream, start, ok );
374       if ( !ok ) return false;
375       cas.AddBoundaryGroup( chunk.c_str(), chunkNext.c_str() );
376     }
377     return true;
378   }
379 //
380 //  Iteration
381 // =================================
382   /*!
383     \brief Restore iteration from the string
384     \param iteration iteration being restored
385     \param stream string representation of the iteration
386     \return \c true if iteration is correctly restored or \c false otherwise
387   */
388   bool Restore( HOMARD_Iteration& iteration, const std::string& stream )
389   {
390     std::string::size_type start = 0;
391     std::string chunk;
392     bool ok;
393     chunk = getNextChunk( stream, start, ok );
394     if ( !ok ) return false;
395
396     iteration.SetName( chunk.c_str() );
397     chunk = getNextChunk( stream, start, ok );
398     if ( !ok ) return false;
399     iteration.SetEtat( (bool)atoi( chunk.c_str() ) );
400     chunk = getNextChunk( stream, start, ok );
401     if ( !ok ) return false;
402     iteration.SetNumber( atoi( chunk.c_str() ) );
403     chunk = getNextChunk( stream, start, ok );
404     if ( !ok ) return false;
405     iteration.SetMeshFile( chunk.c_str() );
406     chunk = getNextChunk( stream, start, ok );
407     if ( !ok ) return false;
408     iteration.SetMessFile( chunk.c_str() );
409     chunk = getNextChunk( stream, start, ok );
410     if ( !ok ) return false;
411     iteration.SetMeshName( chunk.c_str() );
412     chunk = getNextChunk( stream, start, ok );
413     if ( !ok ) return false;
414     iteration.SetFieldFile( chunk.c_str() );
415     // .
416     int timestep, rank;
417     chunk = getNextChunk( stream, start, ok );
418     if ( !ok ) return false;
419     timestep = atoi( chunk.c_str() );
420     chunk = getNextChunk( stream, start, ok );
421     if ( !ok ) return false;
422     rank = atoi( chunk.c_str() );
423     iteration.SetTimeStepRank( timestep, rank );
424     chunk = getNextChunk( stream, start, ok );
425     if ( !ok ) return false;
426     iteration.SetIterParent( chunk.c_str() );
427     //
428     chunk = getNextChunk( stream, start, ok );
429     if ( !ok ) return false;
430     int size = atoi( chunk.c_str() );
431     for ( int i = 0; i < size; i++ ) {
432       chunk = getNextChunk( stream, start, ok );
433       if ( !ok ) return false;
434       iteration.AddIteration( chunk.c_str() );
435     }
436     // 
437     chunk = getNextChunk( stream, start, ok );
438     if ( !ok ) return false;
439     iteration.SetHypoName( chunk.c_str() );
440     chunk = getNextChunk( stream, start, ok );
441     if ( !ok ) return false;
442     iteration.SetCaseName( chunk.c_str() );
443     chunk = getNextChunk( stream, start, ok );
444     if ( !ok ) return false;
445     iteration.SetDirName( chunk.c_str() );
446     return true;
447   }
448
449 //
450 // hypothese
451 // =================================
452   /*!
453     \brief Restore hypothesis from the string
454     \param hypothesis hypothesis being restored
455     \param stream string representation of the hypothesis
456     \return \c true if hypothesis is correctly restored or \c false otherwise
457   */
458   bool Restore( HOMARD_Hypothesis& hypothesis, const std::string& stream )
459   {
460     std::string::size_type start = 0;
461     std::string chunk;
462     bool ok;
463
464     chunk = getNextChunk( stream, start, ok );
465     if ( !ok ) return false;
466     hypothesis.SetName( chunk.c_str() );
467
468     chunk = getNextChunk( stream, start, ok );
469     if ( !ok ) return false;
470     hypothesis.SetCaseCreation( chunk.c_str() );
471
472     chunk = getNextChunk( stream, start, ok );
473     if ( !ok ) return false;
474     hypothesis.SetAdapType( atoi( chunk.c_str() ) );
475
476     chunk = getNextChunk( stream, start, ok );
477     if ( !ok ) return false;
478     int typeraff = atoi( chunk.c_str() );
479     chunk = getNextChunk( stream, start, ok );
480     if ( !ok ) return false;
481     int typedera = atoi( chunk.c_str() );
482     hypothesis.SetRefinTypeDera( typeraff, typedera );
483
484     chunk = getNextChunk( stream, start, ok );
485     if ( !ok ) return false;
486     hypothesis.SetField( chunk.c_str() );
487
488     chunk = getNextChunk( stream, start, ok );
489     if ( !ok ) return false;
490     int typethr = atoi( chunk.c_str() );
491     chunk = getNextChunk( stream, start, ok );
492     if ( !ok ) return false;
493     double threshr = strtod( chunk.c_str(), 0 );
494     hypothesis.SetRefinThr( typethr, threshr );
495
496     chunk = getNextChunk( stream, start, ok );
497     if ( !ok ) return false;
498     int typethc = atoi( chunk.c_str() );
499     chunk = getNextChunk( stream, start, ok );
500     if ( !ok ) return false;
501     double threshc = strtod( chunk.c_str(), 0 );
502     hypothesis.SetUnRefThr( typethc, threshc );
503
504     chunk = getNextChunk( stream, start, ok );
505     if ( !ok ) return false;
506     hypothesis.SetUseComp(atoi(chunk.c_str()));
507
508     chunk = getNextChunk( stream, start, ok );
509     if ( !ok ) return false;
510     hypothesis.SetTypeFieldInterp(atoi(chunk.c_str()));
511
512     chunk = getNextChunk( stream, start, ok );
513     if ( !ok ) return false;
514     int size = atoi( chunk.c_str() );
515     for ( int i = 0; i < size; i++ ) {
516       chunk = getNextChunk( stream, start, ok );
517       if ( !ok ) return false;
518       hypothesis.AddIteration( chunk.c_str() );
519     }
520
521     chunk = getNextChunk( stream, start, ok );
522     if ( !ok ) return false;
523     size = atoi( chunk.c_str() );
524     for ( int i = 0; i < size; i++ ) {
525       chunk = getNextChunk( stream, start, ok );
526       if ( !ok ) return false;
527       hypothesis.AddZone( chunk.c_str() );
528     }
529
530     chunk = getNextChunk( stream, start, ok );
531     if ( !ok ) return false;
532     size = atoi( chunk.c_str() );
533     for ( int i = 0; i < size; i++ ) {
534       chunk = getNextChunk( stream, start, ok );
535       if ( !ok ) return false;
536       hypothesis.AddComp( chunk.c_str() );
537     }
538
539     chunk = getNextChunk( stream, start, ok );
540     if ( !ok ) return false;
541     size = atoi( chunk.c_str() );
542     for ( int i = 0; i < size; i++ ) {
543       chunk = getNextChunk( stream, start, ok );
544       if ( !ok ) return false;
545       hypothesis.AddGroup( chunk.c_str() );
546     }
547
548     chunk = getNextChunk( stream, start, ok );
549     if ( !ok ) return false;
550     size = atoi( chunk.c_str() );
551     for ( int i = 0; i < size; i++ ) {
552       chunk = getNextChunk( stream, start, ok );
553       if ( !ok ) return false;
554       hypothesis.AddFieldInterp( chunk.c_str() );
555     }
556     return true;
557   }
558
559 //
560 // Zone
561 // ============================
562   /*!
563     \brief Restore zone from the string
564     \param zone zone being restored
565     \param stream string representation of the zone
566     \return \c true if zone is correctly restored or \c false otherwise
567   */
568   bool Restore( HOMARD_Zone& zone, const std::string& stream )
569   {
570     std::string::size_type start = 0;
571     std::string chunk;
572     bool ok;
573     // 
574     chunk = getNextChunk( stream, start, ok );
575     if ( !ok ) return false;
576     zone.SetName( chunk.c_str() );
577     //
578     chunk = getNextChunk( stream, start, ok );
579     if ( !ok ) return false;
580     zone.SetZoneType( atoi( chunk.c_str() ) );
581     //
582     std::vector<double> coords;
583     coords.resize( 6 );
584     for ( int i = 0; i < 6; i++ ) {
585       chunk = getNextChunk( stream, start, ok );
586       if ( !ok ) return false;
587       coords[i] = strtod( chunk.c_str(), 0 );
588     }
589     zone.SetBox( coords[0], coords[1], coords[2], coords[3], coords[4], coords[5] );
590     //
591     for ( int i = 0; i < 4; i++ ) {
592       chunk = getNextChunk( stream, start, ok );
593       if ( !ok ) return false;
594       coords[i] = strtod( chunk.c_str(), 0 );
595     }
596     zone.SetSphere( coords[0], coords[1], coords[2], coords[3] );
597
598     //
599     for ( int i = 0; i < 3; i++ ) {
600       chunk = getNextChunk( stream, start, ok );
601       if ( !ok ) return false;
602       coords[i] = strtod( chunk.c_str(), 0 );
603     }
604     zone.SetLimit( coords[0], coords[1], coords[2]);
605
606     chunk = getNextChunk( stream, start, ok );
607     if ( !ok ) return false;
608     int size = atoi( chunk.c_str() );
609     for ( int i = 0; i < size; i++ ) {
610       chunk = getNextChunk( stream, start, ok );
611       if ( !ok ) return false;
612       zone.AddHypo( chunk.c_str() );
613     }
614     return true;
615   }
616
617
618 //
619 // 2.5. Restauration d'une frontiere
620 // =================================
621
622   /*!
623     \brief Restore boundary from the string
624     \param boundary boundary being restored
625     \param stream string representation of the boundary
626     \return \c true if zone is correctly restored or \c false otherwise
627   */
628   bool Restore( HOMARD_Boundary& boundary, const std::string& stream )
629   {
630     std::string::size_type start = 0;
631     std::string chunk;
632     bool ok;
633
634     chunk = getNextChunk( stream, start, ok );
635     if ( !ok ) return false;
636     boundary.SetName( chunk.c_str() );
637
638     chunk = getNextChunk( stream, start, ok );
639     if ( !ok ) return false;
640     boundary.SetBoundaryType(atoi( chunk.c_str()) );
641
642     chunk = getNextChunk( stream, start, ok );
643     if ( !ok ) return false;
644     boundary.SetCaseCreation( chunk.c_str() );
645
646     chunk = getNextChunk( stream, start, ok );
647     if ( !ok ) return false;
648     boundary.SetMeshFile( chunk.c_str() );
649
650     chunk = getNextChunk( stream, start, ok );
651     if ( !ok ) return false;
652     boundary.SetMeshName( chunk.c_str() );
653
654
655     std::vector<double> coords;
656     coords.resize( 3 );
657     for ( int i = 0; i < 3; i++ ) {
658       chunk = getNextChunk( stream, start, ok );
659       if ( !ok ) return false;
660       coords[i] = strtod( chunk.c_str(), 0 );
661     }
662     boundary.SetLimit( coords[0], coords[1], coords[2]);
663
664     coords.resize( 7 );
665     for ( int i = 0; i < 7; i++ ) {
666       chunk = getNextChunk( stream, start, ok );
667       if ( !ok ) return false;
668       coords[i] = strtod( chunk.c_str(), 0 );
669     }
670     boundary.SetCylinder(coords[0],coords[1],coords[2],coords[3],coords[4],coords[5],coords[6]);
671
672     coords.resize( 4 );
673     for ( int i = 0; i < 4; i++ ) {
674       chunk = getNextChunk( stream, start, ok );
675       if ( !ok ) return false;
676       coords[i] = strtod( chunk.c_str(), 0 );
677     }
678     boundary.SetSphere( coords[0], coords[1], coords[2], coords[3]);
679
680     chunk = getNextChunk( stream, start, ok );
681     if ( !ok ) return false;
682     int size = atoi( chunk.c_str() );
683     for ( int i = 0; i < size; i++ ) {
684       chunk = getNextChunk( stream, start, ok );
685       if ( !ok ) return false;
686       boundary.AddGroup( chunk.c_str() );
687     }
688
689     return true;
690   }
691
692 } // namespace HOMARD /end/