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