Initial import from FreeBSD RELENG_4:
[games.git] / lib / libcr / xdr / xdr.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  *
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  *
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  *
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  *
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  */
29
30 #if defined(LIBC_SCCS) && !defined(lint)
31 /*static char *sccsid = "from: @(#)xdr.c 1.35 87/08/12";*/
32 /*static char *sccsid = "from: @(#)xdr.c        2.1 88/07/29 4.0 RPCSRC";*/
33 static char *rcsid = "$FreeBSD: src/lib/libc/xdr/xdr.c,v 1.9.2.1 2000/05/06 21:16:04 dec Exp $";
34 #endif
35
36 /*
37  * xdr.c, Generic XDR routines implementation.
38  *
39  * Copyright (C) 1986, Sun Microsystems, Inc.
40  *
41  * These are the "generic" xdr routines used to serialize and de-serialize
42  * most common data items.  See xdr.h for more info on the interface to
43  * xdr.
44  */
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49
50 #include <rpc/types.h>
51 #include <rpc/xdr.h>
52
53 /*
54  * constants specific to the xdr "protocol"
55  */
56 #define XDR_FALSE       ((long) 0)
57 #define XDR_TRUE        ((long) 1)
58 #define LASTUNSIGNED    ((u_int) 0-1)
59
60 /*
61  * for unit alignment
62  */
63 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
64
65 /*
66  * Free a data structure using XDR
67  * Not a filter, but a convenient utility nonetheless
68  */
69 void
70 xdr_free(proc, objp)
71         xdrproc_t proc;
72         char *objp;
73 {
74         XDR x;
75
76         x.x_op = XDR_FREE;
77         (*proc)(&x, objp);
78 }
79
80 /*
81  * XDR nothing
82  */
83 bool_t
84 xdr_void(/* xdrs, addr */)
85         /* XDR *xdrs; */
86         /* caddr_t addr; */
87 {
88
89         return (TRUE);
90 }
91
92
93 /*
94  * XDR integers
95  */
96 bool_t
97 xdr_int(xdrs, ip)
98         XDR *xdrs;
99         int *ip;
100 {
101         long l;
102
103         switch (xdrs->x_op) {
104
105         case XDR_ENCODE:
106                 l = (long) *ip;
107                 return (XDR_PUTLONG(xdrs, &l));
108
109         case XDR_DECODE:
110                 if (!XDR_GETLONG(xdrs, &l)) {
111                         return (FALSE);
112                 }
113                 *ip = (int) l;
114                 return (TRUE);
115
116         case XDR_FREE:
117                 return (TRUE);
118         }
119         return (FALSE);
120 }
121
122 /*
123  * XDR unsigned integers
124  */
125 bool_t
126 xdr_u_int(xdrs, up)
127         XDR *xdrs;
128         u_int *up;
129 {
130         u_long l;
131
132         switch (xdrs->x_op) {
133
134         case XDR_ENCODE:
135                 l = (u_long) *up;
136                 return (XDR_PUTLONG(xdrs, (long *)&l));
137
138         case XDR_DECODE:
139                 if (!XDR_GETLONG(xdrs, (long *)&l)) {
140                         return (FALSE);
141                 }
142                 *up = (u_int) l;
143                 return (TRUE);
144
145         case XDR_FREE:
146                 return (TRUE);
147         }
148         return (FALSE);
149 }
150
151
152 /*
153  * XDR long integers
154  * same as xdr_u_long - open coded to save a proc call!
155  */
156 bool_t
157 xdr_long(xdrs, lp)
158         register XDR *xdrs;
159         long *lp;
160 {
161         switch (xdrs->x_op) {
162         case XDR_ENCODE:
163                 return (XDR_PUTLONG(xdrs, lp));
164         case XDR_DECODE:
165                 return (XDR_GETLONG(xdrs, lp));
166         case XDR_FREE:
167                 return (TRUE);
168         }
169
170         return (FALSE);
171 }
172
173 /*
174  * XDR unsigned long integers
175  * same as xdr_long - open coded to save a proc call!
176  */
177 bool_t
178 xdr_u_long(xdrs, ulp)
179         register XDR *xdrs;
180         u_long *ulp;
181 {
182         switch (xdrs->x_op) {
183         case XDR_ENCODE:
184                 return (XDR_PUTLONG(xdrs, (long *)ulp));
185         case XDR_DECODE:
186                 return (XDR_GETLONG(xdrs, (long *)ulp));
187         case XDR_FREE:
188                 return (TRUE);
189         }
190         return (FALSE);
191 }
192
193
194 /*
195  * XDR 32-bit integers
196  * same as xdr_u_int32_t - open coded to save a proc call!
197  */
198 bool_t
199 xdr_int32_t(xdrs, int32_p)
200         register XDR *xdrs;
201         int32_t *int32_p;
202 {
203         long l;
204
205         switch (xdrs->x_op) {
206
207         case XDR_ENCODE:
208                 l = (long) *int32_p;
209                 return (XDR_PUTLONG(xdrs, &l));
210
211         case XDR_DECODE:
212                 if (!XDR_GETLONG(xdrs, &l)) {
213                         return (FALSE);
214                 }
215                 *int32_p = (int32_t) l;
216                 return (TRUE);
217
218         case XDR_FREE:
219                 return (TRUE);
220         }
221         return (FALSE);
222 }
223
224 /*
225  * XDR unsigned 32-bit integers
226  * same as xdr_int32_t - open coded to save a proc call!
227  */
228 bool_t
229 xdr_u_int32_t(xdrs, u_int32_p)
230         register XDR *xdrs;
231         u_int32_t *u_int32_p;
232 {
233         u_long l;
234
235         switch (xdrs->x_op) {
236
237         case XDR_ENCODE:
238                 l = (u_long) *u_int32_p;
239                 return (XDR_PUTLONG(xdrs, (long *)&l));
240
241         case XDR_DECODE:
242                 if (!XDR_GETLONG(xdrs, (long *)&l)) {
243                         return (FALSE);
244                 }
245                 *u_int32_p = (u_int32_t) l;
246                 return (TRUE);
247
248         case XDR_FREE:
249                 return (TRUE);
250         }
251         return (FALSE);
252 }
253
254 /*
255  * XDR 64-bit integers
256  */
257 bool_t
258 xdr_int64_t(xdrs, int64_p)
259         register XDR *xdrs;
260         int64_t *int64_p;
261 {
262         u_long ul[2];
263
264         switch (xdrs->x_op) {
265
266         case XDR_ENCODE:
267                 ul[0] = (u_long)((u_int64_t)*int64_p >> 32) & 0xffffffff;
268                 ul[1] = (u_long)((u_int64_t)*int64_p) & 0xffffffff;
269                 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
270                         return (FALSE);
271                 return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
272         case XDR_DECODE:
273                 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
274                         return (FALSE);
275                 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
276                         return (FALSE);
277                 *int64_p = (int64_t)
278                         (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
279                 return (TRUE);
280         case XDR_FREE:
281                 return (TRUE);
282         }
283         return (FALSE);
284 }
285
286 /*
287  * XDR unsigned 64-bit integers
288  */
289 bool_t
290 xdr_u_int64_t(xdrs, uint64_p)
291         register XDR *xdrs;
292         u_int64_t *uint64_p;
293 {
294         u_long ul[2];
295
296         switch (xdrs->x_op) {
297
298         case XDR_ENCODE:
299                 ul[0] = (u_long)(*uint64_p >> 32) & 0xffffffff;
300                 ul[1] = (u_long)(*uint64_p) & 0xffffffff;
301                 if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
302                         return (FALSE);
303                 return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
304
305         case XDR_DECODE:
306                 if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
307                         return (FALSE);
308                 if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
309                         return (FALSE);
310                 *uint64_p = (u_int64_t)
311                         (((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
312                 return (TRUE);
313         case XDR_FREE:
314                 return (TRUE);
315         }
316         return (FALSE);
317 }
318
319
320 /*
321  * XDR short integers
322  */
323 bool_t
324 xdr_short(xdrs, sp)
325         register XDR *xdrs;
326         short *sp;
327 {
328         long l;
329
330         switch (xdrs->x_op) {
331
332         case XDR_ENCODE:
333                 l = (long) *sp;
334                 return (XDR_PUTLONG(xdrs, &l));
335
336         case XDR_DECODE:
337                 if (!XDR_GETLONG(xdrs, &l)) {
338                         return (FALSE);
339                 }
340                 *sp = (short) l;
341                 return (TRUE);
342
343         case XDR_FREE:
344                 return (TRUE);
345         }
346         return (FALSE);
347 }
348
349 /*
350  * XDR unsigned short integers
351  */
352 bool_t
353 xdr_u_short(xdrs, usp)
354         register XDR *xdrs;
355         u_short *usp;
356 {
357         u_long l;
358
359         switch (xdrs->x_op) {
360
361         case XDR_ENCODE:
362                 l = (u_long) *usp;
363                 return (XDR_PUTLONG(xdrs, (long *)&l));
364
365         case XDR_DECODE:
366                 if (!XDR_GETLONG(xdrs, (long *)&l)) {
367                         return (FALSE);
368                 }
369                 *usp = (u_short) l;
370                 return (TRUE);
371
372         case XDR_FREE:
373                 return (TRUE);
374         }
375         return (FALSE);
376 }
377
378
379 /*
380  * XDR 16-bit integers
381  */
382 bool_t
383 xdr_int16_t(xdrs, int16_p)
384         register XDR *xdrs;
385         int16_t *int16_p;
386 {
387         long l;
388
389         switch (xdrs->x_op) {
390
391         case XDR_ENCODE:
392                 l = (long) *int16_p;
393                 return (XDR_PUTLONG(xdrs, &l));
394
395         case XDR_DECODE:
396                 if (!XDR_GETLONG(xdrs, &l)) {
397                         return (FALSE);
398                 }
399                 *int16_p = (int16_t) l;
400                 return (TRUE);
401
402         case XDR_FREE:
403                 return (TRUE);
404         }
405         return (FALSE);
406 }
407
408 /*
409  * XDR unsigned 16-bit integers
410  */
411 bool_t
412 xdr_u_int16_t(xdrs, u_int16_p)
413         register XDR *xdrs;
414         u_int16_t *u_int16_p;
415 {
416         u_long l;
417
418         switch (xdrs->x_op) {
419
420         case XDR_ENCODE:
421                 l = (u_long) *u_int16_p;
422                 return (XDR_PUTLONG(xdrs, (long *)&l));
423
424         case XDR_DECODE:
425                 if (!XDR_GETLONG(xdrs, (long *)&l)) {
426                         return (FALSE);
427                 }
428                 *u_int16_p = (u_int16_t) l;
429                 return (TRUE);
430
431         case XDR_FREE:
432                 return (TRUE);
433         }
434         return (FALSE);
435 }
436
437
438 /*
439  * XDR a char
440  */
441 bool_t
442 xdr_char(xdrs, cp)
443         XDR *xdrs;
444         char *cp;
445 {
446         int i;
447
448         i = (*cp);
449         if (!xdr_int(xdrs, &i)) {
450                 return (FALSE);
451         }
452         *cp = i;
453         return (TRUE);
454 }
455
456 /*
457  * XDR an unsigned char
458  */
459 bool_t
460 xdr_u_char(xdrs, cp)
461         XDR *xdrs;
462         u_char *cp;
463 {
464         u_int u;
465
466         u = (*cp);
467         if (!xdr_u_int(xdrs, &u)) {
468                 return (FALSE);
469         }
470         *cp = u;
471         return (TRUE);
472 }
473
474 /*
475  * XDR booleans
476  */
477 bool_t
478 xdr_bool(xdrs, bp)
479         register XDR *xdrs;
480         bool_t *bp;
481 {
482         long lb;
483
484         switch (xdrs->x_op) {
485
486         case XDR_ENCODE:
487                 lb = *bp ? XDR_TRUE : XDR_FALSE;
488                 return (XDR_PUTLONG(xdrs, &lb));
489
490         case XDR_DECODE:
491                 if (!XDR_GETLONG(xdrs, &lb)) {
492                         return (FALSE);
493                 }
494                 *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
495                 return (TRUE);
496
497         case XDR_FREE:
498                 return (TRUE);
499         }
500         return (FALSE);
501 }
502
503 /*
504  * XDR enumerations
505  */
506 bool_t
507 xdr_enum(xdrs, ep)
508         XDR *xdrs;
509         enum_t *ep;
510 {
511 #ifndef lint
512         enum sizecheck { SIZEVAL };     /* used to find the size of an enum */
513
514         /*
515          * enums are treated as ints
516          */
517         if (sizeof (enum sizecheck) == sizeof (long)) {
518                 return (xdr_long(xdrs, (long *)ep));
519         } else if (sizeof (enum sizecheck) == sizeof (int)) {
520                 return (xdr_int(xdrs, (int *)ep));
521         } else if (sizeof (enum sizecheck) == sizeof (short)) {
522                 return (xdr_short(xdrs, (short *)ep));
523         } else {
524                 return (FALSE);
525         }
526 #else
527         (void) (xdr_short(xdrs, (short *)ep));
528         (void) (xdr_int(xdrs, (int *)ep));
529         return (xdr_long(xdrs, (long *)ep));
530 #endif
531 }
532
533 /*
534  * XDR opaque data
535  * Allows the specification of a fixed size sequence of opaque bytes.
536  * cp points to the opaque object and cnt gives the byte length.
537  */
538 bool_t
539 xdr_opaque(xdrs, cp, cnt)
540         register XDR *xdrs;
541         caddr_t cp;
542         register u_int cnt;
543 {
544         register u_int rndup;
545         static crud[BYTES_PER_XDR_UNIT];
546
547         /*
548          * if no data we are done
549          */
550         if (cnt == 0)
551                 return (TRUE);
552
553         /*
554          * round byte count to full xdr units
555          */
556         rndup = cnt % BYTES_PER_XDR_UNIT;
557         if (rndup > 0)
558                 rndup = BYTES_PER_XDR_UNIT - rndup;
559
560         if (xdrs->x_op == XDR_DECODE) {
561                 if (!XDR_GETBYTES(xdrs, cp, cnt)) {
562                         return (FALSE);
563                 }
564                 if (rndup == 0)
565                         return (TRUE);
566                 return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup));
567         }
568
569         if (xdrs->x_op == XDR_ENCODE) {
570                 if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
571                         return (FALSE);
572                 }
573                 if (rndup == 0)
574                         return (TRUE);
575                 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
576         }
577
578         if (xdrs->x_op == XDR_FREE) {
579                 return (TRUE);
580         }
581
582         return (FALSE);
583 }
584
585 /*
586  * XDR counted bytes
587  * *cpp is a pointer to the bytes, *sizep is the count.
588  * If *cpp is NULL maxsize bytes are allocated
589  */
590 bool_t
591 xdr_bytes(xdrs, cpp, sizep, maxsize)
592         register XDR *xdrs;
593         char **cpp;
594         register u_int *sizep;
595         u_int maxsize;
596 {
597         register char *sp = *cpp;  /* sp is the actual string pointer */
598         register u_int nodesize;
599
600         /*
601          * first deal with the length since xdr bytes are counted
602          */
603         if (! xdr_u_int(xdrs, sizep)) {
604                 return (FALSE);
605         }
606         nodesize = *sizep;
607         if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
608                 return (FALSE);
609         }
610
611         /*
612          * now deal with the actual bytes
613          */
614         switch (xdrs->x_op) {
615
616         case XDR_DECODE:
617                 if (nodesize == 0) {
618                         return (TRUE);
619                 }
620                 if (sp == NULL) {
621                         *cpp = sp = (char *)mem_alloc(nodesize);
622                 }
623                 if (sp == NULL) {
624                         (void) fprintf(stderr, "xdr_bytes: out of memory\n");
625                         return (FALSE);
626                 }
627                 /* fall into ... */
628
629         case XDR_ENCODE:
630                 return (xdr_opaque(xdrs, sp, nodesize));
631
632         case XDR_FREE:
633                 if (sp != NULL) {
634                         mem_free(sp, nodesize);
635                         *cpp = NULL;
636                 }
637                 return (TRUE);
638         }
639         return (FALSE);
640 }
641
642 /*
643  * Implemented here due to commonality of the object.
644  */
645 bool_t
646 xdr_netobj(xdrs, np)
647         XDR *xdrs;
648         struct netobj *np;
649 {
650
651         return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
652 }
653
654 /*
655  * XDR a descriminated union
656  * Support routine for discriminated unions.
657  * You create an array of xdrdiscrim structures, terminated with
658  * an entry with a null procedure pointer.  The routine gets
659  * the discriminant value and then searches the array of xdrdiscrims
660  * looking for that value.  It calls the procedure given in the xdrdiscrim
661  * to handle the discriminant.  If there is no specific routine a default
662  * routine may be called.
663  * If there is no specific or default routine an error is returned.
664  */
665 bool_t
666 xdr_union(xdrs, dscmp, unp, choices, dfault)
667         register XDR *xdrs;
668         enum_t *dscmp;          /* enum to decide which arm to work on */
669         char *unp;              /* the union itself */
670         struct xdr_discrim *choices;    /* [value, xdr proc] for each arm */
671         xdrproc_t dfault;       /* default xdr routine */
672 {
673         register enum_t dscm;
674
675         /*
676          * we deal with the discriminator;  it's an enum
677          */
678         if (! xdr_enum(xdrs, dscmp)) {
679                 return (FALSE);
680         }
681         dscm = *dscmp;
682
683         /*
684          * search choices for a value that matches the discriminator.
685          * if we find one, execute the xdr routine for that value.
686          */
687         for (; choices->proc != NULL_xdrproc_t; choices++) {
688                 if (choices->value == dscm)
689                         return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
690         }
691
692         /*
693          * no match - execute the default xdr routine if there is one
694          */
695         return ((dfault == NULL_xdrproc_t) ? FALSE :
696             (*dfault)(xdrs, unp, LASTUNSIGNED));
697 }
698
699
700 /*
701  * Non-portable xdr primitives.
702  * Care should be taken when moving these routines to new architectures.
703  */
704
705
706 /*
707  * XDR null terminated ASCII strings
708  * xdr_string deals with "C strings" - arrays of bytes that are
709  * terminated by a NULL character.  The parameter cpp references a
710  * pointer to storage; If the pointer is null, then the necessary
711  * storage is allocated.  The last parameter is the max allowed length
712  * of the string as specified by a protocol.
713  */
714 bool_t
715 xdr_string(xdrs, cpp, maxsize)
716         register XDR *xdrs;
717         char **cpp;
718         u_int maxsize;
719 {
720         register char *sp = *cpp;  /* sp is the actual string pointer */
721         u_int size;
722         u_int nodesize;
723
724         /*
725          * first deal with the length since xdr strings are counted-strings
726          */
727         switch (xdrs->x_op) {
728         case XDR_FREE:
729                 if (sp == NULL) {
730                         return(TRUE);   /* already free */
731                 }
732                 /* fall through... */
733         case XDR_ENCODE:
734                 size = strlen(sp);
735                 break;
736         }
737         if (! xdr_u_int(xdrs, &size)) {
738                 return (FALSE);
739         }
740         if (size > maxsize) {
741                 return (FALSE);
742         }
743         nodesize = size + 1;
744
745         /*
746          * now deal with the actual bytes
747          */
748         switch (xdrs->x_op) {
749
750         case XDR_DECODE:
751                 if (nodesize == 0) {
752                         return (TRUE);
753                 }
754                 if (sp == NULL)
755                         *cpp = sp = (char *)mem_alloc(nodesize);
756                 if (sp == NULL) {
757                         (void) fprintf(stderr, "xdr_string: out of memory\n");
758                         return (FALSE);
759                 }
760                 sp[size] = 0;
761                 /* fall into ... */
762
763         case XDR_ENCODE:
764                 return (xdr_opaque(xdrs, sp, size));
765
766         case XDR_FREE:
767                 mem_free(sp, nodesize);
768                 *cpp = NULL;
769                 return (TRUE);
770         }
771         return (FALSE);
772 }
773
774 /*
775  * Wrapper for xdr_string that can be called directly from
776  * routines like clnt_call
777  */
778 bool_t
779 xdr_wrapstring(xdrs, cpp)
780         XDR *xdrs;
781         char **cpp;
782 {
783         return xdr_string(xdrs, cpp, LASTUNSIGNED);
784 }