2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
40 #include "gmxfio_xdr.h"
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"
54 #include "gmxfio_impl.h"
56 /* Enumerated for data types in files */
78 static const char* eioNames[eioNR] = { "REAL", "FLOAT", "DOUBLE", "INT", "INT32", "INT64",
79 "UCHAR", "CHAR", "NCHAR", "NUCHAR", "USHORT", "RVEC",
80 "NRVEC", "IVEC", "STRING", "OPAQUE" };
82 void gmx_fio_setprecision(t_fileio* fio, gmx_bool bDouble)
85 fio->bDouble = bDouble;
89 bool gmx_fio_is_double(t_fileio* fio)
91 bool isDouble = false;
93 isDouble = fio->bDouble;
98 XDR* gmx_fio_getxdr(t_fileio* fio)
102 GMX_RELEASE_ASSERT(fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
108 /* check the number of items given against the type */
109 static void gmx_fio_check_nitem(int eio, std::size_t nitem, const char* file, int line)
112 && !((eio == eioNRVEC) || (eio == eioNUCHAR) || (eio == eioNCHAR) || (eio == eioOPAQUE)))
115 "nitem may differ from 1 only for %s, %s, %s or %s, not for %s"
117 eioNames[eioNUCHAR], eioNames[eioNRVEC], eioNames[eioNCHAR], eioNames[eioOPAQUE],
118 eioNames[eio], file, line);
122 /* output a data type error. */
123 [[noreturn]] static void gmx_fio_fe(t_fileio* fio, int eio, const char* desc, const char* srcfile, int line)
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);
129 /* This is the part that reads xdr files. */
132 do_xdr(t_fileio* fio, void* item, std::size_t nitem, int eio, const char* desc, const char* srcfile, int line)
134 unsigned char ucdum, *ucptr;
147 GMX_RELEASE_ASSERT(fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
148 gmx_fio_check_nitem(eio, nitem, srcfile, line);
154 if (item && !fio->bRead)
156 d = *(static_cast<real*>(item));
158 res = xdr_double(fio->xdr, &d);
161 *(static_cast<real*>(item)) = d;
166 if (item && !fio->bRead)
168 f = *(static_cast<real*>(item));
170 res = xdr_float(fio->xdr, &f);
173 *(static_cast<real*>(item)) = f;
178 if (item && !fio->bRead)
180 f = *(static_cast<float*>(item));
182 res = xdr_float(fio->xdr, &f);
185 *(static_cast<float*>(item)) = f;
189 if (item && !fio->bRead)
191 d = *(static_cast<double*>(item));
193 res = xdr_double(fio->xdr, &d);
196 *(static_cast<double*>(item)) = d;
200 if (item && !fio->bRead)
202 idum = *static_cast<int*>(item);
204 res = xdr_int(fio->xdr, &idum);
207 *static_cast<int*>(item) = idum;
211 if (item && !fio->bRead)
213 s32dum = *static_cast<int32_t*>(item);
215 res = xdr_int32(fio->xdr, &s32dum);
218 *static_cast<int32_t*>(item) = s32dum;
222 if (item && !fio->bRead)
224 s64dum = *static_cast<int64_t*>(item);
226 res = xdr_int64(fio->xdr, &s64dum);
229 *static_cast<int64_t*>(item) = s64dum;
233 if (item && !fio->bRead)
235 ucdum = *static_cast<unsigned char*>(item);
237 res = xdr_u_char(fio->xdr, &ucdum);
240 *static_cast<unsigned char*>(item) = ucdum;
244 if (item && !fio->bRead)
246 cdum = *static_cast<char*>(item);
248 res = xdr_char(fio->xdr, &cdum);
251 *static_cast<char*>(item) = cdum;
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));
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));
271 if (item && !fio->bRead)
273 us = *static_cast<unsigned short*>(item);
275 res = xdr_u_short(fio->xdr, &us);
278 *static_cast<unsigned short*>(item) = us;
284 if (item && !fio->bRead)
286 for (m = 0; (m < DIM); m++)
288 dvec[m] = (static_cast<real*>(item))[m];
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));
296 for (m = 0; (m < DIM); m++)
298 (static_cast<real*>(item))[m] = dvec[m];
304 if (item && !fio->bRead)
306 for (m = 0; (m < DIM); m++)
308 fvec[m] = (static_cast<real*>(item))[m];
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));
316 for (m = 0; (m < DIM); m++)
318 (static_cast<real*>(item))[m] = fvec[m];
326 for (std::size_t j = 0; j < nitem && res; j++)
330 ptr = (static_cast<rvec*>(item))[j];
332 res = static_cast<bool_t>(do_xdr(fio, ptr, 1, eioRVEC, desc, srcfile, line));
336 iptr = static_cast<int*>(item);
338 for (m = 0; (m < DIM) && res; m++)
340 if (item && !fio->bRead)
344 res = xdr_int(fio->xdr, &idum);
360 slen = strlen(static_cast<char*>(item)) + 1;
372 if (xdr_int(fio->xdr, &slen) <= 0)
375 "wrong string length %d for string %s"
376 " (source %s, line %d)",
377 slen, desc, srcfile, line);
379 if (!item && fio->bRead)
385 cptr = static_cast<char*>(item);
389 res = xdr_string(fio->xdr, &cptr, slen);
395 if (!item && fio->bRead)
403 if (item == nullptr && nitem > 0)
405 gmx_fatal(FARGS, "Null pointer provided for non-zero length XDR opaque data.");
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;
420 for (res = 1; res > 0 && nitem > 0;)
422 std::size_t thisChunk = std::min(maxChunk, nitem);
423 res = xdr_opaque(fio->xdr, reinterpret_cast<char*>(item), thisChunk);
433 default: gmx_fio_fe(fio, eio, desc, srcfile, line);
439 /*******************************************************************
441 * READ/WRITE FUNCTIONS
443 *******************************************************************/
445 gmx_bool gmx_fio_writee_string(t_fileio* fio, const char* item, const char* desc, const char* srcfile, int line)
448 void* it = const_cast<char*>(item); /* ugh.. */
450 ret = do_xdr(fio, it, 1, eioSTRING, desc, srcfile, line);
455 gmx_bool gmx_fio_doe_real(t_fileio* fio, real* item, const char* desc, const char* srcfile, int line)
459 ret = do_xdr(fio, item, 1, eioREAL, desc, srcfile, line);
464 gmx_bool gmx_fio_doe_float(t_fileio* fio, float* item, const char* desc, const char* srcfile, int line)
468 ret = do_xdr(fio, item, 1, eioFLOAT, desc, srcfile, line);
473 gmx_bool gmx_fio_doe_double(t_fileio* fio, double* item, const char* desc, const char* srcfile, int line)
477 ret = do_xdr(fio, item, 1, eioDOUBLE, desc, srcfile, line);
483 gmx_bool gmx_fio_doe_gmx_bool(t_fileio* fio, gmx_bool* item, const char* desc, const char* srcfile, int line)
491 ret = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
496 int itmp = static_cast<int>(*item);
497 ret = do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
503 gmx_bool gmx_fio_doe_int(t_fileio* fio, int* item, const char* desc, const char* srcfile, int line)
507 ret = do_xdr(fio, item, 1, eioINT, desc, srcfile, line);
512 gmx_bool gmx_fio_doe_int32(t_fileio* fio, int32_t* item, const char* desc, const char* srcfile, int line)
516 ret = do_xdr(fio, item, 1, eioINT32, desc, srcfile, line);
521 gmx_bool gmx_fio_doe_int64(t_fileio* fio, int64_t* item, const char* desc, const char* srcfile, int line)
525 ret = do_xdr(fio, item, 1, eioINT64, desc, srcfile, line);
530 gmx_bool gmx_fio_doe_uchar(t_fileio* fio, unsigned char* item, const char* desc, const char* srcfile, int line)
534 ret = do_xdr(fio, item, 1, eioUCHAR, desc, srcfile, line);
539 gmx_bool gmx_fio_doe_char(t_fileio* fio, char* item, const char* desc, const char* srcfile, int line)
543 ret = do_xdr(fio, item, 1, eioCHAR, desc, srcfile, line);
548 gmx_bool gmx_fio_doe_ushort(t_fileio* fio, unsigned short* item, const char* desc, const char* srcfile, int line)
552 ret = do_xdr(fio, item, 1, eioUSHORT, desc, srcfile, line);
557 gmx_bool gmx_fio_doe_rvec(t_fileio* fio, rvec* item, const char* desc, const char* srcfile, int line)
561 ret = do_xdr(fio, item, 1, eioRVEC, desc, srcfile, line);
566 gmx_bool gmx_fio_doe_ivec(t_fileio* fio, ivec* item, const char* desc, const char* srcfile, int line)
570 ret = do_xdr(fio, item, 1, eioIVEC, desc, srcfile, line);
575 gmx_bool gmx_fio_doe_string(t_fileio* fio, char* item, const char* desc, const char* srcfile, int line)
579 ret = do_xdr(fio, item, 1, eioSTRING, desc, srcfile, 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)
588 ret = do_xdr(fio, data, size, eioOPAQUE, desc, srcfile, line);
593 /* Array reading & writing */
595 gmx_bool gmx_fio_ndoe_real(t_fileio* fio, real* item, int n, const char* desc, const char* srcfile, int line)
600 for (i = 0; i < n; i++)
602 ret = ret && do_xdr(fio, &(item[i]), 1, eioREAL, desc, srcfile, line);
609 gmx_bool gmx_fio_ndoe_float(t_fileio* fio, float* item, int n, const char* desc, const char* srcfile, int line)
614 for (i = 0; i < n; i++)
616 ret = ret && do_xdr(fio, &(item[i]), 1, eioFLOAT, desc, srcfile, line);
623 gmx_bool gmx_fio_ndoe_double(t_fileio* fio, double* item, int n, const char* desc, const char* srcfile, int line)
628 for (i = 0; i < n; i++)
630 ret = ret && do_xdr(fio, &(item[i]), 1, eioDOUBLE, desc, srcfile, 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)
643 for (i = 0; i < n; i++)
648 ret = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
649 item[i] = (itmp != 0);
653 int itmp = static_cast<int>(item[i]);
654 ret = ret && do_xdr(fio, &itmp, 1, eioINT, desc, srcfile, line);
661 gmx_bool gmx_fio_ndoe_int(t_fileio* fio, int* item, int n, const char* desc, const char* srcfile, int line)
666 for (i = 0; i < n; i++)
668 ret = ret && do_xdr(fio, &(item[i]), 1, eioINT, desc, srcfile, line);
675 gmx_bool gmx_fio_ndoe_int64(t_fileio* fio, int64_t* item, int n, const char* desc, const char* srcfile, int line)
680 for (i = 0; i < n; i++)
682 ret = ret && do_xdr(fio, &(item[i]), 1, eioINT64, desc, srcfile, line);
689 gmx_bool gmx_fio_ndoe_uchar(t_fileio* fio, unsigned char* item, int n, const char* desc, const char* srcfile, int line)
693 ret = ret && do_xdr(fio, item, n, eioNUCHAR, desc, srcfile, line);
698 gmx_bool gmx_fio_ndoe_char(t_fileio* fio, char* item, int n, const char* desc, const char* srcfile, int line)
702 ret = ret && do_xdr(fio, item, n, eioNCHAR, desc, srcfile, line);
708 gmx_bool gmx_fio_ndoe_ushort(t_fileio* fio, unsigned short* item, int n, const char* desc, const char* srcfile, int line)
713 for (i = 0; i < n; i++)
715 ret = ret && do_xdr(fio, &(item[i]), 1, eioUSHORT, desc, srcfile, line);
722 gmx_bool gmx_fio_ndoe_rvec(t_fileio* fio, rvec* item, int n, const char* desc, const char* srcfile, int line)
726 ret = ret && do_xdr(fio, item, n, eioNRVEC, desc, srcfile, line);
732 gmx_bool gmx_fio_ndoe_ivec(t_fileio* fio, ivec* item, int n, const char* desc, const char* srcfile, int line)
737 for (i = 0; i < n; i++)
739 ret = ret && do_xdr(fio, &(item[i]), 1, eioIVEC, desc, srcfile, line);
746 gmx_bool gmx_fio_ndoe_string(t_fileio* fio, char* item[], int n, const char* desc, const char* srcfile, int line)
751 for (i = 0; i < n; i++)
753 ret = ret && do_xdr(fio, &(item[i]), 1, eioSTRING, desc, srcfile, line);
762 FileIOXdrSerializer::FileIOXdrSerializer(t_fileio* fio) : fio_(fio)
764 GMX_RELEASE_ASSERT(fio, "Need valid file io handle");
767 bool FileIOXdrSerializer::reading() const
772 void FileIOXdrSerializer::doBool(bool* value)
774 gmx_fio_do_gmx_bool(fio_, *value);
777 void FileIOXdrSerializer::doUChar(unsigned char* value)
779 gmx_fio_do_uchar(fio_, *value);
782 void FileIOXdrSerializer::doChar(char* value)
784 gmx_fio_do_char(fio_, *value);
787 void FileIOXdrSerializer::doUShort(unsigned short* value)
789 gmx_fio_do_ushort(fio_, *value);
792 void FileIOXdrSerializer::doInt(int* value)
794 gmx_fio_do_int(fio_, *value);
797 void FileIOXdrSerializer::doInt32(int32_t* value)
799 gmx_fio_do_int32(fio_, *value);
802 void FileIOXdrSerializer::doInt64(int64_t* value)
804 gmx_fio_do_int64(fio_, *value);
807 void FileIOXdrSerializer::doFloat(float* value)
809 gmx_fio_do_float(fio_, *value);
812 void FileIOXdrSerializer::doDouble(double* value)
814 gmx_fio_do_double(fio_, *value);
817 void FileIOXdrSerializer::doReal(real* value)
819 gmx_fio_do_real(fio_, *value);
822 void FileIOXdrSerializer::doIvec(ivec* value)
824 gmx_fio_do_ivec(fio_, *value);
827 void FileIOXdrSerializer::doRvec(rvec* value)
829 gmx_fio_do_rvec(fio_, *value);
832 void FileIOXdrSerializer::doCharArray(char* values, int elements)
834 gmx_fio_ndo_char(fio_, values, elements);
837 void FileIOXdrSerializer::doUCharArray(unsigned char* values, int elements)
839 gmx_fio_ndo_uchar(fio_, values, elements);
842 void FileIOXdrSerializer::doRvecArray(rvec* values, int elements)
844 gmx_fio_ndo_rvec(fio_, values, elements);
847 void FileIOXdrSerializer::doString(std::string* value)
849 // TODO: Use an arbitrary length buffer (but that is not supported in
854 std::strncpy(buf, value->c_str(), STRLEN);
857 gmx_fio_do_string(fio_, buf);
864 void FileIOXdrSerializer::doOpaque(char* data, std::size_t size)
866 gmx_fio_do_opaque(fio_, data, size);