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,2021, 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/enumerationhelpers.h"
51 #include "gromacs/utility/fatalerror.h"
52 #include "gromacs/utility/gmxassert.h"
53 #include "gromacs/utility/smalloc.h"
55 #include "gmxfio_impl.h"
57 /* Enumerated for data types in files */
58 enum class InputOutputType : int
79 static const char* enumValueToString(InputOutputType enumValue)
81 constexpr gmx::EnumerationArray<InputOutputType, const char*> ioTypeNames = {
82 "REAL", "FLOAT", "DOUBLE", "INT", "INT32", "INT64", "UCHAR", "CHAR",
83 "NCHAR", "NUCHAR", "USHORT", "RVEC", "NRVEC", "IVEC", "STRING", "OPAQUE"
85 return ioTypeNames[enumValue];
88 void gmx_fio_setprecision(t_fileio* fio, gmx_bool bDouble)
91 fio->bDouble = bDouble;
95 bool gmx_fio_is_double(t_fileio* fio)
97 bool isDouble = false;
99 isDouble = fio->bDouble;
104 XDR* gmx_fio_getxdr(t_fileio* fio)
108 GMX_RELEASE_ASSERT(fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
114 /* check the number of items given against the type */
115 static void gmx_fio_check_nitem(InputOutputType eio, std::size_t nitem, const char* file, int line)
118 && !((eio == InputOutputType::RVecArray) || (eio == InputOutputType::UnsignedCharArray)
119 || (eio == InputOutputType::CharArray) || (eio == InputOutputType::Opaque)))
122 "nitem may differ from 1 only for %s, %s, %s or %s, not for %s"
124 enumValueToString(InputOutputType::UnsignedCharArray),
125 enumValueToString(InputOutputType::RVecArray),
126 enumValueToString(InputOutputType::CharArray),
127 enumValueToString(InputOutputType::Opaque),
128 enumValueToString(eio),
134 /* output a data type error. */
135 [[noreturn]] static void
136 gmx_fio_fe(t_fileio* fio, InputOutputType eio, const char* desc, const char* srcfile, int line)
139 "Trying to %s %s type %d (%s), src %s, line %d",
140 fio->bRead ? "read" : "write",
142 static_cast<int>(eio),
143 ((eio >= InputOutputType::Real) && (eio < InputOutputType::Count)) ? enumValueToString(eio)
149 /* This is the part that reads xdr files. */
150 static gmx_bool do_xdr(t_fileio* fio,
158 unsigned char ucdum, *ucptr;
171 GMX_RELEASE_ASSERT(fio->xdr != nullptr, "Implementation error: NULL XDR pointers");
172 gmx_fio_check_nitem(eio, nitem, srcfile, line);
175 case InputOutputType::Real:
178 if (item && !fio->bRead)
180 d = *(static_cast<real*>(item));
182 res = xdr_double(fio->xdr, &d);
185 *(static_cast<real*>(item)) = d;
190 if (item && !fio->bRead)
192 f = *(static_cast<real*>(item));
194 res = xdr_float(fio->xdr, &f);
197 *(static_cast<real*>(item)) = f;
201 case InputOutputType::Float:
202 if (item && !fio->bRead)
204 f = *(static_cast<float*>(item));
206 res = xdr_float(fio->xdr, &f);
209 *(static_cast<float*>(item)) = f;
212 case InputOutputType::Double:
213 if (item && !fio->bRead)
215 d = *(static_cast<double*>(item));
217 res = xdr_double(fio->xdr, &d);
220 *(static_cast<double*>(item)) = d;
223 case InputOutputType::Int:
224 if (item && !fio->bRead)
226 idum = *static_cast<int*>(item);
228 res = xdr_int(fio->xdr, &idum);
231 *static_cast<int*>(item) = idum;
234 case InputOutputType::Int32:
235 if (item && !fio->bRead)
237 s32dum = *static_cast<int32_t*>(item);
239 res = xdr_int32(fio->xdr, &s32dum);
242 *static_cast<int32_t*>(item) = s32dum;
245 case InputOutputType::Int64:
246 if (item && !fio->bRead)
248 s64dum = *static_cast<int64_t*>(item);
250 res = xdr_int64(fio->xdr, &s64dum);
253 *static_cast<int64_t*>(item) = s64dum;
256 case InputOutputType::UnsignedChar:
257 if (item && !fio->bRead)
259 ucdum = *static_cast<unsigned char*>(item);
261 res = xdr_u_char(fio->xdr, &ucdum);
264 *static_cast<unsigned char*>(item) = ucdum;
267 case InputOutputType::Char:
268 if (item && !fio->bRead)
270 cdum = *static_cast<char*>(item);
272 res = xdr_char(fio->xdr, &cdum);
275 *static_cast<char*>(item) = cdum;
278 case InputOutputType::CharArray:
279 cptr = static_cast<char*>(item);
280 GMX_RELEASE_ASSERT(nitem < static_cast<std::size_t>(std::numeric_limits<int>::max()),
281 "The XDR interface cannot handle array lengths > 2^31");
282 res = xdr_vector(fio->xdr,
284 static_cast<int>(nitem),
285 static_cast<unsigned int>(sizeof(char)),
286 reinterpret_cast<xdrproc_t>(xdr_char));
288 case InputOutputType::UnsignedCharArray:
289 ucptr = static_cast<unsigned char*>(item);
290 GMX_RELEASE_ASSERT(nitem < static_cast<std::size_t>(std::numeric_limits<int>::max()),
291 "The XDR interface cannot handle array lengths > 2^31");
292 res = xdr_vector(fio->xdr,
293 reinterpret_cast<char*>(ucptr),
294 static_cast<int>(nitem),
295 static_cast<unsigned int>(sizeof(unsigned char)),
296 reinterpret_cast<xdrproc_t>(xdr_u_char));
298 case InputOutputType::UnsignedShort:
299 if (item && !fio->bRead)
301 us = *static_cast<unsigned short*>(item);
303 res = xdr_u_short(fio->xdr, &us);
306 *static_cast<unsigned short*>(item) = us;
309 case InputOutputType::RVec:
312 if (item && !fio->bRead)
314 for (m = 0; (m < DIM); m++)
316 dvec[m] = (static_cast<real*>(item))[m];
319 res = xdr_vector(fio->xdr,
320 reinterpret_cast<char*>(dvec),
322 static_cast<unsigned int>(sizeof(double)),
323 reinterpret_cast<xdrproc_t>(xdr_double));
326 for (m = 0; (m < DIM); m++)
328 (static_cast<real*>(item))[m] = dvec[m];
334 if (item && !fio->bRead)
336 for (m = 0; (m < DIM); m++)
338 fvec[m] = (static_cast<real*>(item))[m];
341 res = xdr_vector(fio->xdr,
342 reinterpret_cast<char*>(fvec),
344 static_cast<unsigned int>(sizeof(float)),
345 reinterpret_cast<xdrproc_t>(xdr_float));
348 for (m = 0; (m < DIM); m++)
350 (static_cast<real*>(item))[m] = fvec[m];
355 case InputOutputType::RVecArray:
358 for (std::size_t j = 0; j < nitem && res; j++)
362 ptr = (static_cast<rvec*>(item))[j];
364 res = static_cast<bool_t>(do_xdr(fio, ptr, 1, InputOutputType::RVec, desc, srcfile, line));
367 case InputOutputType::IVec:
368 iptr = static_cast<int*>(item);
370 for (m = 0; (m < DIM) && res; m++)
372 if (item && !fio->bRead)
376 res = xdr_int(fio->xdr, &idum);
383 case InputOutputType::String:
392 slen = strlen(static_cast<char*>(item)) + 1;
404 if (xdr_int(fio->xdr, &slen) <= 0)
407 "wrong string length %d for string %s"
408 " (source %s, line %d)",
414 if (!item && fio->bRead)
420 cptr = static_cast<char*>(item);
424 res = xdr_string(fio->xdr, &cptr, slen);
430 if (!item && fio->bRead)
436 case InputOutputType::Opaque:
438 if (item == nullptr && nitem > 0)
440 gmx_fatal(FARGS, "Null pointer provided for non-zero length XDR opaque data.");
445 // We need to support very large opaque data objects although the default
446 // XDR interface only uses integers for the size field, since gromacs-2020
447 // e.g. embeds the entire TPR body as a single such object, which would break all
448 // TPR files larger than 2GB unless we handle it as a special case.
449 // To avoid inserting extra padding, we calculate the chunk size as:
450 // - The max value of a signed integer + 1
451 // - Subtract 4 (the XDR object size) to get a size within the range of the signed int.
452 const std::size_t maxChunk =
453 static_cast<std::size_t>(std::numeric_limits<int>::max()) + 1 - 4;
455 for (res = 1; res > 0 && nitem > 0;)
457 std::size_t thisChunk = std::min(maxChunk, nitem);
458 res = xdr_opaque(fio->xdr, reinterpret_cast<char*>(item), thisChunk);
468 default: gmx_fio_fe(fio, eio, desc, srcfile, line);
474 /*******************************************************************
476 * READ/WRITE FUNCTIONS
478 *******************************************************************/
480 gmx_bool gmx_fio_writee_string(t_fileio* fio, const char* item, const char* desc, const char* srcfile, int line)
483 void* it = const_cast<char*>(item); /* ugh.. */
485 ret = do_xdr(fio, it, 1, InputOutputType::String, desc, srcfile, line);
490 gmx_bool gmx_fio_doe_real(t_fileio* fio, real* item, const char* desc, const char* srcfile, int line)
494 ret = do_xdr(fio, item, 1, InputOutputType::Real, desc, srcfile, line);
499 gmx_bool gmx_fio_doe_float(t_fileio* fio, float* item, const char* desc, const char* srcfile, int line)
503 ret = do_xdr(fio, item, 1, InputOutputType::Float, desc, srcfile, line);
508 gmx_bool gmx_fio_doe_double(t_fileio* fio, double* item, const char* desc, const char* srcfile, int line)
512 ret = do_xdr(fio, item, 1, InputOutputType::Double, desc, srcfile, line);
518 gmx_bool gmx_fio_doe_gmx_bool(t_fileio* fio, gmx_bool* item, const char* desc, const char* srcfile, int line)
526 ret = do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
531 int itmp = static_cast<int>(*item);
532 ret = do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
538 gmx_bool gmx_fio_doe_int(t_fileio* fio, int* item, const char* desc, const char* srcfile, int line)
542 ret = do_xdr(fio, item, 1, InputOutputType::Int, desc, srcfile, line);
547 gmx_bool gmx_fio_doe_int32(t_fileio* fio, int32_t* item, const char* desc, const char* srcfile, int line)
551 ret = do_xdr(fio, item, 1, InputOutputType::Int32, desc, srcfile, line);
556 gmx_bool gmx_fio_doe_int64(t_fileio* fio, int64_t* item, const char* desc, const char* srcfile, int line)
560 ret = do_xdr(fio, item, 1, InputOutputType::Int64, desc, srcfile, line);
565 gmx_bool gmx_fio_doe_uchar(t_fileio* fio, unsigned char* item, const char* desc, const char* srcfile, int line)
569 ret = do_xdr(fio, item, 1, InputOutputType::UnsignedChar, desc, srcfile, line);
574 gmx_bool gmx_fio_doe_char(t_fileio* fio, char* item, const char* desc, const char* srcfile, int line)
578 ret = do_xdr(fio, item, 1, InputOutputType::Char, desc, srcfile, line);
583 gmx_bool gmx_fio_doe_ushort(t_fileio* fio, unsigned short* item, const char* desc, const char* srcfile, int line)
587 ret = do_xdr(fio, item, 1, InputOutputType::UnsignedShort, desc, srcfile, line);
592 gmx_bool gmx_fio_doe_rvec(t_fileio* fio, rvec* item, const char* desc, const char* srcfile, int line)
596 ret = do_xdr(fio, item, 1, InputOutputType::RVec, desc, srcfile, line);
601 gmx_bool gmx_fio_doe_ivec(t_fileio* fio, ivec* item, const char* desc, const char* srcfile, int line)
605 ret = do_xdr(fio, item, 1, InputOutputType::IVec, desc, srcfile, line);
610 gmx_bool gmx_fio_doe_string(t_fileio* fio, char* item, const char* desc, const char* srcfile, int line)
614 ret = do_xdr(fio, item, 1, InputOutputType::String, desc, srcfile, line);
619 gmx_bool gmx_fio_doe_opaque(t_fileio* fio, char* data, std::size_t size, const char* desc, const char* srcfile, int line)
623 ret = do_xdr(fio, data, size, InputOutputType::Opaque, desc, srcfile, line);
628 /* Array reading & writing */
630 gmx_bool gmx_fio_ndoe_real(t_fileio* fio, real* item, int n, const char* desc, const char* srcfile, int line)
635 for (i = 0; i < n; i++)
637 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Real, desc, srcfile, line);
644 gmx_bool gmx_fio_ndoe_float(t_fileio* fio, float* item, int n, const char* desc, const char* srcfile, int line)
649 for (i = 0; i < n; i++)
651 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Float, desc, srcfile, line);
658 gmx_bool gmx_fio_ndoe_double(t_fileio* fio, double* item, int n, const char* desc, const char* srcfile, int line)
663 for (i = 0; i < n; i++)
665 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Double, desc, srcfile, line);
672 gmx_bool gmx_fio_ndoe_gmx_bool(t_fileio* fio, gmx_bool* item, int n, const char* desc, const char* srcfile, int line)
678 for (i = 0; i < n; i++)
683 ret = ret && do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
684 item[i] = (itmp != 0);
688 int itmp = static_cast<int>(item[i]);
689 ret = ret && do_xdr(fio, &itmp, 1, InputOutputType::Int, desc, srcfile, line);
696 gmx_bool gmx_fio_ndoe_int(t_fileio* fio, int* item, int n, const char* desc, const char* srcfile, int line)
701 for (i = 0; i < n; i++)
703 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Int, desc, srcfile, line);
710 gmx_bool gmx_fio_ndoe_int64(t_fileio* fio, int64_t* item, int n, const char* desc, const char* srcfile, int line)
715 for (i = 0; i < n; i++)
717 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::Int64, desc, srcfile, line);
724 gmx_bool gmx_fio_ndoe_uchar(t_fileio* fio, unsigned char* item, int n, const char* desc, const char* srcfile, int line)
728 ret = ret && do_xdr(fio, item, n, InputOutputType::UnsignedCharArray, desc, srcfile, line);
733 gmx_bool gmx_fio_ndoe_char(t_fileio* fio, char* item, int n, const char* desc, const char* srcfile, int line)
737 ret = ret && do_xdr(fio, item, n, InputOutputType::CharArray, desc, srcfile, line);
743 gmx_bool gmx_fio_ndoe_ushort(t_fileio* fio, unsigned short* item, int n, const char* desc, const char* srcfile, int line)
748 for (i = 0; i < n; i++)
750 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::UnsignedShort, desc, srcfile, line);
757 gmx_bool gmx_fio_ndoe_rvec(t_fileio* fio, rvec* item, int n, const char* desc, const char* srcfile, int line)
761 ret = ret && do_xdr(fio, item, n, InputOutputType::RVecArray, desc, srcfile, line);
767 gmx_bool gmx_fio_ndoe_ivec(t_fileio* fio, ivec* item, int n, const char* desc, const char* srcfile, int line)
772 for (i = 0; i < n; i++)
774 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::IVec, desc, srcfile, line);
781 gmx_bool gmx_fio_ndoe_string(t_fileio* fio, char* item[], int n, const char* desc, const char* srcfile, int line)
786 for (i = 0; i < n; i++)
788 ret = ret && do_xdr(fio, &(item[i]), 1, InputOutputType::String, desc, srcfile, line);
797 FileIOXdrSerializer::FileIOXdrSerializer(t_fileio* fio) : fio_(fio)
799 GMX_RELEASE_ASSERT(fio, "Need valid file io handle");
802 bool FileIOXdrSerializer::reading() const
807 void FileIOXdrSerializer::doBool(bool* value)
809 gmx_fio_do_gmx_bool(fio_, *value);
812 void FileIOXdrSerializer::doUChar(unsigned char* value)
814 gmx_fio_do_uchar(fio_, *value);
817 void FileIOXdrSerializer::doChar(char* value)
819 gmx_fio_do_char(fio_, *value);
822 void FileIOXdrSerializer::doUShort(unsigned short* value)
824 gmx_fio_do_ushort(fio_, *value);
827 void FileIOXdrSerializer::doInt(int* value)
829 gmx_fio_do_int(fio_, *value);
832 void FileIOXdrSerializer::doInt32(int32_t* value)
834 gmx_fio_do_int32(fio_, *value);
837 void FileIOXdrSerializer::doInt64(int64_t* value)
839 gmx_fio_do_int64(fio_, *value);
842 void FileIOXdrSerializer::doFloat(float* value)
844 gmx_fio_do_float(fio_, *value);
847 void FileIOXdrSerializer::doDouble(double* value)
849 gmx_fio_do_double(fio_, *value);
852 void FileIOXdrSerializer::doReal(real* value)
854 gmx_fio_do_real(fio_, *value);
857 void FileIOXdrSerializer::doIvec(ivec* value)
859 gmx_fio_do_ivec(fio_, *value);
862 void FileIOXdrSerializer::doRvec(rvec* value)
864 gmx_fio_do_rvec(fio_, *value);
867 void FileIOXdrSerializer::doCharArray(char* values, int elements)
869 gmx_fio_ndo_char(fio_, values, elements);
872 void FileIOXdrSerializer::doUCharArray(unsigned char* values, int elements)
874 gmx_fio_ndo_uchar(fio_, values, elements);
877 void FileIOXdrSerializer::doRvecArray(rvec* values, int elements)
879 gmx_fio_ndo_rvec(fio_, values, elements);
882 void FileIOXdrSerializer::doString(std::string* value)
884 // TODO: Use an arbitrary length buffer (but that is not supported in
889 std::strncpy(buf, value->c_str(), STRLEN);
892 gmx_fio_do_string(fio_, buf);
899 void FileIOXdrSerializer::doOpaque(char* data, std::size_t size)
901 gmx_fio_do_opaque(fio_, data, size);