1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9  * and including many others, as listed in the AUTHORS file in the
10  * top-level source directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 #include "gmxpre.h"
39 
40 #include "gmxfio_xdr.h"
41 
42 #include <cstddef>
43 #include <cstdio>
44 #include <cstring>
45 
46 #include <limits>
47 
48 #include "gromacs/fileio/gmxfio.h"
49 #include "gromacs/fileio/xdrf.h"
50 #include "gromacs/utility/fatalerror.h"
51 #include "gromacs/utility/gmxassert.h"
52 #include "gromacs/utility/smalloc.h"
53 
54 #include "gmxfio_impl.h"
55 
56 /* Enumerated for data types in files */
57 enum
58 {
59     eioREAL,
60     eioFLOAT,
61     eioDOUBLE,
62     eioINT,
63     eioINT32,
64     eioINT64,
65     eioUCHAR,
66     eioCHAR,
67     eioNCHAR,
68     eioNUCHAR,
69     eioUSHORT,
70     eioRVEC,
71     eioNRVEC,
72     eioIVEC,
73     eioSTRING,
74     eioOPAQUE,
75     eioNR
76 };
77 
78 static const char* eioNames[eioNR] = { "REAL",  "FLOAT", "DOUBLE", "INT",    "INT32",  "INT64",
79                                        "UCHAR", "CHAR",  "NCHAR",  "NUCHAR", "USHORT", "RVEC",
80                                        "NRVEC", "IVEC",  "STRING", "OPAQUE" };
81 
gmx_fio_setprecision(t_fileio * fio,gmx_bool bDouble)82 void gmx_fio_setprecision(t_fileio* fio, gmx_bool bDouble)
83 {
84     gmx_fio_lock(fio);
85     fio->bDouble = bDouble;
86     gmx_fio_unlock(fio);
87 }
88 
gmx_fio_is_double(t_fileio * fio)89 bool gmx_fio_is_double(t_fileio* fio)
90 {
91     bool isDouble = false;
92     gmx_fio_lock(fio);
93     isDouble = fio->bDouble;
94     gmx_fio_unlock(fio);
95     return isDouble;
96 }
97 
gmx_fio_getxdr(t_fileio * fio)98 XDR* gmx_fio_getxdr(t_fileio* fio)
99 {
100     XDR* ret = nullptr;
101     gmx_fio_lock(fio);
102     GMX_RELEASE_ASSERT(fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
103     ret = fio->xdr;
104     gmx_fio_unlock(fio);
105     return ret;
106 }
107 
108 /* check the number of items given against the type */
gmx_fio_check_nitem(int eio,std::size_t nitem,const char * file,int line)109 static void gmx_fio_check_nitem(int eio, std::size_t nitem, const char* file, int line)
110 {
111     if ((nitem != 1)
112         && !((eio == eioNRVEC) || (eio == eioNUCHAR) || (eio == eioNCHAR) || (eio == eioOPAQUE)))
113     {
114         gmx_fatal(FARGS,
115                   "nitem may differ from 1 only for %s, %s, %s or %s, not for %s"
116                   "(%s, %d)",
117                   eioNames[eioNUCHAR], eioNames[eioNRVEC], eioNames[eioNCHAR], eioNames[eioOPAQUE],
118                   eioNames[eio], file, line);
119     }
120 }
121 
122 /* output a data type error. */
gmx_fio_fe(t_fileio * fio,int eio,const char * desc,const char * srcfile,int line)123 [[noreturn]] static void gmx_fio_fe(t_fileio* fio, int eio, const char* desc, const char* srcfile, int line)
124 {
125     gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d", fio->bRead ? "read" : "write",
126               desc, eio, ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown", srcfile, line);
127 }
128 
129 /* This is the part that reads xdr files.  */
130 
131 static gmx_bool
do_xdr(t_fileio * fio,void * item,std::size_t nitem,int eio,const char * desc,const char * srcfile,int line)132 do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc, const char* srcfile, int line)
133 {
134     unsigned char  ucdum, *ucptr;
135     char           cdum, *cptr;
136     bool_t         res = 0;
137     float          fvec[DIM];
138     double         dvec[DIM];
139     int            m, *iptr, idum;
140     int32_t        s32dum;
141     int64_t        s64dum;
142     real*          ptr;
143     unsigned short us;
144     double         d = 0;
145     float          f = 0;
146 
147     GMX_RELEASE_ASSERT(fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
148     gmx_fio_check_nitem(eio, nitem, srcfile, line);
149     switch (eio)
150     {
151         case eioREAL:
152             if (fio->bDouble)
153             {
154                 if (item && !fio->bRead)
155                 {
156                     d = *(static_cast<real*>(item));
157                 }
158                 res = xdr_double(fio->xdr, &d);
159                 if (item)
160                 {
161                     *(static_cast<real*>(item)) = d;
162                 }
163             }
164             else
165             {
166                 if (item && !fio->bRead)
167                 {
168                     f = *(static_cast<real*>(item));
169                 }
170                 res = xdr_float(fio->xdr, &f);
171                 if (item)
172                 {
173                     *(static_cast<real*>(item)) = f;
174                 }
175             }
176             break;
177         case eioFLOAT:
178             if (item && !fio->bRead)
179             {
180                 f = *(static_cast<float*>(item));
181             }
182             res = xdr_float(fio->xdr, &f);
183             if (item)
184             {
185                 *(static_cast<float*>(item)) = f;
186             }
187             break;
188         case eioDOUBLE:
189             if (item && !fio->bRead)
190             {
191                 d = *(static_cast<double*>(item));
192             }
193             res = xdr_double(fio->xdr, &d);
194             if (item)
195             {
196                 *(static_cast<double*>(item)) = d;
197             }
198             break;
199         case eioINT:
200             if (item && !fio->bRead)
201             {
202                 idum = *static_cast<int*>(item);
203             }
204             res = xdr_int(fio->xdr, &idum);
205             if (item)
206             {
207                 *static_cast<int*>(item) = idum;
208             }
209             break;
210         case eioINT32:
211             if (item && !fio->bRead)
212             {
213                 s32dum = *static_cast<int32_t*>(item);
214             }
215             res = xdr_int32(fio->xdr, &s32dum);
216             if (item)
217             {
218                 *static_cast<int32_t*>(item) = s32dum;
219             }
220             break;
221         case eioINT64:
222             if (item && !fio->bRead)
223             {
224                 s64dum = *static_cast<int64_t*>(item);
225             }
226             res = xdr_int64(fio->xdr, &s64dum);
227             if (item)
228             {
229                 *static_cast<int64_t*>(item) = s64dum;
230             }
231             break;
232         case eioUCHAR:
233             if (item && !fio->bRead)
234             {
235                 ucdum = *static_cast<unsigned char*>(item);
236             }
237             res = xdr_u_char(fio->xdr, &ucdum);
238             if (item)
239             {
240                 *static_cast<unsigned char*>(item) = ucdum;
241             }
242             break;
243         case eioCHAR:
244             if (item && !fio->bRead)
245             {
246                 cdum = *static_cast<char*>(item);
247             }
248             res = xdr_char(fio->xdr, &cdum);
249             if (item)
250             {
251                 *static_cast<char*>(item) = cdum;
252             }
253             break;
254         case eioNCHAR:
255             cptr = static_cast<char*>(item);
256             GMX_RELEASE_ASSERT(nitem < static_cast<std::size_t>(std::numeric_limits<int>::max()),
257                                "The XDR interface cannot handle array lengths > 2^31");
258             res = xdr_vector(fio->xdr, cptr, static_cast<int>(nitem),
259                              static_cast<unsigned int>(sizeof(char)),
260                              reinterpret_cast<xdrproc_t>(xdr_char));
261             break;
262         case eioNUCHAR:
263             ucptr = static_cast<unsigned char*>(item);
264             GMX_RELEASE_ASSERT(nitem < static_cast<std::size_t>(std::numeric_limits<int>::max()),
265                                "The XDR interface cannot handle array lengths > 2^31");
266             res = xdr_vector(fio->xdr, reinterpret_cast<char*>(ucptr), static_cast<int>(nitem),
267                              static_cast<unsigned int>(sizeof(unsigned char)),
268                              reinterpret_cast<xdrproc_t>(xdr_u_char));
269             break;
270         case eioUSHORT:
271             if (item && !fio->bRead)
272             {
273                 us = *static_cast<unsigned short*>(item);
274             }
275             res = xdr_u_short(fio->xdr, &us);
276             if (item)
277             {
278                 *static_cast<unsigned short*>(item) = us;
279             }
280             break;
281         case eioRVEC:
282             if (fio->bDouble)
283             {
284                 if (item && !fio->bRead)
285                 {
286                     for (m = 0; (m < DIM); m++)
287                     {
288                         dvec[m] = (static_cast<real*>(item))[m];
289                     }
290                 }
291                 res = xdr_vector(fio->xdr, reinterpret_cast<char*>(dvec), DIM,
292                                  static_cast<unsigned int>(sizeof(double)),
293                                  reinterpret_cast<xdrproc_t>(xdr_double));
294                 if (item)
295                 {
296                     for (m = 0; (m < DIM); m++)
297                     {
298                         (static_cast<real*>(item))[m] = dvec[m];
299                     }
300                 }
301             }
302             else
303             {
304                 if (item && !fio->bRead)
305                 {
306                     for (m = 0; (m < DIM); m++)
307                     {
308                         fvec[m] = (static_cast<real*>(item))[m];
309                     }
310                 }
311                 res = xdr_vector(fio->xdr, reinterpret_cast<char*>(fvec), DIM,
312                                  static_cast<unsigned int>(sizeof(float)),
313                                  reinterpret_cast<xdrproc_t>(xdr_float));
314                 if (item)
315                 {
316                     for (m = 0; (m < DIM); m++)
317                     {
318                         (static_cast<real*>(item))[m] = fvec[m];
319                     }
320                 }
321             }
322             break;
323         case eioNRVEC:
324             ptr = nullptr;
325             res = 1;
326             for (std::size_t j = 0; j < nitem && res; j++)
327             {
328                 if (item)
329                 {
330                     ptr = (static_cast<rvec*>(item))[j];
331                 }
332                 res = static_cast<bool_t>(do_xdr(fio, ptr, 1, eioRVEC, desc, srcfile, line));
333             }
334             break;
335         case eioIVEC:
336             iptr = static_cast<int*>(item);
337             res  = 1;
338             for (m = 0; (m < DIM) && res; m++)
339             {
340                 if (item && !fio->bRead)
341                 {
342                     idum = iptr[m];
343                 }
344                 res = xdr_int(fio->xdr, &idum);
345                 if (item)
346                 {
347                     iptr[m] = idum;
348                 }
349             }
350             break;
351         case eioSTRING:
352         {
353             char* cptr;
354             int   slen;
355 
356             if (item)
357             {
358                 if (!fio->bRead)
359                 {
360                     slen = strlen(static_cast<char*>(item)) + 1;
361                 }
362                 else
363                 {
364                     slen = 0;
365                 }
366             }
367             else
368             {
369                 slen = 0;
370             }
371 
372             if (xdr_int(fio->xdr, &slen) <= 0)
373             {
374                 gmx_fatal(FARGS,
375                           "wrong string length %d for string %s"
376                           " (source %s, line %d)",
377                           slen, desc, srcfile, line);
378             }
379             if (!item && fio->bRead)
380             {
381                 snew(cptr, slen);
382             }
383             else
384             {
385                 cptr = static_cast<char*>(item);
386             }
387             if (cptr)
388             {
389                 res = xdr_string(fio->xdr, &cptr, slen);
390             }
391             else
392             {
393                 res = 1;
394             }
395             if (!item && fio->bRead)
396             {
397                 sfree(cptr);
398             }
399             break;
400         }
401         case eioOPAQUE:
402         {
403             if (item == nullptr && nitem > 0)
404             {
405                 gmx_fatal(FARGS, "Null pointer provided for non-zero length XDR opaque data.");
406             }
407 
408             if (nitem > 0)
409             {
410                 // We need to support very large opaque data objects although the default
411                 // XDR interface only uses integers for the size field, since gromacs-2020
412                 // e.g. embeds the entire TPR body as a single such object, which would break all
413                 // TPR files larger than 2GB unless we handle it as a special case.
414                 // To avoid inserting extra padding, we calculate the chunk size as:
415                 // - The max value of a signed integer + 1
416                 // - Subtract 4 (the XDR object size) to get a size within the range of the signed int.
417                 const std::size_t maxChunk =
418                         static_cast<std::size_t>(std::numeric_limits<int>::max()) + 1 - 4;
419 
420                 for (res = 1; res > 0 && nitem > 0;)
421                 {
422                     std::size_t thisChunk = std::min(maxChunk, nitem);
423                     res = xdr_opaque(fio->xdr, reinterpret_cast<char*>(item), thisChunk);
424                     nitem -= thisChunk;
425                 }
426             }
427             else
428             {
429                 res = 1;
430             }
431             break;
432         }
433         default: gmx_fio_fe(fio, eio, desc, srcfile, line);
434     }
435 
436     return (res != 0);
437 }
438 
439 /*******************************************************************
440  *
441  * READ/WRITE FUNCTIONS
442  *
443  *******************************************************************/
444 
gmx_fio_writee_string(t_fileio * fio,const char * item,const char * desc,const char * srcfile,int line)445 gmx_bool gmx_fio_writee_string(t_fileio* fio, const char* item, const char* desc, const char* srcfile, int line)
446 {
447     gmx_bool ret;
448     void*    it = const_cast<char*>(item); /* ugh.. */
449     gmx_fio_lock(fio);
450     ret = do_xdr(fio, it, 1, eioSTRING, desc, srcfile, line);
451     gmx_fio_unlock(fio);
452     return ret;
453 }
454 
gmx_fio_doe_real(t_fileio * fio,real * item,const char * desc,const char * srcfile,int line)455 gmx_bool gmx_fio_doe_real(t_fileio* fio, real* item, const char* desc, const char* srcfile, int line)
456 {
457     gmx_bool ret;
458     gmx_fio_lock(fio);
459     ret = do_xdr(fio, item, 1, eioREAL, desc, srcfile, line);
460     gmx_fio_unlock(fio);
461     return ret;
462 }
463 
gmx_fio_doe_float(t_fileio * fio,float * item,const char * desc,const char * srcfile,int line)464 gmx_bool gmx_fio_doe_float(t_fileio* fio, float* item, const char* desc, const char* srcfile, int line)
465 {
466     gmx_bool ret;
467     gmx_fio_lock(fio);
468     ret = do_xdr(fio, item, 1, eioFLOAT, desc, srcfile, line);
469     gmx_fio_unlock(fio);
470     return ret;
471 }
472 
gmx_fio_doe_double(t_fileio * fio,double * item,const char * desc,const char * srcfile,int line)473 gmx_bool gmx_fio_doe_double(t_fileio* fio, double* item, const char* desc, const char* srcfile, int line)
474 {
475     gmx_bool ret;
476     gmx_fio_lock(fio);
477     ret = do_xdr(fio, item, 1, eioDOUBLE, desc, srcfile, line);
478     gmx_fio_unlock(fio);
479     return ret;
480 }
481 
482 
gmx_fio_doe_gmx_bool(t_fileio * fio,gmx_bool * item,const char * desc,const char * srcfile,int line)483 gmx_bool gmx_fio_doe_gmx_bool(t_fileio* fio, gmx_bool* item, const char* desc, const char* srcfile, int line)
484 {
485     gmx_bool ret;
486 
487     gmx_fio_lock(fio);
488     if (fio->bRead)
489     {
490         int itmp = 0;
491         ret      = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
492         *item    = (itmp != 0);
493     }
494     else
495     {
496         int itmp = static_cast<int>(*item);
497         ret      = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
498     }
499     gmx_fio_unlock(fio);
500     return ret;
501 }
502 
gmx_fio_doe_int(t_fileio * fio,int * item,const char * desc,const char * srcfile,int line)503 gmx_bool gmx_fio_doe_int(t_fileio* fio, int* item, const char* desc, const char* srcfile, int line)
504 {
505     gmx_bool ret;
506     gmx_fio_lock(fio);
507     ret = do_xdr(fio, item, 1, eioINT, desc, srcfile, line);
508     gmx_fio_unlock(fio);
509     return ret;
510 }
511 
gmx_fio_doe_int32(t_fileio * fio,int32_t * item,const char * desc,const char * srcfile,int line)512 gmx_bool gmx_fio_doe_int32(t_fileio* fio, int32_t* item, const char* desc, const char* srcfile, int line)
513 {
514     gmx_bool ret;
515     gmx_fio_lock(fio);
516     ret = do_xdr(fio, item, 1, eioINT32, desc, srcfile, line);
517     gmx_fio_unlock(fio);
518     return ret;
519 }
520 
gmx_fio_doe_int64(t_fileio * fio,int64_t * item,const char * desc,const char * srcfile,int line)521 gmx_bool gmx_fio_doe_int64(t_fileio* fio, int64_t* item, const char* desc, const char* srcfile, int line)
522 {
523     gmx_bool ret;
524     gmx_fio_lock(fio);
525     ret = do_xdr(fio, item, 1, eioINT64, desc, srcfile, line);
526     gmx_fio_unlock(fio);
527     return ret;
528 }
529 
gmx_fio_doe_uchar(t_fileio * fio,unsigned char * item,const char * desc,const char * srcfile,int line)530 gmx_bool gmx_fio_doe_uchar(t_fileio* fio, unsigned char* item, const char* desc, const char* srcfile, int line)
531 {
532     gmx_bool ret;
533     gmx_fio_lock(fio);
534     ret = do_xdr(fio, item, 1, eioUCHAR, desc, srcfile, line);
535     gmx_fio_unlock(fio);
536     return ret;
537 }
538 
gmx_fio_doe_char(t_fileio * fio,char * item,const char * desc,const char * srcfile,int line)539 gmx_bool gmx_fio_doe_char(t_fileio* fio, char* item, const char* desc, const char* srcfile, int line)
540 {
541     gmx_bool ret;
542     gmx_fio_lock(fio);
543     ret = do_xdr(fio, item, 1, eioCHAR, desc, srcfile, line);
544     gmx_fio_unlock(fio);
545     return ret;
546 }
547 
gmx_fio_doe_ushort(t_fileio * fio,unsigned short * item,const char * desc,const char * srcfile,int line)548 gmx_bool gmx_fio_doe_ushort(t_fileio* fio, unsigned short* item, const char* desc, const char* srcfile, int line)
549 {
550     gmx_bool ret;
551     gmx_fio_lock(fio);
552     ret = do_xdr(fio, item, 1, eioUSHORT, desc, srcfile, line);
553     gmx_fio_unlock(fio);
554     return ret;
555 }
556 
gmx_fio_doe_rvec(t_fileio * fio,rvec * item,const char * desc,const char * srcfile,int line)557 gmx_bool gmx_fio_doe_rvec(t_fileio* fio, rvec* item, const char* desc, const char* srcfile, int line)
558 {
559     gmx_bool ret;
560     gmx_fio_lock(fio);
561     ret = do_xdr(fio, item, 1, eioRVEC, desc, srcfile, line);
562     gmx_fio_unlock(fio);
563     return ret;
564 }
565 
gmx_fio_doe_ivec(t_fileio * fio,ivec * item,const char * desc,const char * srcfile,int line)566 gmx_bool gmx_fio_doe_ivec(t_fileio* fio, ivec* item, const char* desc, const char* srcfile, int line)
567 {
568     gmx_bool ret;
569     gmx_fio_lock(fio);
570     ret = do_xdr(fio, item, 1, eioIVEC, desc, srcfile, line);
571     gmx_fio_unlock(fio);
572     return ret;
573 }
574 
gmx_fio_doe_string(t_fileio * fio,char * item,const char * desc,const char * srcfile,int line)575 gmx_bool gmx_fio_doe_string(t_fileio* fio, char* item, const char* desc, const char* srcfile, int line)
576 {
577     gmx_bool ret;
578     gmx_fio_lock(fio);
579     ret = do_xdr(fio, item, 1, eioSTRING, desc, srcfile, line);
580     gmx_fio_unlock(fio);
581     return ret;
582 }
583 
gmx_fio_doe_opaque(t_fileio * fio,char * data,std::size_t size,const char * desc,const char * srcfile,int line)584 gmx_bool gmx_fio_doe_opaque(t_fileio* fio, char* data, std::size_t size, const char* desc, const char* srcfile, int line)
585 {
586     gmx_bool ret;
587     gmx_fio_lock(fio);
588     ret = do_xdr(fio, data, size, eioOPAQUE, desc, srcfile, line);
589     gmx_fio_unlock(fio);
590     return ret;
591 }
592 
593 /* Array reading & writing */
594 
gmx_fio_ndoe_real(t_fileio * fio,real * item,int n,const char * desc,const char * srcfile,int line)595 gmx_bool gmx_fio_ndoe_real(t_fileio* fio, real* item, int n, const char* desc, const char* srcfile, int line)
596 {
597     gmx_bool ret = TRUE;
598     int      i;
599     gmx_fio_lock(fio);
600     for (i = 0; i < n; i++)
601     {
602         ret = ret && do_xdr(fio, &(item[i]), 1, eioREAL, desc, srcfile, line);
603     }
604     gmx_fio_unlock(fio);
605     return ret;
606 }
607 
608 
gmx_fio_ndoe_float(t_fileio * fio,float * item,int n,const char * desc,const char * srcfile,int line)609 gmx_bool gmx_fio_ndoe_float(t_fileio* fio, float* item, int n, const char* desc, const char* srcfile, int line)
610 {
611     gmx_bool ret = TRUE;
612     int      i;
613     gmx_fio_lock(fio);
614     for (i = 0; i < n; i++)
615     {
616         ret = ret && do_xdr(fio, &(item[i]), 1, eioFLOAT, desc, srcfile, line);
617     }
618     gmx_fio_unlock(fio);
619     return ret;
620 }
621 
622 
gmx_fio_ndoe_double(t_fileio * fio,double * item,int n,const char * desc,const char * srcfile,int line)623 gmx_bool gmx_fio_ndoe_double(t_fileio* fio, double* item, int n, const char* desc, const char* srcfile, int line)
624 {
625     gmx_bool ret = TRUE;
626     int      i;
627     gmx_fio_lock(fio);
628     for (i = 0; i < n; i++)
629     {
630         ret = ret && do_xdr(fio, &(item[i]), 1, eioDOUBLE, desc, srcfile, line);
631     }
632     gmx_fio_unlock(fio);
633     return ret;
634 }
635 
636 
gmx_fio_ndoe_gmx_bool(t_fileio * fio,gmx_bool * item,int n,const char * desc,const char * srcfile,int line)637 gmx_bool gmx_fio_ndoe_gmx_bool(t_fileio* fio, gmx_bool* item, int n, const char* desc, const char* srcfile, int line)
638 {
639     gmx_bool ret = TRUE;
640     int      i;
641 
642     gmx_fio_lock(fio);
643     for (i = 0; i < n; i++)
644     {
645         if (fio->bRead)
646         {
647             int itmp = 0;
648             ret      = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
649             item[i]  = (itmp != 0);
650         }
651         else
652         {
653             int itmp = static_cast<int>(item[i]);
654             ret      = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
655         }
656     }
657     gmx_fio_unlock(fio);
658     return ret;
659 }
660 
gmx_fio_ndoe_int(t_fileio * fio,int * item,int n,const char * desc,const char * srcfile,int line)661 gmx_bool gmx_fio_ndoe_int(t_fileio* fio, int* item, int n, const char* desc, const char* srcfile, int line)
662 {
663     gmx_bool ret = TRUE;
664     int      i;
665     gmx_fio_lock(fio);
666     for (i = 0; i < n; i++)
667     {
668         ret = ret && do_xdr(fio, &(item[i]), 1, eioINT, desc, srcfile, line);
669     }
670     gmx_fio_unlock(fio);
671     return ret;
672 }
673 
674 
gmx_fio_ndoe_int64(t_fileio * fio,int64_t * item,int n,const char * desc,const char * srcfile,int line)675 gmx_bool gmx_fio_ndoe_int64(t_fileio* fio, int64_t* item, int n, const char* desc, const char* srcfile, int line)
676 {
677     gmx_bool ret = TRUE;
678     int      i;
679     gmx_fio_lock(fio);
680     for (i = 0; i < n; i++)
681     {
682         ret = ret && do_xdr(fio, &(item[i]), 1, eioINT64, desc, srcfile, line);
683     }
684     gmx_fio_unlock(fio);
685     return ret;
686 }
687 
688 
gmx_fio_ndoe_uchar(t_fileio * fio,unsigned char * item,int n,const char * desc,const char * srcfile,int line)689 gmx_bool gmx_fio_ndoe_uchar(t_fileio* fio, unsigned char* item, int n, const char* desc, const char* srcfile, int line)
690 {
691     gmx_bool ret = TRUE;
692     gmx_fio_lock(fio);
693     ret = ret && do_xdr(fio, item, n, eioNUCHAR, desc, srcfile, line);
694     gmx_fio_unlock(fio);
695     return ret;
696 }
697 
gmx_fio_ndoe_char(t_fileio * fio,char * item,int n,const char * desc,const char * srcfile,int line)698 gmx_bool gmx_fio_ndoe_char(t_fileio* fio, char* item, int n, const char* desc, const char* srcfile, int line)
699 {
700     gmx_bool ret = TRUE;
701     gmx_fio_lock(fio);
702     ret = ret && do_xdr(fio, item, n, eioNCHAR, desc, srcfile, line);
703     gmx_fio_unlock(fio);
704     return ret;
705 }
706 
707 
gmx_fio_ndoe_ushort(t_fileio * fio,unsigned short * item,int n,const char * desc,const char * srcfile,int line)708 gmx_bool gmx_fio_ndoe_ushort(t_fileio* fio, unsigned short* item, int n, const char* desc, const char* srcfile, int line)
709 {
710     gmx_bool ret = TRUE;
711     int      i;
712     gmx_fio_lock(fio);
713     for (i = 0; i < n; i++)
714     {
715         ret = ret && do_xdr(fio, &(item[i]), 1, eioUSHORT, desc, srcfile, line);
716     }
717     gmx_fio_unlock(fio);
718     return ret;
719 }
720 
721 
gmx_fio_ndoe_rvec(t_fileio * fio,rvec * item,int n,const char * desc,const char * srcfile,int line)722 gmx_bool gmx_fio_ndoe_rvec(t_fileio* fio, rvec* item, int n, const char* desc, const char* srcfile, int line)
723 {
724     gmx_bool ret = TRUE;
725     gmx_fio_lock(fio);
726     ret = ret && do_xdr(fio, item, n, eioNRVEC, desc, srcfile, line);
727     gmx_fio_unlock(fio);
728     return ret;
729 }
730 
731 
gmx_fio_ndoe_ivec(t_fileio * fio,ivec * item,int n,const char * desc,const char * srcfile,int line)732 gmx_bool gmx_fio_ndoe_ivec(t_fileio* fio, ivec* item, int n, const char* desc, const char* srcfile, int line)
733 {
734     gmx_bool ret = TRUE;
735     int      i;
736     gmx_fio_lock(fio);
737     for (i = 0; i < n; i++)
738     {
739         ret = ret && do_xdr(fio, &(item[i]), 1, eioIVEC, desc, srcfile, line);
740     }
741     gmx_fio_unlock(fio);
742     return ret;
743 }
744 
745 
gmx_fio_ndoe_string(t_fileio * fio,char * item[],int n,const char * desc,const char * srcfile,int line)746 gmx_bool gmx_fio_ndoe_string(t_fileio* fio, char* item[], int n, const char* desc, const char* srcfile, int line)
747 {
748     gmx_bool ret = TRUE;
749     int      i;
750     gmx_fio_lock(fio);
751     for (i = 0; i < n; i++)
752     {
753         ret = ret && do_xdr(fio, &(item[i]), 1, eioSTRING, desc, srcfile, line);
754     }
755     gmx_fio_unlock(fio);
756     return ret;
757 }
758 
759 namespace gmx
760 {
761 
FileIOXdrSerializer(t_fileio * fio)762 FileIOXdrSerializer::FileIOXdrSerializer(t_fileio* fio) : fio_(fio)
763 {
764     GMX_RELEASE_ASSERT(fio, "Need valid file io handle");
765 }
766 
reading() const767 bool FileIOXdrSerializer::reading() const
768 {
769     return fio_->bRead;
770 }
771 
doBool(bool * value)772 void FileIOXdrSerializer::doBool(bool* value)
773 {
774     gmx_fio_do_gmx_bool(fio_, *value);
775 }
776 
doUChar(unsigned char * value)777 void FileIOXdrSerializer::doUChar(unsigned char* value)
778 {
779     gmx_fio_do_uchar(fio_, *value);
780 }
781 
doChar(char * value)782 void FileIOXdrSerializer::doChar(char* value)
783 {
784     gmx_fio_do_char(fio_, *value);
785 }
786 
doUShort(unsigned short * value)787 void FileIOXdrSerializer::doUShort(unsigned short* value)
788 {
789     gmx_fio_do_ushort(fio_, *value);
790 }
791 
doInt(int * value)792 void FileIOXdrSerializer::doInt(int* value)
793 {
794     gmx_fio_do_int(fio_, *value);
795 }
796 
doInt32(int32_t * value)797 void FileIOXdrSerializer::doInt32(int32_t* value)
798 {
799     gmx_fio_do_int32(fio_, *value);
800 }
801 
doInt64(int64_t * value)802 void FileIOXdrSerializer::doInt64(int64_t* value)
803 {
804     gmx_fio_do_int64(fio_, *value);
805 }
806 
doFloat(float * value)807 void FileIOXdrSerializer::doFloat(float* value)
808 {
809     gmx_fio_do_float(fio_, *value);
810 }
811 
doDouble(double * value)812 void FileIOXdrSerializer::doDouble(double* value)
813 {
814     gmx_fio_do_double(fio_, *value);
815 }
816 
doReal(real * value)817 void FileIOXdrSerializer::doReal(real* value)
818 {
819     gmx_fio_do_real(fio_, *value);
820 }
821 
doIvec(ivec * value)822 void FileIOXdrSerializer::doIvec(ivec* value)
823 {
824     gmx_fio_do_ivec(fio_, *value);
825 }
826 
doRvec(rvec * value)827 void FileIOXdrSerializer::doRvec(rvec* value)
828 {
829     gmx_fio_do_rvec(fio_, *value);
830 }
831 
doCharArray(char * values,int elements)832 void FileIOXdrSerializer::doCharArray(char* values, int elements)
833 {
834     gmx_fio_ndo_char(fio_, values, elements);
835 }
836 
doUCharArray(unsigned char * values,int elements)837 void FileIOXdrSerializer::doUCharArray(unsigned char* values, int elements)
838 {
839     gmx_fio_ndo_uchar(fio_, values, elements);
840 }
841 
doRvecArray(rvec * values,int elements)842 void FileIOXdrSerializer::doRvecArray(rvec* values, int elements)
843 {
844     gmx_fio_ndo_rvec(fio_, values, elements);
845 }
846 
doString(std::string * value)847 void FileIOXdrSerializer::doString(std::string* value)
848 {
849     // TODO: Use an arbitrary length buffer (but that is not supported in
850     // gmx_fio, either).
851     char buf[STRLEN];
852     if (!fio_->bRead)
853     {
854         std::strncpy(buf, value->c_str(), STRLEN);
855         buf[STRLEN - 1] = 0;
856     }
857     gmx_fio_do_string(fio_, buf);
858     if (fio_->bRead)
859     {
860         *value = buf;
861     }
862 }
863 
doOpaque(char * data,std::size_t size)864 void FileIOXdrSerializer::doOpaque(char* data, std::size_t size)
865 {
866     gmx_fio_do_opaque(fio_, data, size);
867 }
868 
869 } // namespace gmx
870