Moved tdb functions that access parse structs into parse_prs.c
[kai/samba.git] / source / rpc_parse / parse_prs.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Samba memory buffer functions
5    Copyright (C) Andrew Tridgell              1992-1997
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1997
7    Copyright (C) Jeremy Allison 1999.
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 extern int DEBUGLEVEL;
25
26 #include "includes.h"
27
28
29 /*******************************************************************
30 dump a prs to a file
31  ********************************************************************/
32 void prs_dump(char *name, int v, prs_struct *ps)
33 {
34         int fd, i;
35         pstring fname;
36         if (DEBUGLEVEL < 50) return;
37         for (i=1;i<100;i++) {
38                 if (v != -1) {
39                         slprintf(fname,sizeof(fname), "/tmp/%s_%d.%d.prs", name, v, i);
40                 } else {
41                         slprintf(fname,sizeof(fname), "/tmp/%s.%d.prs", name, i);
42                 }
43                 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
44                 if (fd != -1 || errno != EEXIST) break;
45         }
46         if (fd != -1) {
47                 write(fd, ps->data_p + ps->data_offset, ps->grow_size - ps->data_offset);
48                 close(fd);
49                 DEBUG(0,("created %s\n", fname));
50         }
51 }
52
53
54
55 /*******************************************************************
56  debug output for parsing info.
57
58  XXXX side-effect of this function is to increase the debug depth XXXX
59
60  ********************************************************************/
61 void prs_debug(prs_struct *ps, int depth, char *desc, char *fn_name)
62 {
63         DEBUG(5+depth, ("%s%06x %s %s\n", tab_depth(depth), ps->data_offset, fn_name, desc));
64 }
65
66 /*******************************************************************
67  Initialise a parse structure - malloc the data if requested.
68  ********************************************************************/
69
70 BOOL prs_init(prs_struct *ps, uint32 size, uint8 align, BOOL io)
71 {
72         ZERO_STRUCTP(ps);
73         ps->io = io;
74         ps->bigendian_data = False;
75         ps->align = align;
76         ps->is_dynamic = False;
77         ps->data_offset = 0;
78         ps->buffer_size = 0;
79         ps->data_p = NULL;
80
81         if (size != 0) {
82                 ps->buffer_size = size;
83                 if((ps->data_p = (char *)malloc((size_t)size)) == NULL) {
84                         DEBUG(0,("prs_init: malloc fail for %u bytes.\n", (unsigned int)size));
85                         return False;
86                 }
87                 ps->is_dynamic = True; /* We own this memory. */
88         }
89
90         return True;
91 }
92
93 /*******************************************************************
94  read from a socket into memory.
95  ********************************************************************/
96 BOOL prs_read(prs_struct *ps, int fd, size_t len, int timeout)
97 {
98         BOOL ok;
99         size_t prev_size = ps->buffer_size;
100         if (!prs_grow(ps, len))
101         {
102                 return False;
103         }
104
105         if (timeout > 0)
106         {
107                 ok = (read_with_timeout(fd, &ps->data_p[prev_size],
108                                             len, len,timeout) == len);
109         }
110         else 
111         {
112                 ok = (read_data(fd, &ps->data_p[prev_size], len) == len);
113         }
114         return ok;
115 }
116
117 /*******************************************************************
118  Delete the memory in a parse structure - if we own it.
119  ********************************************************************/
120
121 void prs_mem_free(prs_struct *ps)
122 {
123         if(ps->is_dynamic && (ps->data_p != NULL))
124                 free(ps->data_p);
125         ps->is_dynamic = False;
126         ps->data_p = NULL;
127         ps->buffer_size = 0;
128         ps->data_offset = 0;
129 }
130
131 /*******************************************************************
132  Hand some already allocated memory to a prs_struct.
133  ********************************************************************/
134
135 void prs_give_memory(prs_struct *ps, char *buf, uint32 size, BOOL is_dynamic)
136 {
137         ps->is_dynamic = is_dynamic;
138         ps->data_p = buf;
139         ps->buffer_size = size;
140 }
141
142 /*******************************************************************
143  Take some memory back from a prs_struct.
144  ********************************************************************/
145
146 char *prs_take_memory(prs_struct *ps, uint32 *psize)
147 {
148         char *ret = ps->data_p;
149         if(psize)
150                 *psize = ps->buffer_size;
151         ps->is_dynamic = False;
152         prs_mem_free(ps);
153         return ret;
154 }
155
156 /*******************************************************************
157  Set a prs_struct to exactly a given size. Will grow or tuncate if neccessary.
158  ********************************************************************/
159
160 BOOL prs_set_buffer_size(prs_struct *ps, uint32 newsize)
161 {
162         if (newsize > ps->buffer_size)
163                 return prs_force_grow(ps, newsize - ps->buffer_size);
164
165         if (newsize < ps->buffer_size) {
166                 char *new_data_p = Realloc(ps->data_p, newsize);
167                 /* if newsize is zero, Realloc acts like free() & returns NULL*/
168                 if (new_data_p == NULL && newsize != 0) {
169                         DEBUG(0,("prs_set_buffer_size: Realloc failure for size %u.\n",
170                                 (unsigned int)newsize));
171                         DEBUG(0,("prs_set_buffer_size: Reason %s\n",strerror(errno)));
172                         return False;
173                 }
174                 ps->data_p = new_data_p;
175                 ps->buffer_size = newsize;
176         }
177
178         return True;
179 }
180
181 /*******************************************************************
182  Attempt, if needed, to grow a data buffer.
183  Also depends on the data stream mode (io).
184  ********************************************************************/
185
186 BOOL prs_grow(prs_struct *ps, uint32 extra_space)
187 {
188         uint32 new_size;
189         char *new_data;
190
191         ps->grow_size = MAX(ps->grow_size, ps->data_offset + extra_space);
192
193         if(ps->data_offset + extra_space <= ps->buffer_size)
194                 return True;
195
196         /*
197          * We cannot grow the buffer if we're not reading
198          * into the prs_struct, or if we don't own the memory.
199          */
200
201         if(UNMARSHALLING(ps) || !ps->is_dynamic) {
202                 DEBUG(0,("prs_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
203                                 (unsigned int)extra_space));
204                 /* JRATEST */
205                 smb_panic("prs_grow");
206                 /* JRATEST */
207                 return False;
208         }
209         
210         /*
211          * Decide how much extra space we really need.
212          */
213
214         extra_space -= (ps->buffer_size - ps->data_offset);
215         if(ps->buffer_size == 0) {
216                 /*
217                  * Ensure we have at least a PDU's length, or extra_space, whichever
218                  * is greater.
219                  */
220
221                 new_size = MAX(MAX_PDU_FRAG_LEN,extra_space);
222
223                 if((new_data = malloc(new_size)) == NULL) {
224                         DEBUG(0,("prs_grow: Malloc failure for size %u.\n", (unsigned int)new_size));
225                         return False;
226                 }
227                 memset(new_data, '\0', new_size );
228         } else {
229                 /*
230                  * If the current buffer size is bigger than the space needed, just 
231                  * double it, else add extra_space.
232                  */
233                 new_size = MAX(ps->buffer_size*2, ps->buffer_size + extra_space);               
234
235                 if ((new_data = Realloc(ps->data_p, new_size)) == NULL) {
236                         DEBUG(0,("prs_grow: Realloc failure for size %u.\n",
237                                 (unsigned int)new_size));
238                         return False;
239                 }
240
241                 memset(&new_data[ps->buffer_size], '\0', new_size - ps->buffer_size);
242         }
243         ps->buffer_size = new_size;
244         ps->data_p = new_data;
245
246         return True;
247 }
248
249 /*******************************************************************
250  Attempt to force a data buffer to grow by len bytes.
251  This is only used when appending more data onto a prs_struct
252  when reading an rpc reply, before unmarshalling it.
253  ********************************************************************/
254
255 BOOL prs_force_grow(prs_struct *ps, uint32 extra_space)
256 {
257         uint32 new_size = ps->buffer_size + extra_space;
258         char *new_data;
259
260         if(!UNMARSHALLING(ps) || !ps->is_dynamic) {
261                 DEBUG(0,("prs_force_grow: Buffer overflow - unable to expand buffer by %u bytes.\n",
262                                 (unsigned int)extra_space));
263                 return False;
264         }
265
266         if((new_data = Realloc(ps->data_p, new_size)) == NULL) {
267                 DEBUG(0,("prs_force_grow: Realloc failure for size %u.\n",
268                         (unsigned int)new_size));
269                 return False;
270         }
271
272         memset(&new_data[ps->buffer_size], '\0', new_size - ps->buffer_size);
273
274         ps->buffer_size = new_size;
275         ps->data_p = new_data;
276
277         return True;
278 }
279
280 /*******************************************************************
281  Get the data pointer (external interface).
282  ********************************************************************/
283
284 char *prs_data_p(prs_struct *ps)
285 {
286         return ps->data_p;
287 }
288
289 /*******************************************************************
290  Get the current data size (external interface).
291  ********************************************************************/
292
293 uint32 prs_data_size(prs_struct *ps)
294 {
295         return ps->buffer_size;
296 }
297
298 /*******************************************************************
299  Fetch the current offset (external interface).
300  ********************************************************************/
301
302 uint32 prs_offset(prs_struct *ps)
303 {
304         return ps->data_offset;
305 }
306
307 /*******************************************************************
308  Set the current offset (external interface).
309  ********************************************************************/
310
311 BOOL prs_set_offset(prs_struct *ps, uint32 offset)
312 {
313         if(offset <= ps->data_offset) {
314                 ps->data_offset = offset;
315                 return True;
316         }
317
318         if(!prs_grow(ps, offset - ps->data_offset))
319                 return False;
320
321         ps->data_offset = offset;
322         return True;
323 }
324
325 /*******************************************************************
326  Append the data from one parse_struct into another.
327  ********************************************************************/
328
329 BOOL prs_append_prs_data(prs_struct *dst, prs_struct *src)
330 {
331         if(!prs_grow(dst, prs_offset(src)))
332                 return False;
333
334         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src), (size_t)prs_offset(src));
335         dst->data_offset += prs_offset(src);
336
337         return True;
338 }
339
340 /*******************************************************************
341  Append some data from one parse_struct into another.
342  ********************************************************************/
343
344 BOOL prs_append_some_prs_data(prs_struct *dst, prs_struct *src, int32 start, uint32 len)
345 {       
346         if (len == 0)
347                 return True;
348
349         if(!prs_grow(dst, len))
350                 return False;
351         
352         memcpy(&dst->data_p[dst->data_offset], prs_data_p(src)+start, (size_t)len);
353         dst->data_offset += len;
354
355         return True;
356 }
357
358 /*******************************************************************
359  Append the data from a buffer into a parse_struct.
360  ********************************************************************/
361
362 BOOL prs_append_data(prs_struct *dst, char *src, uint32 len)
363 {
364         if(!prs_grow(dst, len))
365                 return False;
366
367         memcpy(&dst->data_p[dst->data_offset], src, (size_t)len);
368         dst->data_offset += len;
369
370         return True;
371 }
372
373 /*******************************************************************
374  Set the data as big-endian (external interface).
375  ********************************************************************/
376
377 void prs_set_bigendian_data(prs_struct *ps)
378 {
379         ps->bigendian_data = True;
380 }
381
382 /*******************************************************************
383  Align a the data_len to a multiple of align bytes - filling with
384  zeros.
385  ********************************************************************/
386
387 BOOL prs_align(prs_struct *ps)
388 {
389         uint32 mod = ps->data_offset & (ps->align-1);
390
391         if (ps->align != 0 && mod != 0) {
392                 uint32 extra_space = (ps->align - mod);
393                 if(!prs_grow(ps, extra_space))
394                         return False;
395                 memset(&ps->data_p[ps->data_offset], '\0', (size_t)extra_space);
396                 ps->data_offset += extra_space;
397         }
398
399         return True;
400 }
401
402 /*******************************************************************
403  Ensure we can read/write to a given offset.
404  ********************************************************************/
405
406 char *prs_mem_get(prs_struct *ps, uint32 extra_size)
407 {
408         if(UNMARSHALLING(ps)) {
409                 /*
410                  * If reading, ensure that we can read the requested size item.
411                  */
412                 if (ps->data_offset + extra_size > ps->buffer_size) {
413                         DEBUG(0,("prs_mem_get: reading data of size %u would overrun buffer.\n",
414                                         (unsigned int)extra_size ));
415                         return NULL;
416                 }
417         } else {
418                 /*
419                  * Writing - grow the buffer if needed.
420                  */
421                 if(!prs_grow(ps, extra_size))
422                         return False;
423         }
424         return &ps->data_p[ps->data_offset];
425 }
426
427 /*******************************************************************
428  Change the struct type.
429  ********************************************************************/
430
431 void prs_switch_type(prs_struct *ps, BOOL io)
432 {
433         if ((ps->io ^ io) == True)
434                 ps->io=io;
435 }
436
437 /*******************************************************************
438  Force a prs_struct to be dynamic even when it's size is 0.
439  ********************************************************************/
440
441 void prs_force_dynamic(prs_struct *ps)
442 {
443         ps->is_dynamic=True;
444 }
445
446 /*******************************************************************
447  Stream a uint8.
448  ********************************************************************/
449
450 BOOL prs_uint8(char *name, prs_struct *ps, int depth, uint8 *data8)
451 {
452         char *q = prs_mem_get(ps, sizeof(uint8));
453         if (q == NULL)
454                 return False;
455
456         DBG_RW_CVAL(name, depth, ps->data_offset, ps->io, q, *data8)
457         ps->data_offset += sizeof(uint8);
458
459         return True;
460 }
461
462 /*******************************************************************
463  Stream a uint16.
464  ********************************************************************/
465
466 BOOL prs_uint16(char *name, prs_struct *ps, int depth, uint16 *data16)
467 {
468         char *q = prs_mem_get(ps, sizeof(uint16));
469         if (q == NULL)
470                 return False;
471
472         DBG_RW_SVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data16)
473         ps->data_offset += sizeof(uint16);
474
475         return True;
476 }
477
478 /*******************************************************************
479  Stream a uint32.
480  ********************************************************************/
481
482 BOOL prs_uint32(char *name, prs_struct *ps, int depth, uint32 *data32)
483 {
484         char *q = prs_mem_get(ps, sizeof(uint32));
485         if (q == NULL)
486                 return False;
487
488         DBG_RW_IVAL(name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, *data32)
489         ps->data_offset += sizeof(uint32);
490
491         return True;
492 }
493
494 /******************************************************************
495  Stream an array of uint8s. Length is number of uint8s.
496  ********************************************************************/
497
498 BOOL prs_uint8s(BOOL charmode, char *name, prs_struct *ps, int depth, uint8 *data8s, int len)
499 {
500         char *q = prs_mem_get(ps, len * sizeof(uint8));
501         if (q == NULL)
502                 return False;
503
504         DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, data8s, len)
505         ps->data_offset += (len * sizeof(uint8));
506
507         return True;
508 }
509
510 /******************************************************************
511  Stream an array of uint16s. Length is number of uint16s.
512  ********************************************************************/
513
514 BOOL prs_uint16s(BOOL charmode, char *name, prs_struct *ps, int depth, uint16 *data16s, int len)
515 {
516         char *q = prs_mem_get(ps, len * sizeof(uint16));
517         if (q == NULL)
518                 return False;
519
520         DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data16s, len)
521         ps->data_offset += (len * sizeof(uint16));
522
523         return True;
524 }
525
526 /******************************************************************
527  Stream an array of uint32s. Length is number of uint32s.
528  ********************************************************************/
529
530 BOOL prs_uint32s(BOOL charmode, char *name, prs_struct *ps, int depth, uint32 *data32s, int len)
531 {
532         char *q = prs_mem_get(ps, len * sizeof(uint32));
533         if (q == NULL)
534                 return False;
535
536         DBG_RW_PIVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, data32s, len)
537         ps->data_offset += (len * sizeof(uint32));
538
539         return True;
540 }
541
542 /******************************************************************
543  Stream a "not" unicode string, length/buffer specified separately,
544  in byte chars. String is in little-endian format.
545  ********************************************************************/
546
547 BOOL prs_buffer2(BOOL charmode, char *name, prs_struct *ps, int depth, BUFFER2 *str)
548 {
549         char *p = (char *)str->buffer;
550         char *q = prs_mem_get(ps, str->buf_len);
551         if (q == NULL)
552                 return False;
553
554         /* If we're using big-endian, reverse to get little-endian. */
555         if(ps->bigendian_data)
556                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->buf_len/2)
557         else
558                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->buf_len)
559         ps->data_offset += str->buf_len;
560
561         return True;
562 }
563
564 /******************************************************************
565  Stream a string, length/buffer specified separately,
566  in uint8 chars.
567  ********************************************************************/
568
569 BOOL prs_string2(BOOL charmode, char *name, prs_struct *ps, int depth, STRING2 *str)
570 {
571         char *q = prs_mem_get(ps, str->str_str_len * sizeof(uint8));
572         if (q == NULL)
573                 return False;
574
575         DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, str->buffer, str->str_max_len)
576         ps->data_offset += (str->str_str_len * sizeof(uint8));
577
578         return True;
579 }
580
581 /******************************************************************
582  Stream a unicode string, length/buffer specified separately,
583  in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
584  as the unicode string is already in little-endian format.
585  ********************************************************************/
586
587 BOOL prs_unistr2(BOOL charmode, char *name, prs_struct *ps, int depth, UNISTR2 *str)
588 {
589         char *p = (char *)str->buffer;
590         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
591         if (q == NULL)
592                 return False;
593
594         /* If we're using big-endian, reverse to get little-endian. */
595         if(ps->bigendian_data)
596                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
597         else
598                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
599         ps->data_offset += (str->uni_str_len * sizeof(uint16));
600
601         return True;
602 }
603
604 /******************************************************************
605  Stream a unicode string, length/buffer specified separately,
606  in uint16 chars. We use DBG_RW_PCVAL, not DBG_RW_PSVAL here
607  as the unicode string is already in little-endian format.
608  ********************************************************************/
609
610 BOOL prs_unistr3(BOOL charmode, char *name, UNISTR3 *str, prs_struct *ps, int depth)
611 {
612         char *p = (char *)str->str.buffer;
613         char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16));
614         if (q == NULL)
615                 return False;
616
617         /* If we're using big-endian, reverse to get little-endian. */
618         if(ps->bigendian_data)
619                 DBG_RW_PSVAL(charmode, name, depth, ps->data_offset, ps->io, ps->bigendian_data, q, p, str->uni_str_len)
620         else
621                 DBG_RW_PCVAL(charmode, name, depth, ps->data_offset, ps->io, q, p, str->uni_str_len * 2)
622         ps->data_offset += (str->uni_str_len * sizeof(uint16));
623
624         return True;
625 }
626
627 /*******************************************************************
628  Stream a unicode  null-terminated string. As the string is already
629  in little-endian format then do it as a stream of bytes.
630  ********************************************************************/
631
632 BOOL prs_unistr(char *name, prs_struct *ps, int depth, UNISTR *str)
633 {
634         int len = 0;
635         unsigned char *p = (unsigned char *)str->buffer;
636         uint8 *start;
637         char *q;
638         char zero=0;
639
640         for(len = 0; len < (sizeof(str->buffer) / sizeof(str->buffer[0])) &&
641                            str->buffer[len] != 0; len++)
642                 ;
643
644         q = prs_mem_get(ps, (len+1)*2);
645         if (q == NULL)
646                 return False;
647
648         start = (uint8*)q;
649
650         for(len = 0; len < (sizeof(str->buffer) / sizeof(str->buffer[0])) &&
651                            str->buffer[len] != 0; len++) {
652                 if(ps->bigendian_data) {
653                         RW_SVAL(ps->io, ps->bigendian_data, q, *p, 0);
654                         p += 2;
655                         q += 2;
656                 } else {
657                         RW_CVAL(ps->io, q, *p, 0);
658                         p++;
659                         q++;
660                         RW_CVAL(ps->io, q, *p, 0);
661                         p++;
662                         q++;
663                 }
664         }
665         
666         /*
667          * even if the string is 'empty' (only an \0 char)
668          * at this point the leading \0 hasn't been parsed.
669          * so parse it now
670          */
671
672         RW_CVAL(ps->io, q, zero, 0);
673         q++;
674         RW_CVAL(ps->io, q, zero, 0);
675         q++;
676
677         len++;
678                 
679         ps->data_offset += len*2;
680
681         dump_data(5+depth, (char *)start, len * 2);
682
683         return True;
684 }
685
686 /*******************************************************************
687  Stream a null-terminated string.  len is strlen, and therefore does
688  not include the null-termination character.
689  ********************************************************************/
690
691 BOOL prs_string(char *name, prs_struct *ps, int depth, char *str, int len, int max_buf_size)
692 {
693         char *q;
694         uint8 *start;
695         int i;
696
697         len = MIN(len, (max_buf_size-1));
698
699         q = prs_mem_get(ps, len+1);
700         if (q == NULL)
701                 return False;
702
703         start = (uint8*)q;
704
705         for(i = 0; i < len; i++) {
706                 RW_CVAL(ps->io, q, str[i],0);
707                 q++;
708         }
709
710         /* The terminating null. */
711         str[i] = '\0';
712
713         if (MARSHALLING(ps)) {
714                 RW_CVAL(ps->io, q, str[i], 0);
715         }
716
717         ps->data_offset += len+1;
718
719         dump_data(5+depth, (char *)start, len);
720
721         return True;
722 }
723
724 /*******************************************************************
725  prs_uint16 wrapper. Call this and it sets up a pointer to where the
726  uint16 should be stored, or gets the size if reading.
727  ********************************************************************/
728
729 BOOL prs_uint16_pre(char *name, prs_struct *ps, int depth, uint16 *data16, uint32 *offset)
730 {
731         (*offset) = ps->data_offset;
732         if (UNMARSHALLING(ps)) {
733                 /* reading. */
734                 return prs_uint16(name, ps, depth, data16);
735         } else {
736                 char *q = prs_mem_get(ps, sizeof(uint16));
737                 if(q ==NULL)
738                         return False;
739                 ps->data_offset += sizeof(uint16);
740         }
741         return True;
742 }
743
744 /*******************************************************************
745  prs_uint16 wrapper.  call this and it retrospectively stores the size.
746  does nothing on reading, as that is already handled by ...._pre()
747  ********************************************************************/
748
749 BOOL prs_uint16_post(char *name, prs_struct *ps, int depth, uint16 *data16,
750                                 uint32 ptr_uint16, uint32 start_offset)
751 {
752         if (MARSHALLING(ps)) {
753                 /* 
754                  * Writing - temporarily move the offset pointer.
755                  */
756                 uint16 data_size = ps->data_offset - start_offset;
757                 uint32 old_offset = ps->data_offset;
758
759                 ps->data_offset = ptr_uint16;
760                 if(!prs_uint16(name, ps, depth, &data_size)) {
761                         ps->data_offset = old_offset;
762                         return False;
763                 }
764                 ps->data_offset = old_offset;
765         } else {
766                 ps->data_offset = start_offset + (uint32)(*data16);
767         }
768         return True;
769 }
770
771 /*******************************************************************
772  prs_uint32 wrapper. Call this and it sets up a pointer to where the
773  uint32 should be stored, or gets the size if reading.
774  ********************************************************************/
775
776 BOOL prs_uint32_pre(char *name, prs_struct *ps, int depth, uint32 *data32, uint32 *offset)
777 {
778         (*offset) = ps->data_offset;
779         if (UNMARSHALLING(ps)) {
780                 /* reading. */
781                 return prs_uint32(name, ps, depth, data32);
782         } else {
783                 ps->data_offset += sizeof(uint32);
784         }
785         return True;
786 }
787
788 /*******************************************************************
789  prs_uint32 wrapper.  call this and it retrospectively stores the size.
790  does nothing on reading, as that is already handled by ...._pre()
791  ********************************************************************/
792
793 BOOL prs_uint32_post(char *name, prs_struct *ps, int depth, uint32 *data32,
794                                 uint32 ptr_uint32, uint32 data_size)
795 {
796         if (MARSHALLING(ps)) {
797                 /* 
798                  * Writing - temporarily move the offset pointer.
799                  */
800                 uint32 old_offset = ps->data_offset;
801                 ps->data_offset = ptr_uint32;
802                 if(!prs_uint32(name, ps, depth, &data_size)) {
803                         ps->data_offset = old_offset;
804                         return False;
805                 }
806                 ps->data_offset = old_offset;
807         }
808         return True;
809 }
810
811 /* useful function to store a structure in rpc wire format */
812 int tdb_prs_store(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
813 {
814     TDB_DATA kbuf, dbuf;
815     kbuf.dptr = keystr;
816     kbuf.dsize = strlen(keystr)+1;
817     dbuf.dptr = prs_data_p(ps);
818     dbuf.dsize = prs_offset(ps);
819     return tdb_store(tdb, kbuf, dbuf, TDB_REPLACE);
820 }
821
822 /* useful function to fetch a structure into rpc wire format */
823 int tdb_prs_fetch(TDB_CONTEXT *tdb, char *keystr, prs_struct *ps)
824 {
825     TDB_DATA kbuf, dbuf;
826     kbuf.dptr = keystr;
827     kbuf.dsize = strlen(keystr)+1;
828
829     dbuf = tdb_fetch(tdb, kbuf);
830     if (!dbuf.dptr) return -1;
831
832     ZERO_STRUCTP(ps);
833     prs_init(ps, 0, 4, UNMARSHALL);
834     prs_give_memory(ps, dbuf.dptr, dbuf.dsize, True);
835
836     return 0;
837