7694368137a8f7e707c6bcce7f97e95fd53df8ef
[alexxy/gromacs.git] / src / gmxlib / gmx_system_xdr.c
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  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * 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 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #ifdef GMX_INTERNAL_XDR
43
44
45 #include <stdlib.h>
46 #include <limits.h>
47 #include <string.h>
48
49 #include "gmx_system_xdr.h"
50
51
52 /* NB - THIS FILE IS ONLY USED ON MICROSOFT WINDOWS, since that
53  * system doesn't provide any standard XDR system libraries. It will
54  * most probably work on other platforms too, but make sure you
55  * test that the xtc files produced are ok before using it. 
56  *
57  * This header file contains Gromacs versions of the definitions for 
58  * Sun External Data Representation (XDR) headers and routines.
59  *
60  * On most UNIX systems this is already present as part of your 
61  * system libraries, but since we want to make Gromacs portable to
62  * platforms like Microsoft Windows we have created a private version
63  * of the necessary routines and distribute them with the Gromacs source.
64  * 
65  * Although the rest of Gromacs is GPL, you can copy and use the XDR 
66  * routines in any way you want as long as you obey Sun's license:
67  *
68  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
69  * unrestricted use provided that this legend is included on all tape
70  * media and as a part of the software program in whole or part.  Users
71  * may copy or modify Sun RPC without charge, but are not authorized
72  * to license or distribute it to anyone else except as part of a product or
73  * program developed by the user.
74  *
75  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
76  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
77  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
78  *
79  * Sun RPC is provided with no support and without any obligation on the
80  * part of Sun Microsystems, Inc. to assist in its use, correction,
81  * modification or enhancement.
82  *
83  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
84  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
85  * OR ANY PART THEREOF.
86  *
87  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
88  * or profits or other special, indirect and consequential damages, even if
89  * Sun has been advised of the possibility of such damages.
90  *
91  * Sun Microsystems, Inc.
92  * 2550 Garcia Avenue
93  * Mountain View, California  94043
94  */ 
95
96
97
98 /*
99  * for unit alignment
100  */
101 static char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0};
102
103 static xdr_uint32_t xdr_swapbytes(xdr_uint32_t x)
104 {
105   xdr_uint32_t y;
106   int i;
107   char *px=(char *)&x;
108   char *py=(char *)&y;
109   
110   for(i=0;i<4;i++)
111     py[i]=px[3-i];
112   
113   return y;
114 }
115
116 static xdr_uint32_t xdr_htonl(xdr_uint32_t x)
117 {
118   short s=0x0F00;
119   if( *((char *)&s)==(char)0x0F) {
120     /* bigendian, do nothing */
121     return x;
122   } else {
123     /* smallendian,swap bytes */
124     return xdr_swapbytes(x);
125   }
126 }
127
128 static xdr_uint32_t xdr_ntohl(xdr_uint32_t x)
129 {
130   short s=0x0F00;
131   if( *((char *)&s)==(char)0x0F) {
132     /* bigendian, do nothing */
133     return x;
134   } else {
135     /* smallendian, swap bytes */
136     return xdr_swapbytes(x);
137   }
138 }
139
140
141 /*
142  * Free a data structure using XDR
143  * Not a filter, but a convenient utility nonetheless
144  */
145 void
146 xdr_free (xdrproc_t proc, char *objp)
147 {
148   XDR x;
149
150   x.x_op = XDR_FREE;
151   (*proc) (&x, objp);
152 }
153
154 /*
155  * XDR nothing
156  */
157 bool_t
158 xdr_void (void)
159 {
160   return TRUE;
161 }
162
163 /*
164  * XDR integers
165  */
166 bool_t
167 xdr_int (XDR *xdrs, int *ip)
168 {
169   xdr_int32_t l;
170
171   switch (xdrs->x_op)
172   {
173     case XDR_ENCODE:
174       l = (xdr_int32_t) (*ip);
175       return xdr_putint32 (xdrs, &l);
176
177     case XDR_DECODE:
178       if (!xdr_getint32 (xdrs, &l))
179           {
180             return FALSE;
181           }
182       *ip = (int) l;
183           
184     case XDR_FREE:
185       return TRUE;
186   }
187   return FALSE;
188 }
189
190
191 /*
192  * XDR unsigned integers
193  */
194 bool_t
195 xdr_u_int (XDR *xdrs, unsigned int *up)
196 {
197   xdr_uint32_t l;
198
199   switch (xdrs->x_op)
200   {
201     case XDR_ENCODE:
202       l = (xdr_uint32_t) (*up);
203       return xdr_putuint32 (xdrs, &l);
204
205     case XDR_DECODE:
206       if (!xdr_getuint32 (xdrs, &l))
207           {
208             return FALSE;
209           }
210       *up = (unsigned int) l;
211           
212     case XDR_FREE:
213       return TRUE;
214   }
215   return FALSE;
216 }
217
218
219
220
221 /*
222  * XDR short integers
223  */
224 bool_t
225 xdr_short (XDR *xdrs, short *sp)
226 {
227   xdr_int32_t l;
228
229   switch (xdrs->x_op)
230     {
231     case XDR_ENCODE:
232       l = (xdr_int32_t) *sp;
233       return xdr_putint32 (xdrs, &l);
234
235     case XDR_DECODE:
236       if (!xdr_getint32 (xdrs, &l))
237         {
238           return FALSE;
239         }
240       *sp = (short) l;
241       return TRUE;
242
243     case XDR_FREE:
244       return TRUE;
245     }
246   return FALSE;
247 }
248
249
250 /*
251  * XDR unsigned short integers
252  */
253 bool_t
254 xdr_u_short (XDR *xdrs, unsigned short *usp)
255 {
256   xdr_uint32_t l;
257
258   switch (xdrs->x_op)
259     {
260     case XDR_ENCODE:
261       l = (xdr_uint32_t) *usp;
262       return xdr_putuint32 (xdrs, &l);
263
264     case XDR_DECODE:
265       if (!xdr_getuint32 (xdrs, &l))
266         {
267           return FALSE;
268         }
269           *usp = (unsigned short) l;
270       return TRUE;
271
272     case XDR_FREE:
273       return TRUE;
274     }
275   return FALSE;
276 }
277
278
279 /*
280  * XDR a char
281  */
282 bool_t
283 xdr_char (XDR *xdrs, char *cp)
284 {
285   int i;
286
287   i = (*cp);
288   if (!xdr_int (xdrs, &i))
289     {
290       return FALSE;
291     }
292   *cp = i;
293   return TRUE;
294 }
295
296 /*
297  * XDR an unsigned char
298  */
299 bool_t
300 xdr_u_char (XDR *xdrs, unsigned char *cp)
301 {
302   unsigned int u;
303
304   u = (*cp);
305   if (!xdr_u_int (xdrs, &u))
306     {
307       return FALSE;
308     }
309   *cp = u;
310   return TRUE;
311 }
312
313 /*
314  * XDR booleans
315  */
316 bool_t
317 xdr_bool (XDR *xdrs, int *bp)
318 {
319 #define XDR_FALSE       ((xdr_int32_t) 0)
320 #define XDR_TRUE        ((xdr_int32_t) 1)
321
322   xdr_int32_t lb;
323
324   switch (xdrs->x_op)
325     {
326     case XDR_ENCODE:
327       lb = *bp ? XDR_TRUE : XDR_FALSE;
328       return xdr_putint32 (xdrs, &lb);
329
330     case XDR_DECODE:
331       if (!xdr_getint32 (xdrs, &lb))
332         {
333           return FALSE;
334         }
335       *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
336       return TRUE;
337
338     case XDR_FREE:
339       return TRUE;
340     }
341   return FALSE;
342 #undef XDR_FALSE
343 #undef XDR_TRUE
344 }
345
346
347
348 /*
349  * XDR opaque data
350  * Allows the specification of a fixed size sequence of opaque bytes.
351  * cp points to the opaque object and cnt gives the byte length.
352  */
353 bool_t
354 xdr_opaque (XDR *xdrs, char *cp, unsigned int cnt)
355 {
356   unsigned int rndup;
357   char crud[BYTES_PER_XDR_UNIT];
358
359   /*
360    * if no data we are done
361    */
362   if (cnt == 0)
363     return TRUE;
364
365   /*
366    * round byte count to full xdr units
367    */
368   rndup = cnt % BYTES_PER_XDR_UNIT;
369   if (rndup > 0)
370     rndup = BYTES_PER_XDR_UNIT - rndup;
371
372   switch (xdrs->x_op)
373     {
374     case XDR_DECODE:
375       if (!xdr_getbytes (xdrs, cp, cnt))
376         {
377           return FALSE;
378         }
379       if (rndup == 0)
380         return TRUE;
381       return xdr_getbytes (xdrs, (char *)crud, rndup);
382
383     case XDR_ENCODE:
384       if (!xdr_putbytes (xdrs, cp, cnt))
385         {
386           return FALSE;
387         }
388       if (rndup == 0)
389         return TRUE;
390       return xdr_putbytes (xdrs, xdr_zero, rndup);
391
392     case XDR_FREE:
393       return TRUE;
394     }
395   return FALSE;
396 }
397
398
399 /*
400  * XDR null terminated ASCII strings
401  * xdr_string deals with "C strings" - arrays of bytes that are
402  * terminated by a NULL character.  The parameter cpp references a
403  * pointer to storage; If the pointer is null, then the necessary
404  * storage is allocated.  The last parameter is the max allowed length
405  * of the string as specified by a protocol.
406  */
407 bool_t
408 xdr_string (xdrs, cpp, maxsize)
409      XDR *xdrs;
410      char **cpp;
411      unsigned int maxsize;
412 {
413   char *sp = *cpp;      /* sp is the actual string pointer */
414   unsigned int size = 0;
415   unsigned int nodesize = 0;
416
417   /*
418    * first deal with the length since xdr strings are counted-strings
419    */
420   switch (xdrs->x_op)
421     {
422     case XDR_FREE:
423       if (sp == NULL)
424         {
425           return TRUE;          /* already free */
426         }
427       /* fall through... */
428     case XDR_ENCODE:
429       if (sp == NULL)
430             return FALSE;
431       size = strlen (sp);
432       break;
433     case XDR_DECODE:
434       break;
435     }
436   
437   if (!xdr_u_int (xdrs, &size))
438     {
439       return FALSE;
440     }
441   if (size > maxsize)
442     {
443       return FALSE;
444     }
445   nodesize = size + 1;
446
447   /*
448    * now deal with the actual bytes
449    */
450   switch (xdrs->x_op)
451     {
452     case XDR_DECODE:
453       if (nodesize == 0)
454         {
455           return TRUE;
456         }
457       if (sp == NULL)
458         *cpp = sp = (char *) malloc (nodesize);
459       if (sp == NULL)
460         {
461           (void) fputs ("xdr_string: out of memory\n", stderr);
462           return FALSE;
463         }
464       sp[size] = 0;
465       /* fall into ... */
466
467     case XDR_ENCODE:
468       return xdr_opaque (xdrs, sp, size);
469
470     case XDR_FREE:
471       free (sp);
472       *cpp = NULL;
473       return TRUE;
474     }
475   return FALSE;
476 }
477
478
479
480 /* Floating-point stuff */
481
482 bool_t
483 xdr_float(xdrs, fp)
484      XDR *xdrs;
485      float *fp;
486 {
487         xdr_int32_t tmp;
488         
489         switch (xdrs->x_op) {
490
491         case XDR_ENCODE:
492                 tmp = *(xdr_int32_t *)fp;
493             return (xdr_putint32(xdrs, &tmp));
494
495                 break;
496
497         case XDR_DECODE:
498                         if (xdr_getint32(xdrs, &tmp)) {
499                                 *(xdr_int32_t *)fp = tmp;
500                                 return (TRUE);
501                         }
502
503                 break;
504
505         case XDR_FREE:
506                 return (TRUE);
507         }
508         return (FALSE);
509 }
510
511
512 bool_t
513 xdr_double(xdrs, dp)
514      XDR *xdrs;
515      double *dp;
516 {
517
518   /* Windows and some other systems dont define double-precision
519    * word order in the header files, so unfortunately we have
520    * to calculate it!
521    *
522    * For thread safety, we calculate it every time: locking this would
523    * be more expensive.
524    */
525   /*static int LSW=-1;*/ /* Least significant fp word */
526   int LSW=-1; /* Least significant fp word */
527   
528
529   int *ip;
530   xdr_int32_t tmp[2];
531
532   if(LSW<0) {
533     double x=0.987654321; /* Just a number */
534
535     /* Possible representations in IEEE double precision: 
536      * (S=small endian, B=big endian)
537      * 
538      * Byte order, Word order, Hex
539      *     S           S       b8 56 0e 3c dd 9a ef 3f    
540      *     B           S       3c 0e 56 b8 3f ef 9a dd
541      *     S           B       dd 9a ef 3f b8 56 0e 3c
542      *     B           B       3f ef 9a dd 3c 0e 56 b8
543      */ 
544     
545     unsigned char ix = *((char *)&x);
546     
547     if(ix==0xdd || ix==0x3f)
548       LSW=1;  /* Big endian word order */
549     else if(ix==0xb8 || ix==0x3c)
550       LSW=0;  /* Small endian word order */
551     else { /* Catch strange errors */
552       printf("Error when detecting floating-point word order.\n"
553              "Do you have a non-IEEE system?\n"
554              "If possible, use the XDR libraries provided with your system,\n"
555              "instead of the Gromacs fallback XDR source.\n");
556       exit(0);
557     }
558   }  
559   
560   switch (xdrs->x_op) {
561     
562   case XDR_ENCODE:
563     ip = (int *)dp;
564     tmp[0] = ip[!LSW];
565     tmp[1] = ip[LSW];
566     return (xdr_putint32(xdrs, tmp) &&
567               xdr_putint32(xdrs, tmp+1));
568  
569     break;
570     
571   case XDR_DECODE:
572     ip = (int *)dp;
573     if (xdr_getint32(xdrs, tmp+!LSW) &&
574           xdr_getint32(xdrs, tmp+LSW)) {
575         ip[0] = tmp[0];
576         ip[1] = tmp[1];
577         return (TRUE);
578     }
579
580     break;
581     
582   case XDR_FREE:
583     return (TRUE);
584   }
585   return (FALSE);
586 }
587
588
589 /* Array routines */
590
591 /*
592  * xdr_vector():
593  *
594  * XDR a fixed length array. Unlike variable-length arrays,
595  * the storage of fixed length arrays is static and unfreeable.
596  * > basep: base of the array
597  * > size: size of the array
598  * > elemsize: size of each element
599  * > xdr_elem: routine to XDR each element
600  */
601 bool_t
602 xdr_vector (xdrs, basep, nelem, elemsize, xdr_elem)
603      XDR *xdrs;
604      char *basep;
605      unsigned int nelem;
606      unsigned int elemsize;
607      xdrproc_t xdr_elem;
608 {
609 #define LASTUNSIGNED    ((unsigned int)0-1)
610   unsigned int i;
611   char *elptr;
612
613   elptr = basep;
614   for (i = 0; i < nelem; i++)
615     {
616       if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED))
617         {
618           return FALSE;
619         }
620       elptr += elemsize;
621     }
622   return TRUE;
623 #undef LASTUNSIGNED
624 }
625
626
627
628 static bool_t xdrstdio_getbytes (XDR *, char *, unsigned int);
629 static bool_t xdrstdio_putbytes (XDR *, char *, unsigned int);
630 static unsigned int xdrstdio_getpos (XDR *);
631 static bool_t xdrstdio_setpos (XDR *, unsigned int);
632 static xdr_int32_t *xdrstdio_inline (XDR *, int);
633 static void xdrstdio_destroy (XDR *);
634 static bool_t xdrstdio_getint32 (XDR *, xdr_int32_t *);
635 static bool_t xdrstdio_putint32 (XDR *, xdr_int32_t *);
636 static bool_t xdrstdio_getuint32 (XDR *, xdr_uint32_t *);
637 static bool_t xdrstdio_putuint32 (XDR *, xdr_uint32_t *);
638
639 /*
640  * Ops vector for stdio type XDR
641  */
642 static const struct xdr_ops xdrstdio_ops =
643 {
644   xdrstdio_getbytes,            /* deserialize counted bytes */
645   xdrstdio_putbytes,            /* serialize counted bytes */
646   xdrstdio_getpos,              /* get offset in the stream */
647   xdrstdio_setpos,              /* set offset in the stream */
648   xdrstdio_inline,              /* prime stream for inline macros */
649   xdrstdio_destroy,             /* destroy stream */
650   xdrstdio_getint32,    /* deserialize a int */
651   xdrstdio_putint32,    /* serialize a int */
652   xdrstdio_getuint32,   /* deserialize a int */
653   xdrstdio_putuint32            /* serialize a int */
654 };
655
656 /*
657  * Initialize a stdio xdr stream.
658  * Sets the xdr stream handle xdrs for use on the stream file.
659  * Operation flag is set to op.
660  */
661 void
662 xdrstdio_create (XDR *xdrs, FILE *file, enum xdr_op op)
663 {
664   xdrs->x_op = op;
665   /* We have to add the const since the `struct xdr_ops' in `struct XDR'
666      is not `const'.  */
667   xdrs->x_ops = (struct xdr_ops *) &xdrstdio_ops;
668   xdrs->x_private = (char *) file;
669   xdrs->x_handy = 0;
670   xdrs->x_base = 0;
671 }
672
673 /*
674  * Destroy a stdio xdr stream.
675  * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create.
676  */
677 static void
678 xdrstdio_destroy (XDR *xdrs)
679 {
680   (void) fflush ((FILE *) xdrs->x_private);
681   /* xx should we close the file ?? */
682 }
683
684
685 static bool_t
686 xdrstdio_getbytes (XDR *xdrs, char *addr, unsigned int len)
687 {
688   if ((len != 0) && (fread (addr, (int) len, 1,
689                             (FILE *) xdrs->x_private) != 1))
690     return FALSE;
691   return TRUE;
692 }
693
694 static bool_t
695 xdrstdio_putbytes (XDR *xdrs, char *addr, unsigned int len)
696 {
697   if ((len != 0) && (fwrite (addr, (int) len, 1,
698                              (FILE *) xdrs->x_private) != 1))
699     return FALSE;
700   return TRUE;
701 }
702
703 static unsigned int
704 xdrstdio_getpos (XDR *xdrs)
705 {
706   return (unsigned int) ftell ((FILE *) xdrs->x_private);
707 }
708
709 static bool_t
710 xdrstdio_setpos (XDR *xdrs, unsigned int pos)
711 {
712   return fseek ((FILE *) xdrs->x_private, (xdr_int32_t) pos, 0) < 0 ? FALSE : TRUE;
713 }
714
715 static xdr_int32_t *
716 xdrstdio_inline (XDR *xdrs, int len)
717 {
718   /*
719    * Must do some work to implement this: must insure
720    * enough data in the underlying stdio buffer,
721    * that the buffer is aligned so that we can indirect through a
722    * long *, and stuff this pointer in xdrs->x_buf.  Doing
723    * a fread or fwrite to a scratch buffer would defeat
724    * most of the gains to be had here and require storage
725    * management on this buffer, so we don't do this.
726    */
727   return NULL;
728 }
729
730 static bool_t
731 xdrstdio_getint32 (XDR *xdrs, xdr_int32_t *ip)
732 {
733   xdr_int32_t mycopy;
734
735   if (fread ((char *) &mycopy, 4, 1, (FILE *) xdrs->x_private) != 1)
736     return FALSE;
737   *ip = xdr_ntohl (mycopy);
738   return TRUE;
739 }
740
741 static bool_t
742 xdrstdio_putint32 (XDR *xdrs, xdr_int32_t *ip)
743 {
744   xdr_int32_t mycopy = xdr_htonl (*ip);
745
746   ip = &mycopy;
747   if (fwrite ((char *) ip, 4, 1, (FILE *) xdrs->x_private) != 1)
748     return FALSE;
749   return TRUE;
750 }
751
752 static bool_t
753 xdrstdio_getuint32 (XDR *xdrs, xdr_uint32_t *ip)
754 {
755         xdr_uint32_t mycopy;
756         
757         if (fread ((char *) &mycopy, 4, 1, (FILE *) xdrs->x_private) != 1)
758                 return FALSE;
759         *ip = xdr_ntohl (mycopy);
760         return TRUE;
761 }
762
763 static bool_t
764 xdrstdio_putuint32 (XDR *xdrs, xdr_uint32_t *ip)
765 {
766         xdr_uint32_t mycopy = xdr_htonl (*ip);
767         
768         ip = &mycopy;
769         if (fwrite ((char *) ip, 4, 1, (FILE *) xdrs->x_private) != 1)
770                 return FALSE;
771         return TRUE;
772 }
773
774 #else
775 int
776 gmx_system_xdr_empty;
777 #endif /* GMX_SYSTEM_XDR */