87a672112e572c928dd50fe7bc12418cc72a12f9
[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 <cstdio>
42 #include <cstring>
43
44 #include "gromacs/fileio/gmxfio.h"
45 #include "gromacs/fileio/xdrf.h"
46 #include "gromacs/utility/fatalerror.h"
47 #include "gromacs/utility/gmxassert.h"
48 #include "gromacs/utility/smalloc.h"
49
50 #include "gmxfio-impl.h"
51
52 /* Enumerated for data types in files */
53 enum {
54     eioREAL, eioFLOAT, eioDOUBLE, eioINT, eioINT64,
55     eioUCHAR, eioNUCHAR, eioUSHORT,
56     eioRVEC, eioNRVEC, eioIVEC, eioSTRING, eioNR
57 };
58
59 static const char *eioNames[eioNR] =
60 {
61     "REAL", "FLOAT", "DOUBLE", "INT", "INT64",
62     "UCHAR", "NUCHAR", "USHORT",
63     "RVEC", "NRVEC", "IVEC", "STRING"
64 };
65
66 void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble)
67 {
68     gmx_fio_lock(fio);
69     fio->bDouble = bDouble;
70     gmx_fio_unlock(fio);
71 }
72
73 XDR *gmx_fio_getxdr(t_fileio *fio)
74 {
75     XDR *ret = nullptr;
76     gmx_fio_lock(fio);
77     GMX_RELEASE_ASSERT( fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
78     ret = fio->xdr;
79     gmx_fio_unlock(fio);
80     return ret;
81 }
82
83 /* check the number of items given against the type */
84 static void gmx_fio_check_nitem(int eio, int nitem, const char *file, int line)
85 {
86     if ((nitem != 1) && !((eio == eioNRVEC) || (eio == eioNUCHAR)))
87     {
88         gmx_fatal(FARGS,
89                   "nitem (%d) may differ from 1 only for %s or %s, not   for %s"
90                   "(%s, %d)", nitem, eioNames[eioNUCHAR], eioNames[eioNRVEC],
91                   eioNames[eio], file, line);
92     }
93 }
94
95 /* output a data type error. */
96 [[ noreturn ]]
97 static void gmx_fio_fe(t_fileio *fio, int eio, const char *desc,
98                        const char *srcfile, int line)
99 {
100     gmx_fatal(FARGS, "Trying to %s %s type %d (%s), src %s, line %d",
101               fio->bRead ? "read" : "write", desc, eio,
102               ((eio >= 0) && (eio < eioNR)) ? eioNames[eio] : "unknown",
103               srcfile, line);
104 }
105
106 /* This is the part that reads xdr files.  */
107
108 static gmx_bool do_xdr(t_fileio *fio, void *item, int nitem, int eio,
109                        const char *desc, const char *srcfile, int line)
110 {
111     unsigned char   ucdum, *ucptr;
112     bool_t          res = 0;
113     float           fvec[DIM];
114     double          dvec[DIM];
115     int             j, m, *iptr, idum;
116     int64_t         sdum;
117     real           *ptr;
118     unsigned short  us;
119     double          d = 0;
120     float           f = 0;
121
122     GMX_RELEASE_ASSERT( fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
123     gmx_fio_check_nitem(eio, nitem, srcfile, line);
124     switch (eio)
125     {
126         case eioREAL:
127             if (fio->bDouble)
128             {
129                 if (item && !fio->bRead)
130                 {
131                     d = *(static_cast<real *>(item));
132                 }
133                 res = xdr_double(fio->xdr, &d);
134                 if (item)
135                 {
136                     *(static_cast<real *>(item)) = d;
137                 }
138             }
139             else
140             {
141                 if (item && !fio->bRead)
142                 {
143                     f = *(static_cast<real *>(item));
144                 }
145                 res = xdr_float(fio->xdr, &f);
146                 if (item)
147                 {
148                     *(static_cast<real *>(item)) = f;
149                 }
150             }
151             break;
152         case eioFLOAT:
153             if (item && !fio->bRead)
154             {
155                 f = *(static_cast<float *>(item));
156             }
157             res = xdr_float(fio->xdr, &f);
158             if (item)
159             {
160                 *(static_cast<float *>(item)) = f;
161             }
162             break;
163         case eioDOUBLE:
164             if (item && !fio->bRead)
165             {
166                 d = *(static_cast<double *>(item));
167             }
168             res = xdr_double(fio->xdr, &d);
169             if (item)
170             {
171                 *(static_cast<double *>(item)) = d;
172             }
173             break;
174         case eioINT:
175             if (item && !fio->bRead)
176             {
177                 idum = *static_cast<int *>(item);
178             }
179             res = xdr_int(fio->xdr, &idum);
180             if (item)
181             {
182                 *static_cast<int *>(item) = idum;
183             }
184             break;
185         case eioINT64:
186             if (item && !fio->bRead)
187             {
188                 sdum = *static_cast<int64_t *>(item);
189             }
190             res = xdr_int64(fio->xdr, &sdum);
191             if (item)
192             {
193                 *static_cast<int64_t *>(item) = sdum;
194             }
195             break;
196         case eioUCHAR:
197             if (item && !fio->bRead)
198             {
199                 ucdum = *static_cast<unsigned char *>(item);
200             }
201             res = xdr_u_char(fio->xdr, &ucdum);
202             if (item)
203             {
204                 *static_cast<unsigned char *>(item) = ucdum;
205             }
206             break;
207         case eioNUCHAR:
208             ucptr = static_cast<unsigned char *>(item);
209             res   = 1;
210             for (j = 0; (j < nitem) && res; j++)
211             {
212                 res = xdr_u_char(fio->xdr, &(ucptr[j]));
213             }
214             break;
215         case eioUSHORT:
216             if (item && !fio->bRead)
217             {
218                 us = *static_cast<unsigned short *>(item);
219             }
220             res = xdr_u_short(fio->xdr, &us);
221             if (item)
222             {
223                 *static_cast<unsigned short *>(item) = us;
224             }
225             break;
226         case eioRVEC:
227             if (fio->bDouble)
228             {
229                 if (item && !fio->bRead)
230                 {
231                     for (m = 0; (m < DIM); m++)
232                     {
233                         dvec[m] = (static_cast<real *>(item))[m];
234                     }
235                 }
236                 res = xdr_vector(fio->xdr, reinterpret_cast<char *>(dvec), DIM,
237                                  static_cast<unsigned int>(sizeof(double)),
238                                  reinterpret_cast<xdrproc_t>(xdr_double));
239                 if (item)
240                 {
241                     for (m = 0; (m < DIM); m++)
242                     {
243                         (static_cast<real *>(item))[m] = dvec[m];
244                     }
245                 }
246             }
247             else
248             {
249                 if (item && !fio->bRead)
250                 {
251                     for (m = 0; (m < DIM); m++)
252                     {
253                         fvec[m] = (static_cast<real *>(item))[m];
254                     }
255                 }
256                 res = xdr_vector(fio->xdr, reinterpret_cast<char *>(fvec), DIM,
257                                  static_cast<unsigned int>(sizeof(float)),
258                                  reinterpret_cast<xdrproc_t>(xdr_float));
259                 if (item)
260                 {
261                     for (m = 0; (m < DIM); m++)
262                     {
263                         (static_cast<real *>(item))[m] = fvec[m];
264                     }
265                 }
266             }
267             break;
268         case eioNRVEC:
269             ptr = nullptr;
270             res = 1;
271             for (j = 0; (j < nitem) && res; j++)
272             {
273                 if (item)
274                 {
275                     ptr = (static_cast<rvec *>(item))[j];
276                 }
277                 res = static_cast<bool_t>(do_xdr(fio, ptr, 1, eioRVEC, desc, srcfile, line));
278             }
279             break;
280         case eioIVEC:
281             iptr = static_cast<int *>(item);
282             res  = 1;
283             for (m = 0; (m < DIM) && res; m++)
284             {
285                 if (item && !fio->bRead)
286                 {
287                     idum = iptr[m];
288                 }
289                 res = xdr_int(fio->xdr, &idum);
290                 if (item)
291                 {
292                     iptr[m] = idum;
293                 }
294             }
295             break;
296         case eioSTRING:
297         {
298             char *cptr;
299             int   slen;
300
301             if (item)
302             {
303                 if (!fio->bRead)
304                 {
305                     slen = strlen(static_cast<char *>(item)) + 1;
306                 }
307                 else
308                 {
309                     slen = 0;
310                 }
311             }
312             else
313             {
314                 slen = 0;
315             }
316
317             if (xdr_int(fio->xdr, &slen) <= 0)
318             {
319                 gmx_fatal(FARGS, "wrong string length %d for string %s"
320                           " (source %s, line %d)", slen, desc, srcfile, line);
321             }
322             if (!item && fio->bRead)
323             {
324                 snew(cptr, slen);
325             }
326             else
327             {
328                 cptr = static_cast<char *>(item);
329             }
330             if (cptr)
331             {
332                 res = xdr_string(fio->xdr, &cptr, slen);
333             }
334             else
335             {
336                 res = 1;
337             }
338             if (!item && fio->bRead)
339             {
340                 sfree(cptr);
341             }
342             break;
343         }
344         default:
345             gmx_fio_fe(fio, eio, desc, srcfile, line);
346     }
347
348     return (res != 0);
349 }
350
351 /*******************************************************************
352  *
353  * READ/WRITE FUNCTIONS
354  *
355  *******************************************************************/
356
357 gmx_bool gmx_fio_writee_string(t_fileio *fio, const char *item,
358                                const char *desc, const char *srcfile, int line)
359 {
360     gmx_bool ret;
361     void    *it = const_cast<char*>(item); /* ugh.. */
362     gmx_fio_lock(fio);
363     ret = do_xdr(fio, it, 1, eioSTRING, desc, srcfile, line);
364     gmx_fio_unlock(fio);
365     return ret;
366 }
367
368 gmx_bool gmx_fio_doe_real(t_fileio *fio, real *item,
369                           const char *desc, const char *srcfile, int line)
370 {
371     gmx_bool ret;
372     gmx_fio_lock(fio);
373     ret = do_xdr(fio, item, 1, eioREAL, desc, srcfile, line);
374     gmx_fio_unlock(fio);
375     return ret;
376
377 }
378
379 gmx_bool gmx_fio_doe_float(t_fileio *fio, float *item,
380                            const char *desc, const char *srcfile, int line)
381 {
382     gmx_bool ret;
383     gmx_fio_lock(fio);
384     ret = do_xdr(fio, item, 1, eioFLOAT, desc, srcfile, line);
385     gmx_fio_unlock(fio);
386     return ret;
387 }
388
389 gmx_bool gmx_fio_doe_double(t_fileio *fio, double *item,
390                             const char *desc, const char *srcfile, int line)
391 {
392     gmx_bool ret;
393     gmx_fio_lock(fio);
394     ret = do_xdr(fio, item, 1, eioDOUBLE, desc, srcfile, line);
395     gmx_fio_unlock(fio);
396     return ret;
397 }
398
399
400 gmx_bool gmx_fio_doe_gmx_bool(t_fileio *fio, gmx_bool *item,
401                               const char *desc, const char *srcfile, int line)
402 {
403     gmx_bool ret;
404
405     gmx_fio_lock(fio);
406     if (fio->bRead)
407     {
408         int itmp = 0;
409         ret      = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
410         *item    = (itmp != 0);
411     }
412     else
413     {
414         int itmp = static_cast<int>(*item);
415         ret      = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
416     }
417     gmx_fio_unlock(fio);
418     return ret;
419 }
420
421 gmx_bool gmx_fio_doe_int(t_fileio *fio, int *item,
422                          const char *desc, const char *srcfile, int line)
423 {
424     gmx_bool ret;
425     gmx_fio_lock(fio);
426     ret = do_xdr(fio, item, 1, eioINT, desc, srcfile, line);
427     gmx_fio_unlock(fio);
428     return ret;
429 }
430
431 gmx_bool gmx_fio_doe_int64(t_fileio *fio, int64_t *item,
432                            const char *desc, const char *srcfile, int line)
433 {
434     gmx_bool ret;
435     gmx_fio_lock(fio);
436     ret = do_xdr(fio, item, 1, eioINT64, desc, srcfile, line);
437     gmx_fio_unlock(fio);
438     return ret;
439 }
440
441 gmx_bool gmx_fio_doe_uchar(t_fileio *fio, unsigned char *item,
442                            const char *desc, const char *srcfile, int line)
443 {
444     gmx_bool ret;
445     gmx_fio_lock(fio);
446     ret = do_xdr(fio, item, 1, eioUCHAR, desc, srcfile, line);
447     gmx_fio_unlock(fio);
448     return ret;
449 }
450
451 gmx_bool gmx_fio_doe_ushort(t_fileio *fio, unsigned short *item,
452                             const char *desc, const char *srcfile, int line)
453 {
454     gmx_bool ret;
455     gmx_fio_lock(fio);
456     ret = do_xdr(fio, item, 1, eioUSHORT, desc, srcfile, line);
457     gmx_fio_unlock(fio);
458     return ret;
459 }
460
461 gmx_bool gmx_fio_doe_rvec(t_fileio *fio, rvec *item,
462                           const char *desc, const char *srcfile, int line)
463 {
464     gmx_bool ret;
465     gmx_fio_lock(fio);
466     ret = do_xdr(fio, item, 1, eioRVEC, desc, srcfile, line);
467     gmx_fio_unlock(fio);
468     return ret;
469 }
470
471 gmx_bool gmx_fio_doe_ivec(t_fileio *fio, ivec *item,
472                           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, eioIVEC, desc, srcfile, line);
477     gmx_fio_unlock(fio);
478     return ret;
479 }
480
481 gmx_bool gmx_fio_doe_string(t_fileio *fio, char *item,
482                             const char *desc, const char *srcfile, int line)
483 {
484     gmx_bool ret;
485     gmx_fio_lock(fio);
486     ret = do_xdr(fio, item, 1, eioSTRING, desc, srcfile, line);
487     gmx_fio_unlock(fio);
488     return ret;
489 }
490
491
492 /* Array reading & writing */
493
494 gmx_bool gmx_fio_ndoe_real(t_fileio *fio, real *item, int n,
495                            const char *desc, const char *srcfile, int line)
496 {
497     gmx_bool ret = TRUE;
498     int      i;
499     gmx_fio_lock(fio);
500     for (i = 0; i < n; i++)
501     {
502         ret = ret && do_xdr(fio, &(item[i]), 1, eioREAL, desc,
503                             srcfile, line);
504     }
505     gmx_fio_unlock(fio);
506     return ret;
507 }
508
509
510
511 gmx_bool gmx_fio_ndoe_float(t_fileio *fio, float *item, int n,
512                             const char *desc, const char *srcfile, int line)
513 {
514     gmx_bool ret = TRUE;
515     int      i;
516     gmx_fio_lock(fio);
517     for (i = 0; i < n; i++)
518     {
519         ret = ret && do_xdr(fio, &(item[i]), 1, eioFLOAT, desc,
520                             srcfile, line);
521     }
522     gmx_fio_unlock(fio);
523     return ret;
524 }
525
526
527
528 gmx_bool gmx_fio_ndoe_double(t_fileio *fio, double *item, int n,
529                              const char *desc, const char *srcfile, int line)
530 {
531     gmx_bool ret = TRUE;
532     int      i;
533     gmx_fio_lock(fio);
534     for (i = 0; i < n; i++)
535     {
536         ret = ret && do_xdr(fio, &(item[i]), 1, eioDOUBLE, desc,
537                             srcfile, line);
538     }
539     gmx_fio_unlock(fio);
540     return ret;
541 }
542
543
544
545 gmx_bool gmx_fio_ndoe_gmx_bool(t_fileio *fio, gmx_bool *item, int n,
546                                const char *desc, const char *srcfile, int line)
547 {
548     gmx_bool ret = TRUE;
549     int      i;
550
551     gmx_fio_lock(fio);
552     for (i = 0; i < n; i++)
553     {
554         if (fio->bRead)
555         {
556             int itmp = 0;
557             ret      = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
558             item[i]  = (itmp != 0);
559         }
560         else
561         {
562             int itmp = static_cast<int>(item[i]);
563             ret      = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
564         }
565     }
566     gmx_fio_unlock(fio);
567     return ret;
568 }
569
570 gmx_bool gmx_fio_ndoe_int(t_fileio *fio, int *item, int n,
571                           const char *desc, const char *srcfile, int line)
572 {
573     gmx_bool ret = TRUE;
574     int      i;
575     gmx_fio_lock(fio);
576     for (i = 0; i < n; i++)
577     {
578         ret = ret && do_xdr(fio, &(item[i]), 1, eioINT, desc,
579                             srcfile, line);
580     }
581     gmx_fio_unlock(fio);
582     return ret;
583 }
584
585
586
587 gmx_bool gmx_fio_ndoe_int64(t_fileio *fio, int64_t *item, int n,
588                             const char *desc, const char *srcfile, int line)
589 {
590     gmx_bool ret = TRUE;
591     int      i;
592     gmx_fio_lock(fio);
593     for (i = 0; i < n; i++)
594     {
595         ret = ret && do_xdr(fio, &(item[i]), 1, eioINT64, desc,
596                             srcfile, line);
597     }
598     gmx_fio_unlock(fio);
599     return ret;
600 }
601
602
603
604 gmx_bool gmx_fio_ndoe_uchar(t_fileio *fio, unsigned char *item, int n,
605                             const char *desc, const char *srcfile, int line)
606 {
607     gmx_bool ret = TRUE;
608     gmx_fio_lock(fio);
609     ret = ret && do_xdr(fio, item, n, eioNUCHAR, desc,
610                         srcfile, line);
611     gmx_fio_unlock(fio);
612     return ret;
613 }
614
615
616
617 gmx_bool gmx_fio_ndoe_ushort(t_fileio *fio, unsigned short *item, int n,
618                              const char *desc, const char *srcfile, int line)
619 {
620     gmx_bool ret = TRUE;
621     int      i;
622     gmx_fio_lock(fio);
623     for (i = 0; i < n; i++)
624     {
625         ret = ret && do_xdr(fio, &(item[i]), 1, eioUSHORT, desc,
626                             srcfile, line);
627     }
628     gmx_fio_unlock(fio);
629     return ret;
630 }
631
632
633
634 gmx_bool gmx_fio_ndoe_rvec(t_fileio *fio, rvec *item, int n,
635                            const char *desc, const char *srcfile, int line)
636 {
637     gmx_bool ret = TRUE;
638     gmx_fio_lock(fio);
639     ret = ret && do_xdr(fio, item, n, eioNRVEC, desc, srcfile, line);
640     gmx_fio_unlock(fio);
641     return ret;
642 }
643
644
645
646 gmx_bool gmx_fio_ndoe_ivec(t_fileio *fio, ivec *item, int n,
647                            const char *desc, const char *srcfile, int line)
648 {
649     gmx_bool ret = TRUE;
650     int      i;
651     gmx_fio_lock(fio);
652     for (i = 0; i < n; i++)
653     {
654         ret = ret && do_xdr(fio, &(item[i]), 1, eioIVEC, desc,
655                             srcfile, line);
656     }
657     gmx_fio_unlock(fio);
658     return ret;
659 }
660
661
662
663 gmx_bool gmx_fio_ndoe_string(t_fileio *fio, char *item[], int n,
664                              const char *desc, const char *srcfile, int line)
665 {
666     gmx_bool ret = TRUE;
667     int      i;
668     gmx_fio_lock(fio);
669     for (i = 0; i < n; i++)
670     {
671         ret = ret && do_xdr(fio, &(item[i]), 1, eioSTRING, desc,
672                             srcfile, line);
673     }
674     gmx_fio_unlock(fio);
675     return ret;
676 }
677
678 namespace gmx
679 {
680
681 bool FileIOXdrSerializer::reading() const
682 {
683     return fio_->bRead;
684 }
685
686 void FileIOXdrSerializer::doBool(bool *value)
687 {
688     gmx_bool v = *value;
689     gmx_fio_do_gmx_bool(fio_, v);
690     *value = v;
691 }
692
693 void FileIOXdrSerializer::doUChar(unsigned char *value)
694 {
695     gmx_fio_do_uchar(fio_, *value);
696 }
697
698 void FileIOXdrSerializer::doInt(int *value)
699 {
700     gmx_fio_do_int(fio_, *value);
701 }
702
703 void FileIOXdrSerializer::doInt64(int64_t *value)
704 {
705     gmx_fio_do_int64(fio_, *value);
706 }
707
708 void FileIOXdrSerializer::doFloat(float *value)
709 {
710     gmx_fio_do_float(fio_, *value);
711 }
712
713 void FileIOXdrSerializer::doDouble(double *value)
714 {
715     gmx_fio_do_double(fio_, *value);
716 }
717
718 void FileIOXdrSerializer::doString(std::string *value)
719 {
720     // TODO: Use an arbitrary length buffer (but that is not supported in
721     // gmx_fio, either).
722     char buf[STRLEN];
723     if (!fio_->bRead)
724     {
725         std::strncpy(buf, value->c_str(), STRLEN);
726         buf[STRLEN-1] = 0;
727     }
728     gmx_fio_do_string(fio_, buf);
729     if (fio_->bRead)
730     {
731         *value = buf;
732     }
733 }
734
735 } // namespace gmx