1 
2 #include "config.h"
3 
4 #include "assert.h"
5 #include "ffs.h"
6 #include "cod.h"
7 #include "fm_internal.h"
8 #include "ffs_internal.h"
9 #include "string.h"
10 #include "stdio.h"
11 #include "stdlib.h"
12 #include "ffs_marshal.h"
13 
14 static void *
15 quick_get_pointer(FMFieldPtr iofield, void *data);
16 static unsigned long
17 quick_get_ulong(FMFieldPtr iofield, void *data);
18 void
19 quick_put_ulong(FMFieldPtr iofield, unsigned long value, void *data);
20 
21 static long add_to_tmp_buffer(FFSBuffer buf, int size);
22 static int
23 final_variant_size_for_record(int input_record_len, IOConversionPtr conv);
24 
25 static void byte_swap(char *data, int size);
26 
27 typedef struct addr_list {
28     void *addr;
29     int offset;
30 } addr_list_entry;
31 
32 typedef struct encode_state {
33     int copy_all;
34     int output_len;
35     int iovec_is_stack;
36     int iovcnt;
37     internal_iovec *iovec;
38     int malloc_vec_size;
39     int no_leaf_copy;
40 
41     int addr_list_is_stack;
42     int addr_list_cnt;
43     addr_list_entry *addr_list;
44     int malloc_addr_size;
45     int saved_offset_difference;
46     void *orig_data;
47 }*estate;
48 
49 static void free_addr_list(estate s);
50 
51 void
setup_header(FFSBuffer buf,FMFormat f,estate s)52 setup_header(FFSBuffer buf, FMFormat f, estate s)
53 {
54     int header_size = f->server_ID.length;
55     long tmp_data;	/* offset for header */
56     int align_pad;
57 
58     if (f->variant) {
59 	header_size += sizeof(FILE_INT);	/* length info */
60     }
61     align_pad = (8 - header_size) & 0x7;	/* align to 8 */
62     header_size += align_pad;
63 
64     tmp_data = add_to_tmp_buffer(buf, header_size);
65 
66     memcpy((char *) buf->tmp_buffer + tmp_data, f->server_ID.value,
67 	   f->server_ID.length);
68 
69     memset((char*)buf->tmp_buffer + tmp_data + f->server_ID.length,
70 	   0, header_size - f->server_ID.length);
71 
72     /* fill in an IOV field for the header */
73     s->iovec[0].iov_len = header_size;
74     s->iovec[0].iov_offset = tmp_data;
75     s->iovec[0].iov_base = NULL;	/* offset is in tmp_data */
76     s->iovcnt++;
77     s->output_len = header_size;
78 }
79 
80 
81 static char zeroes[8] = {0, 0, 0, 0, 0, 0, 0, 0};
82 #define STACK_ARRAY_SIZE 100
83 
84 static void
ensure_writev_room(estate s,int add_count)85 ensure_writev_room(estate s, int add_count)
86 {
87     /*
88      * we need to track the length of the strings we're writing
89      * assume a small number (STACK_ARRAY_SIZE) but expand
90      * dynamically if we have more...
91      */
92     if (!(s->malloc_vec_size) &&
93 	(s->iovcnt >= STACK_ARRAY_SIZE - add_count)) {
94 	int j;
95 	internal_iovec *tmpl = (internal_iovec *)
96 	    malloc(sizeof(internal_iovec) * (2 * STACK_ARRAY_SIZE + add_count));
97 	s->malloc_vec_size = (2 * STACK_ARRAY_SIZE + add_count);
98 	for (j = 0; j < s->iovcnt; j++) {
99 	    tmpl[j].iov_len = (s->iovec)[j].iov_len;
100 	    tmpl[j].iov_base = (s->iovec)[j].iov_base;
101 	    tmpl[j].iov_offset = (s->iovec)[j].iov_offset;
102 	}
103 	s->iovec = tmpl;
104     } else if ((s->malloc_vec_size != 0) &&
105 	       (s->iovcnt >= s->malloc_vec_size - add_count)) {
106 	(s->malloc_vec_size) *= 2;
107 	s->iovec = realloc(s->iovec, sizeof(internal_iovec) *
108 				(s->malloc_vec_size));
109     }
110 }
111 
112 
113 int
allocate_tmp_space(estate s,FFSBuffer buf,int length,int req_alignment,int * tmp_data_loc)114 allocate_tmp_space(estate s, FFSBuffer buf, int length, int req_alignment, int *tmp_data_loc)
115 {
116     int pad = (req_alignment - s->output_len) & (req_alignment -1);  /*  only works if req_align is power of two */
117     long tmp_data, msg_offset;
118     switch (req_alignment) {
119     case 1: case 2: case 4: case 8: case 16: break;
120     default:
121 	assert(0);
122     }
123     ensure_writev_room(s, 2);
124     tmp_data = add_to_tmp_buffer(buf, length + pad);
125     if (tmp_data == -1) return -1;
126     if (pad != 0) {
127 	if (s->iovec[s->iovcnt-1].iov_base == NULL) {
128 	    /* last was tmp too */
129 	    memset((char*)buf->tmp_buffer + tmp_data, 0, pad);	/* zero pad */
130 	    tmp_data += pad;
131 	    s->iovec[s->iovcnt-1].iov_len += pad;
132 	} else {
133 	    s->iovec[s->iovcnt].iov_len = pad;
134 	    s->iovec[s->iovcnt].iov_offset = 0;
135 	    s->iovec[s->iovcnt].iov_base = zeroes;
136 	    s->iovcnt++;
137 	}
138     }
139     msg_offset = s->output_len + pad;
140     if (tmp_data_loc) *tmp_data_loc = tmp_data;
141     s->output_len += length + pad;
142     return msg_offset;
143 }
144 
145 int
copy_data_to_tmp(estate s,FFSBuffer buf,void * data,int length,int req_alignment,int * tmp_data_loc)146 copy_data_to_tmp(estate s, FFSBuffer buf, void *data, int length, int req_alignment, int *tmp_data_loc)
147 {
148     int tmp_data;
149     int msg_offset = allocate_tmp_space(s, buf, length, req_alignment, &tmp_data);
150     if (length != 0) {
151 	memcpy((char*)buf->tmp_buffer + tmp_data, data, length);
152 	s->iovec[s->iovcnt].iov_len = length;
153 	s->iovec[s->iovcnt].iov_offset = tmp_data;
154 	s->iovec[s->iovcnt].iov_base = NULL;
155 	s->iovcnt++;
156     }
157     if (tmp_data_loc) *tmp_data_loc = tmp_data;
158     return msg_offset;
159 }
160 
161 /*
162  *  same as copy_data_to_tmp, except doesn't actually copy the data.  This is used for FFS_NO_LEAF_COPY.
163  */
164 int
reserve_space_for_data_in_tmp(estate s,FFSBuffer buf,void * data,int length,int req_alignment,int * tmp_data_loc)165 reserve_space_for_data_in_tmp(estate s, FFSBuffer buf, void *data, int length, int req_alignment, int *tmp_data_loc)
166 {
167     int tmp_data;
168     int msg_offset = allocate_tmp_space(s, buf, length, req_alignment, &tmp_data);
169     if (length != 0) {
170 	s->iovec[s->iovcnt].iov_len = length;
171 	s->iovec[s->iovcnt].iov_offset = tmp_data;
172 	s->iovec[s->iovcnt].iov_base = NULL;
173 	s->iovcnt++;
174     }
175     if (tmp_data_loc) *tmp_data_loc = tmp_data;
176     return msg_offset;
177 }
178 
179 int
add_data_iovec(estate s,FFSBuffer buf,void * data,int length,int req_alignment)180 add_data_iovec(estate s, FFSBuffer buf, void *data, int length, int req_alignment)
181 {
182     int msg_offset;
183     int pad = (req_alignment - s->output_len) & (req_alignment -1);  /*  only works if req_align is power of two */
184     switch (req_alignment) {
185     case 1: case 2: case 4: case 8: case 16: break;
186     default:
187 	assert(0);
188     }
189     ensure_writev_room(s, 2);
190     if (pad != 0) {
191 	s->iovec[s->iovcnt].iov_len = pad;
192 	s->iovec[s->iovcnt].iov_offset = 0;
193 	s->iovec[s->iovcnt].iov_base = zeroes;
194 	s->iovcnt++;
195 	s->output_len += pad;
196     }
197     if (length != 0) {
198 	s->iovec[s->iovcnt].iov_len = length;
199 	s->iovec[s->iovcnt].iov_offset = 0;
200 	s->iovec[s->iovcnt].iov_base = data;
201 	s->iovcnt++;
202     }
203     msg_offset = s->output_len;
204     s->output_len += length;
205     return msg_offset;
206 }
207 
208 void
init_encode_state(estate state)209 init_encode_state(estate state)
210 {
211     state->output_len = 0;
212     state->iovcnt = 0;
213     state->malloc_vec_size = 0;
214     state->addr_list_cnt = 0;
215     state->no_leaf_copy = 0;
216 }
217 
218 static int
219 handle_subfields(FFSBuffer buf, FMFormat f, estate s, int data_offset);
220 
221 static char *
FFSencode_internal(FFSBuffer b,FMFormat fmformat,void * data,int * buf_size,int flags)222 FFSencode_internal(FFSBuffer b, FMFormat fmformat, void *data, int *buf_size, int flags)
223 {
224     internal_iovec stack_iov_array[STACK_ARRAY_SIZE];
225     addr_list_entry stack_addr_list[STACK_ARRAY_SIZE];
226     struct encode_state state;
227     init_encode_state(&state);
228     int base_offset = 0;
229     int header_size;
230 
231     state.iovec_is_stack = 1;
232     state.iovec = stack_iov_array;
233     state.addr_list_is_stack = 1;
234     state.addr_list_cnt = 0;
235     state.addr_list = stack_addr_list;
236     state.copy_all = 1;
237     state.saved_offset_difference = 0;
238     state.orig_data = data;
239     if ((flags & FFS_NO_LEAF_COPY) == FFS_NO_LEAF_COPY) {
240 	state.no_leaf_copy = 1;
241     }
242 
243     make_tmp_buffer(b, 0);
244 
245     /* setup header information */
246     setup_header(b, fmformat, &state);
247 
248     header_size = state.output_len;
249     state.saved_offset_difference = header_size;
250 
251     if (fmformat->variant || state.copy_all) {
252 	base_offset = copy_data_to_tmp(&state, b, data,
253 				       fmformat->record_length, 1, NULL);
254 	if (base_offset == -1) return NULL;
255     }
256 
257     if (!fmformat->variant) {
258 	*buf_size = state.output_len;
259 	return b->tmp_buffer;
260     }
261 
262     if (fmformat->recursive) {
263 	state.addr_list[state.addr_list_cnt].addr = data;
264 	state.addr_list[state.addr_list_cnt].offset = base_offset;
265 	state.addr_list_cnt++;
266     }
267 
268     if (copy_data_to_tmp(&state, b, NULL, 0, 8, NULL) == -1) {   /* force 64-bit align for var */
269 	return NULL;
270     }
271     if (!handle_subfields(b, fmformat, &state, base_offset)) return NULL;
272 
273     {
274 	/* fill in actual length of data marshalled after header */
275 	char *tmp_data = b->tmp_buffer;
276 	int record_len = state.output_len - header_size;
277 	int len_align_pad = (4 - fmformat->server_ID.length) & 3;
278 	tmp_data += fmformat->server_ID.length + len_align_pad;
279 	memcpy(tmp_data, &record_len, 4);
280     }
281     free_addr_list(&state);
282     *buf_size = state.output_len;
283     return b->tmp_buffer;
284 }
285 
286 char *
FFSencode(FFSBuffer b,FMFormat fmformat,void * data,int * buf_size)287 FFSencode(FFSBuffer b, FMFormat fmformat, void *data, int *buf_size)
288 {
289     return FFSencode_internal(b, fmformat, data, buf_size, /*flags*/ 0);
290 }
291 
292 char *
FFSencode_no_leaf_copy(FFSBuffer b,FMFormat fmformat,void * data,int * buf_size)293 FFSencode_no_leaf_copy(FFSBuffer b, FMFormat fmformat, void *data, int *buf_size)
294 {
295     return FFSencode_internal(b, fmformat, data, buf_size, /*flags*/ FFS_NO_LEAF_COPY);
296 }
297 
298 static FFSEncodeVector
fixup_output_vector(FFSBuffer b,estate s)299 fixup_output_vector(FFSBuffer b, estate s)
300 {
301     int size = (s->iovcnt + 5) * sizeof(struct FFSEncodeVec);
302     long tmp_vec_offset = add_to_tmp_buffer(b, size);
303     FFSEncodeVector ret;
304     /* buffer will not be realloc'd after this */
305     int i;
306 
307     if (tmp_vec_offset == -1) return NULL;
308 
309     tmp_vec_offset += sizeof(ret[0]) - 1;
310     tmp_vec_offset -= tmp_vec_offset % sizeof(ret[0]);
311     ret = (FFSEncodeVector)(((char*)b->tmp_buffer) + tmp_vec_offset);
312     /* leave two blanks, see notes in ffs_file.c */
313     /* the upshot is that we use these if we need to add headers */
314     ret += 3;
315     for (i=0; i < s->iovcnt; i++) {
316 	ret[i].iov_len = s->iovec[i].iov_len;
317 	if (s->iovec[i].iov_base != NULL) {
318 	    ret[i].iov_base = s->iovec[i].iov_base;
319 	} else {
320 	    ret[i].iov_base = ((char*)b->tmp_buffer) + s->iovec[i].iov_offset;
321 	}
322     }
323     ret[s->iovcnt].iov_base = NULL;
324     ret[s->iovcnt].iov_len = 0;
325     if (!s->iovec_is_stack) {
326 	free(s->iovec);
327 	s->iovec = NULL;
328     }
329     if (!s->addr_list_is_stack && (s->addr_list != NULL)) {
330 	free(s->addr_list);
331 	s->addr_list = NULL;
332     }
333     return ret;
334 }
335 
336 static void
add_to_addr_list(estate s,void * addr,int offset)337 add_to_addr_list(estate s, void *addr, int offset)
338 {
339     if (s->addr_list_is_stack) {
340 	if (s->addr_list_cnt == STACK_ARRAY_SIZE) {
341 	    /* reached the max size for stack-based addr list */
342 	    addr_list_entry *malloc_list;
343 	    s->addr_list_is_stack = 0;
344 	    s->malloc_addr_size = 2*STACK_ARRAY_SIZE;
345 	    malloc_list = malloc(2*STACK_ARRAY_SIZE * sizeof(addr_list_entry));
346 	    memcpy(malloc_list, s->addr_list, STACK_ARRAY_SIZE * sizeof(addr_list_entry));
347 	    s->addr_list = malloc_list;
348 	}
349     } else {
350        /* malloc'd addr_list */
351        if (s->addr_list_cnt == s->malloc_addr_size) {
352 	   s->malloc_addr_size *= 2;
353 	   s->addr_list =
354 	       realloc(s->addr_list, sizeof(addr_list_entry)*s->malloc_addr_size);
355        }
356     }
357     s->addr_list[s->addr_list_cnt].addr = addr;
358     s->addr_list[s->addr_list_cnt].offset = offset;
359     s->addr_list_cnt++;
360 }
361 
362 static int
search_addr_list(estate s,void * addr)363 search_addr_list(estate s, void *addr)
364 {
365     int i;
366     int previous_offset = -1;
367     for (i=0; i < s->addr_list_cnt; i++) {
368 	if (s->addr_list[i].addr == addr) {
369 	    previous_offset = s->addr_list[i].offset;
370 	}
371     }
372     return previous_offset;
373 }
374 
375 static void
free_addr_list(estate s)376 free_addr_list(estate s)
377 {
378     if (s->addr_list_is_stack == 0) {
379 	free(s->addr_list);
380 	s->addr_list = NULL;
381     }
382 }
383 
384 FFSEncodeVector
FFSencode_vector(FFSBuffer b,FMFormat fmformat,void * data)385 FFSencode_vector(FFSBuffer b, FMFormat fmformat, void *data)
386 {
387     internal_iovec stack_iov_array[STACK_ARRAY_SIZE];
388     addr_list_entry stack_addr_list[STACK_ARRAY_SIZE];
389     struct encode_state state;
390     init_encode_state(&state);
391     int base_offset = 0;
392     int header_size;
393 
394     state.iovec_is_stack = 1;
395     state.iovec = stack_iov_array;
396     state.addr_list_is_stack = 1;
397     state.addr_list = stack_addr_list;
398     state.copy_all = 0;
399     state.saved_offset_difference = 0;
400     state.orig_data = data;
401 
402     make_tmp_buffer(b, 0);
403 
404     /* setup header information */
405     setup_header(b, fmformat, &state);
406 
407     header_size = state.output_len;
408     state.saved_offset_difference = header_size;
409 
410     if (fmformat->variant || state.copy_all) {
411 	base_offset = copy_data_to_tmp(&state, b, data,
412 				       fmformat->record_length, 1, NULL);
413 	if (base_offset == -1) return NULL;
414     } else if (!state.copy_all) {
415 	base_offset = add_data_iovec(&state, b, data,
416 				     fmformat->record_length, 1);
417     }
418     if (!fmformat->variant) {
419 	return fixup_output_vector(b, &state);
420     }
421 
422     if (fmformat->recursive) {
423 	state.addr_list[state.addr_list_cnt].addr = data;
424 	state.addr_list[state.addr_list_cnt].offset = base_offset;
425 	state.addr_list_cnt++;
426     }
427 
428     if (copy_data_to_tmp(&state, b, NULL, 0, 8, NULL) == -1) {   /* force 64-bit align for var */
429 	return NULL;
430     }
431     if (!handle_subfields(b, fmformat, &state, base_offset)) return NULL;
432     {
433 	/* fill in actual length of data marshalled after header */
434 	char *tmp_data = b->tmp_buffer;
435 	int record_len = state.output_len - header_size;
436 	int len_align_pad = (4 - fmformat->server_ID.length) & 3;
437 	tmp_data += fmformat->server_ID.length + len_align_pad;
438 	memcpy(tmp_data, &record_len, 4);
439     }
440     free_addr_list(&state);
441     return fixup_output_vector(b, &state);
442 }
443 
444 static int
445 handle_subfield(FFSBuffer buf, FMFormat f, estate s, int data_offset, int parent_offset, FMTypeDesc *t);
446 
447 extern int
field_is_flat(FMFormat f,FMTypeDesc * t)448 field_is_flat(FMFormat f, FMTypeDesc *t)
449 {
450     switch (t->type) {
451     case FMType_pointer:
452 	return FALSE;
453     case FMType_array:
454 	return field_is_flat(f, t->next);
455     case FMType_string:
456 	return FALSE;
457     case FMType_subformat:
458 	return !f->field_subformats[t->field_index]->variant;
459     case FMType_simple:
460 	return TRUE;
461     default:
462 	assert(FALSE);
463     }
464     /* notreached */
465     return FALSE;
466 }
467 
468 static int
handle_subfields(FFSBuffer buf,FMFormat f,estate s,int data_offset)469 handle_subfields(FFSBuffer buf, FMFormat f, estate s, int data_offset)
470 {
471     int i;
472     /* if base is not variant (I.E. doesn't contain addresses), return;*/
473     if (!f->variant) return 1;
474 
475     for (i = 0; i < f->field_count; i++) {
476 	int subfield_offset = data_offset + f->field_list[i].field_offset;
477 	int ret;
478 	if (field_is_flat(f, &f->var_list[i].type_desc)) continue;
479 	ret = handle_subfield(buf, f, s, subfield_offset, data_offset,
480 			      &f->var_list[i].type_desc);
481 	if (ret != 1) return 0;
482     }
483     return 1;
484 }
485 
486 static void
set_dynamic_array_size(FMFormat f,FFSBuffer buf,int parent_offset,FMTypeDesc * t,int new_value)487 set_dynamic_array_size(FMFormat f, FFSBuffer buf, int parent_offset, FMTypeDesc *t, int new_value)
488 {
489     struct _FMgetFieldStruct src_spec;
490     int field = t->control_field_index;
491     if ((t->type != FMType_array) || (t->static_size != 0)) {
492 	printf("Set array size failed!\n");
493 	return;
494     }
495     memset(&src_spec, 0, sizeof(src_spec));
496     src_spec.size = f->field_list[field].field_size;
497     src_spec.offset = f->field_list[field].field_offset;
498     quick_put_ulong(&src_spec, new_value,
499 		    (char*)buf->tmp_buffer + parent_offset);
500 }
501 
502 
503 static int
determine_size(FMFormat f,FFSBuffer buf,int parent_offset,FMTypeDesc * t)504 determine_size(FMFormat f, FFSBuffer buf, int parent_offset, FMTypeDesc *t)
505 {
506     switch (t->type) {
507     case FMType_pointer:
508     case FMType_string:
509 	return f->pointer_size;
510     case FMType_array: {
511 	int size = 1;
512 	while (t->type == FMType_array) {
513 	    if (t->static_size == 0) {
514 		struct _FMgetFieldStruct src_spec;
515 		int field = t->control_field_index;
516 		memset(&src_spec, 0, sizeof(src_spec));
517 		src_spec.size = f->field_list[field].field_size;
518 		src_spec.offset = f->field_list[field].field_offset;
519 		int tmp = quick_get_ulong(&src_spec, (char*)buf->tmp_buffer + parent_offset);
520 		size = size * tmp;
521 	    } else {
522 		size *= t->static_size;
523 	    }
524 	    t = t->next;
525 	}
526 	size *= determine_size(f, buf, parent_offset, t);
527 	return size;
528     }
529     case FMType_subformat:
530 	return f->field_subformats[t->field_index]->record_length;
531     case FMType_simple:
532 	return f->field_list[t->field_index].field_size;
533     }
534     return -1;
535 }
536 
537 static int
handle_subfield(FFSBuffer buf,FMFormat f,estate s,int data_offset,int parent_offset,FMTypeDesc * t)538 handle_subfield(FFSBuffer buf, FMFormat f, estate s, int data_offset, int parent_offset, FMTypeDesc *t)
539 {
540 
541     switch (t->type) {
542     case FMType_pointer:
543     {
544 	struct _FMgetFieldStruct src_spec;
545 	int size, new_offset, tmp_data_loc;
546 	char *ptr_value;
547 	field_marshal_info marshal_info;
548 
549 	memset(&src_spec, 0, sizeof(src_spec));
550 	src_spec.size = f->pointer_size;
551 	ptr_value = quick_get_pointer(&src_spec, (char*)buf->tmp_buffer + data_offset);
552 	if (ptr_value == NULL) return 1;
553 
554 	/* customized marshalling */
555 	if ((marshal_info = get_marshal_info(f, t)) != NULL) {
556 	    if (marshal_info->type == FFSDropField) {
557 		if (marshal_info->drop_row_func(s->orig_data)) {
558 		    /* drop the value */
559 		    quick_put_ulong(&src_spec, 0,
560 				    (char*)buf->tmp_buffer + data_offset);
561 		    return 1;
562 		}
563 	    }
564 	}
565 
566 	if (f->recursive) {
567 	    int previous_offset = search_addr_list(s, ptr_value);
568 	    if (previous_offset != -1) {
569 		quick_put_ulong(&src_spec, previous_offset,
570 				(char*)buf->tmp_buffer + data_offset);
571 		return 1;
572 	    }
573 	}
574 	size = determine_size(f, buf, parent_offset, t->next);
575 	if (size == 0)  {
576 	    quick_put_ulong(&src_spec, 0,
577 			    (char*)buf->tmp_buffer + data_offset);
578 	    return 1;
579 	}
580 	if ((marshal_info == NULL) || (marshal_info->type != FFSSubsampleArrayField)) {
581 	    if (!s->copy_all && field_is_flat(f, t->next)) {
582 		/* leave data where it sits */
583 		new_offset = add_data_iovec(s, buf, ptr_value, size, 8);
584 	    } else {
585 		if (s->no_leaf_copy) {
586 		    /* this path only used for FFSencode_no_leaf_copy() */
587 		    new_offset = reserve_space_for_data_in_tmp(s, buf, ptr_value, size, 8, &tmp_data_loc);
588 		} else {
589 		    new_offset = copy_data_to_tmp(s, buf, ptr_value, size, 8, &tmp_data_loc);
590 		}
591 		if (new_offset == -1) return 0;
592 	    }
593 	} else {
594 	    /* can't leave data where it sits */
595 	    /* 1. allocate temporary space for the destination array
596 	       2. call function to fill destination with part of source
597 	       3. return value is number of elements copied
598 	       4. adjust size of temporary to reflect actual data copied
599 	    */
600 	    int element_size = determine_size(f, buf, parent_offset, t->next->next);
601 	    int element_count = size / element_size;
602 	    cod_exec_context ec = marshal_info->ec;
603 	    struct subsample_marshal_data smd;
604 	    new_offset = allocate_tmp_space(s, buf, size, 8, &tmp_data_loc);
605 	    smd.element_count = element_count;
606 	    smd.element_size = element_size;
607 	    smd.src_ptr = ptr_value;
608 	    smd.dst_ptr = (char*)buf->tmp_buffer + new_offset;
609 	    smd.marshalled_count = 0;
610 #ifdef DO_DCG
611 	    cod_assoc_client_data(ec,  0x534d4450, (long)&smd);
612 #endif
613 	    marshal_info->subsample_array_func(ec, s->orig_data, element_count);
614 	    /* fixup size */
615 	    set_dynamic_array_size(f, buf, parent_offset, t->next,
616 				   smd.marshalled_count);
617 	    if (size != 0) {
618 		s->iovec[s->iovcnt].iov_len = smd.marshalled_count * element_size;
619 		s->iovec[s->iovcnt].iov_offset = tmp_data_loc;
620 		s->iovec[s->iovcnt].iov_base = NULL;
621 		s->iovcnt++;
622 	    }
623 	    s->output_len -= (size - (smd.marshalled_count *element_size));
624 	    buf->tmp_buffer_in_use_size -= (size - (smd.marshalled_count *element_size));
625 	}
626 	quick_put_ulong(&src_spec, new_offset - s->saved_offset_difference,
627 			(char*)buf->tmp_buffer + data_offset);
628 	if (f->recursive) {
629 	    add_to_addr_list(s, ptr_value, new_offset - s->saved_offset_difference);
630 	}
631 	if (field_is_flat(f, t->next)) return 1;
632 	return handle_subfield(buf, f, s, tmp_data_loc, parent_offset, t->next);
633 	break;
634     }
635     case FMType_string:
636     {
637 	struct _FMgetFieldStruct src_spec;
638 	char *ptr_value;
639 	int size, str_offset;
640 	memset(&src_spec, 0, sizeof(src_spec));
641 	src_spec.size = f->pointer_size;
642 	ptr_value = quick_get_pointer(&src_spec, (char*)buf->tmp_buffer + data_offset);
643 	if (ptr_value == NULL) return 1;
644 	size = strlen(ptr_value) + 1;
645 	if (!s->copy_all) {
646 	    /* leave data where it sits */
647 	    str_offset = add_data_iovec(s, buf, ptr_value, size, 1);
648 	} else {
649 	    str_offset = copy_data_to_tmp(s, buf, ptr_value, size, 1, NULL);
650 	    if (str_offset == -1) return 0;
651 	}
652 	quick_put_ulong(&src_spec, str_offset - s->saved_offset_difference,
653 			(char*)buf->tmp_buffer + data_offset);
654 	break;
655     }
656     case FMType_array:
657     {
658 	int elements = 1, i;
659 	int element_size;
660 	int var_array = 0;
661 	FMTypeDesc *next = t;
662 	while (next->type == FMType_array) {
663 	    if (next->static_size == 0) {
664 		struct _FMgetFieldStruct src_spec;
665 		int field = next->control_field_index;
666 		memset(&src_spec, 0, sizeof(src_spec));
667 		src_spec.size = f->field_list[field].field_size;
668 		src_spec.offset = f->field_list[field].field_offset;
669 		int tmp = quick_get_ulong(&src_spec, (char*)buf->tmp_buffer + parent_offset);
670 		elements = elements * tmp;
671 		var_array = 1;
672 	    } else {
673 		elements = elements * next->static_size;
674 	    }
675 	    next = next->next;
676 	}
677 	element_size = determine_size(f, buf, parent_offset, next);
678 	if (field_is_flat(f, next)) return 1;
679 	for (i = 0; i < elements ; i++) {
680 	    int element_offset = data_offset + i * element_size;
681 	    if (!handle_subfield(buf, f, s, element_offset, parent_offset, next)) return 0;
682 	}
683 	break;
684     }
685     case FMType_subformat:
686     {
687 	int field_index = t->field_index;
688 	FMFormat subformat = f->field_subformats[field_index];
689 	return handle_subfields(buf, subformat, s, data_offset);
690 	break;
691     }
692     default:
693 	assert(0);
694     }
695     return 1;
696 }
697 
698 extern FFSEncodeVector
copy_vector_to_FFSBuffer(FFSBuffer buf,FFSEncodeVector vec)699 copy_vector_to_FFSBuffer(FFSBuffer buf, FFSEncodeVector vec) {
700     long vec_offset = (char *) vec - (char *)buf->tmp_buffer;
701 
702     if (((char*)vec < (char*)buf->tmp_buffer)
703         || ((char*)vec >= (char*)buf->tmp_buffer + buf->tmp_buffer_size)) {
704         int i, remainder;
705         for (i = 0; vec[i].iov_base; ++i);
706         vec_offset = add_to_tmp_buffer(buf, (i + 2) * sizeof(*vec));
707 	remainder = vec_offset % sizeof(*vec);
708 	if (remainder != 0) {
709 	    vec_offset += sizeof(*vec) - remainder;
710 	}
711         memcpy((char *) buf->tmp_buffer + vec_offset, vec, (i + 1) * sizeof(*vec));
712     }
713 
714     return (FFSEncodeVector) ((char *) buf->tmp_buffer + vec_offset);
715 }
716 
717 extern FFSEncodeVector
copy_all_to_FFSBuffer(FFSBuffer buf,FFSEncodeVector vec)718 copy_all_to_FFSBuffer(FFSBuffer buf, FFSEncodeVector vec)
719 {
720     int i = 0;
721     int vec_offset = (long) vec - (long)buf->tmp_buffer;
722     /*
723      * vec and some of the buffers may be in the memory managed by the
724      * FFSBuffer.  The goal here to is put *everything* into the FFSBuffer.
725      */
726     int vec_count = 0;
727     while (vec[vec_count].iov_base != NULL) {
728       vec_count++;
729     }
730     assert(((unsigned long)vec >= (unsigned long)buf->tmp_buffer) &&
731 	   ((unsigned long)vec < (unsigned long)buf->tmp_buffer + buf->tmp_buffer_size));
732     {
733         int already_in[vec_count];
734 	while (vec[i].iov_base != NULL) {
735 	    if (((char*)vec[i].iov_base >= (char*)buf->tmp_buffer) &&
736 		((char*)vec[i].iov_base < (char*)buf->tmp_buffer + buf->tmp_buffer_size)) {
737 	        /*
738 		 * remap pointers into temp so that they're offsets (must do
739 		 * this before we realloc the temp
740 		 */
741 	        vec[i].iov_base = (void*)((char *)vec[i].iov_base - (char *)buf->tmp_buffer + 1);
742 		already_in[i] = 1;
743 	    } else {
744 		already_in[i] = 0;
745 	    }
746 	    i++;
747 	}
748 
749 	i = 0;
750 	while (((FFSEncodeVector)((long)buf->tmp_buffer + vec_offset))[i].iov_base !=
751 	       NULL) {
752 	    FFSEncodeVector v = (void*)((long) buf->tmp_buffer + vec_offset);
753 	    if (already_in[i] == 0) {
754 	        /* if this is an external buffer, copy it */
755 	        long offset = add_to_tmp_buffer(buf, v[i].iov_len);
756 		char * data = (char *) buf->tmp_buffer + offset;
757 		/* add_to_tmp_buffer() might have remapped vector */
758 		v = (void*)((char *) buf->tmp_buffer + vec_offset);
759 		memcpy(data, v[i].iov_base, v[i].iov_len);
760 		v[i].iov_base = (void*)(long)(offset + 1);
761 	    }
762 	    i++;
763 	}
764     }
765     /* reallocation done now */
766     vec = (void*)((long)buf->tmp_buffer + vec_offset);
767     i = 0;
768     while (vec[i].iov_base != NULL) {
769 	if (((long)vec[i].iov_base > 0) &&
770 	    ((long)vec[i].iov_base <= buf->tmp_buffer_size)) {
771 	    /*
772 	     * remap pointers into temp so that they're addresses
773 	     */
774 	    vec[i].iov_base = (void*)((long)vec[i].iov_base + (char *)buf->tmp_buffer - 1);
775 	}
776 	i++;
777     }
778     return vec;
779 }
780 
781 void
782 FFSfree_conversion(IOConversionPtr conv);
783 
784 extern
785 void
free_FFSTypeHandle(FFSTypeHandle f)786 free_FFSTypeHandle(FFSTypeHandle f)
787 {
788     int i = 0;
789     if (f->conversion) FFSfree_conversion(f->conversion);
790     while(f->subformats && f->subformats[i]) {
791 	free_FFSTypeHandle(f->subformats[i]);
792 	f->subformats[i] = NULL;
793 	i++;
794     }
795     free(f->subformats);
796     free(f->field_subformats);
797     free(f);
798 }
799 
800 extern
801 FFSTypeHandle
FFSTypeHandle_by_index(FFSContext c,int index)802 FFSTypeHandle_by_index(FFSContext c, int index)
803 {
804     FFSTypeHandle handle = NULL;
805     if (c->handle_list == NULL) {
806 	c->handle_list = malloc(sizeof(c->handle_list[0]) * (index+1));
807 	memset(c->handle_list, 0, sizeof(c->handle_list[0]) * (index+1));
808 	c->handle_list_size = index + 1;
809     } else if (c->handle_list_size <= index) {
810 	c->handle_list = realloc(c->handle_list,
811 				 (index+1)*sizeof(c->handle_list[0]));
812 	memset(&c->handle_list[c->handle_list_size], 0,
813 	       sizeof(c->handle_list[0]) * ((index+1) - c->handle_list_size));
814 	c->handle_list_size = index + 1;
815     }
816     if (c->handle_list[index] == NULL) {
817 	FMFormat fmf = FMformat_by_index(c->fmc, index);
818 	if (fmf == NULL) return NULL;
819 	c->handle_list[index] = malloc(sizeof(struct _FFSTypeHandle));
820 	handle = c->handle_list[index];
821 	handle->context = c;
822 	handle->format_id = index;
823 	handle->conversion = NULL;
824 	handle->status = not_checked;
825 	handle->body = FMformat_by_index(c->fmc, index);
826 	handle->is_fixed_target = 0;
827 	if ((fmf->subformats && (fmf->subformats[0] != NULL)) || fmf->recursive) {
828 	    int i, k, subformat_count = 0;
829 	    while (fmf->subformats[subformat_count] != NULL) subformat_count++;
830 	    handle->subformats =
831 		malloc(sizeof(FFSTypeHandle)*(subformat_count+1));
832 	    for (i = 0 ; i < subformat_count ; i++) {
833 		handle->subformats[i] = malloc(sizeof(*handle->subformats[i]));
834 		handle->subformats[i]->context = c;
835 		handle->subformats[i]->format_id = -1;
836 		handle->subformats[i]->conversion = NULL;
837 		handle->subformats[i]->status = not_checked;
838 		handle->subformats[i]->body = fmf->subformats[i];
839 		handle->subformats[i]->subformats = NULL;
840 	    }
841 	    handle->subformats[subformat_count] = NULL;
842 	    handle->field_subformats =
843 		malloc(fmf->field_count * sizeof(FFSTypeHandle));
844 	    memset(handle->field_subformats, 0,
845 		   fmf->field_count * sizeof(FFSTypeHandle));
846 	    for (i = 0; i < fmf->field_count; i++) {
847 		if (fmf->field_subformats[i] != NULL) {
848 		    int j;
849 		    for (j = 0; j < subformat_count; j++) {
850 			if (fmf->field_subformats[i] == handle->subformats[j]->body) {
851 			    handle->field_subformats[i] = handle->subformats[j];
852 			}
853 		    }
854 		    if (fmf->field_subformats[i] == fmf) {
855 			/* recursive */
856 			handle->field_subformats[i] = handle;
857 		    }
858 		} else {
859 		    handle->field_subformats[i] = NULL;
860 		}
861 	    }
862 	    for (k = 0; k < subformat_count ; k++) {
863 		FFSTypeHandle sf = handle->subformats[k];
864 		FMFormat sfmf = fmf->subformats[k];
865 		sf->field_subformats =
866 		    malloc(sfmf->field_count * sizeof(FFSTypeHandle));
867 		memset(sf->field_subformats, 0,
868 		       sfmf->field_count * sizeof(FFSTypeHandle));
869 		for (i = 0; i < sfmf->field_count; i++) {
870 		    if (sfmf->field_subformats[i] != NULL) {
871 			int j;
872 			for (j = 0; j < subformat_count; j++) {
873 			    if (sfmf->field_subformats[i] == handle->subformats[j]->body) {
874 				sf->field_subformats[i] = handle->subformats[j];
875 			    }
876 			}
877 		    }
878 		}
879 	    }
880 	} else {
881 	    handle->subformats = NULL;
882 	    handle->field_subformats = NULL;
883 	}
884     }
885     return c->handle_list[index];
886 }
887 
888 extern
889 FFSTypeHandle
FFSTypeHandle_from_encode(FFSContext c,char * buffer)890 FFSTypeHandle_from_encode(FFSContext c, char *buffer)
891 {
892     int index;
893     FFSTypeHandle handle;
894     /* first element in encoded buffer is format ID */
895     FMFormat fmf = FMformat_from_ID(c->fmc, buffer);
896     if (fmf == NULL) return NULL;
897     index = fmf->format_index;
898     handle = FFSTypeHandle_by_index(c, index);
899     return handle;
900 }
901 
902 extern
903 FFSContext
create_FFSContext_FM(FMContext fmc)904 create_FFSContext_FM(FMContext fmc)
905 {
906     FFSContext c;
907     c = (FFSContext) malloc((size_t) sizeof(*c));
908     init_float_formats();
909     if (fmc == NULL) {
910         fmc = create_FMcontext();
911     } else {
912         add_ref_FMcontext(fmc);
913     }
914     c->fmc = fmc;
915     c->handle_list_size = 0;
916     c->handle_list = NULL;
917     c->tmp.tmp_buffer = NULL;
918     c->tmp.tmp_buffer_size = 0;
919     c->tmp.tmp_buffer_in_use_size = 0;
920 
921     return c;
922 }
923 
924 extern FMContext
FMContext_from_FFS(FFSContext c)925 FMContext_from_FFS(FFSContext c)
926 {
927     return c->fmc;
928 }
929 
930 extern FMFormat
FMFormat_of_original(FFSTypeHandle h)931 FMFormat_of_original(FFSTypeHandle h)
932 {
933     return h->body;
934 }
935 
936 extern void
free_FFSContext(FFSContext c)937 free_FFSContext(FFSContext c)
938 {
939     int i;
940     free(c->tmp.tmp_buffer);
941     for (i = 0; i < c->handle_list_size; i++) {
942 	if (c->handle_list[i]) free_FFSTypeHandle(c->handle_list[i]);
943     }
944     free(c->handle_list);
945     free_FMcontext(c->fmc);
946     free(c);
947 }
948 
949 static void
reset_prior_conversions(FFSContext c)950 reset_prior_conversions(FFSContext c)
951 {
952     int i;
953     for (i=0; i < c->handle_list_size; i++) {
954 	if (c->handle_list[i] != NULL) {
955 	    c->handle_list[i]->status = not_checked;
956 	}
957     }
958 }
959 
960 extern FFSTypeHandle
FFSset_fixed_target(FFSContext c,FMStructDescList struct_list)961 FFSset_fixed_target(FFSContext c, FMStructDescList struct_list)
962 {
963     FMFormat fmf = register_data_format(c->fmc, struct_list);
964     int index;
965     FFSTypeHandle handle;
966     index = fmf->format_index;
967     handle = FFSTypeHandle_by_index(c, index);
968     handle->is_fixed_target = 1;
969     /* any new target may invalidate prior conversion decisions */
970     reset_prior_conversions(c);
971     return handle;
972 }
973 
974 extern FFSTypeHandle
FFSset_simple_target(FFSContext c,char * format_name,FMFieldList field_list,int struct_size)975 FFSset_simple_target(FFSContext c, char *format_name, FMFieldList field_list, int struct_size)
976 {
977     FMStructDescRec struct_list[2];
978     struct_list[0].format_name = format_name;
979     struct_list[0].field_list = field_list;
980     struct_list[0].struct_size = struct_size;
981     struct_list[0].opt_info = NULL;
982     struct_list[1].format_name = NULL;
983     struct_list[1].field_list = NULL;
984     return FFSset_fixed_target(c, &struct_list[0]);
985 }
986 
987 /*
988  * inputs:
989  *  1.  maybe --> where data is now, base & variant
990  *  2.  where we want data : base
991  *  3.  should variant be buffered or go with base?
992  *  5.  input_record_len
993  *
994  * outputs:
995  *  1.  where data should be read into: base & variant
996  *              - or -
997  *      if and to where data should be moved: base & variant
998  *  2.  source address for conversion
999  *  3.  dest address for conversion
1000  *  4.  src string address
1001  *  5.  final string address
1002  *  6.  base_string_offset
1003  */
1004 typedef struct _conversion_action {
1005     char *cur_base;		/* where record is now (NULL if not in
1006 				 * mem) */
1007     char *cur_variant;		/* where variant part is now (NULL if not
1008 				 * in mem) */
1009     char *final_base;		/* where record should go (NULL if tmp
1010 				 * buffer) */
1011     int variant_with_base;	/* true if variant should end up contig
1012 				 * w/base */
1013 
1014 /* outputs */
1015 /* iovector read_iov[2]; int    read_icount; */
1016     void *src_address;
1017     void *dest_address;
1018     void *src_string_address;
1019     void *final_string_address;
1020     int base_string_offset;
1021 } conversion_action, *conversion_action_ptr;
1022 
1023 static int
in_place_base_conversion_possible(conv)1024 in_place_base_conversion_possible(conv)
1025 IOConversionPtr conv;
1026 {
1027     switch (conv->conversion_type) {
1028     case buffer_and_convert:
1029 	/*
1030 	 * Buffer_and_convert differs from Copy_Strings in that it
1031 	 * means no size-changing conversions need be done on the
1032 	 * variant part of the record.
1033 	 */
1034 	return FALSE;		/* no in-place conversion */
1035     case copy_dynamic_portion:
1036 	/*
1037 	 * Copy_Strings differs from Buffer_and_convert in that it
1038 	 * means size-changing conversions are required for the
1039 	 * variant part of the record.
1040 	 */
1041 	return FALSE;		/* no in-place conversion */
1042     case none_required:
1043     case direct_to_mem:
1044 	return TRUE;
1045     default:
1046 	assert(FALSE);
1047     }
1048     /* NOTREACHED */
1049     return FALSE;
1050 }
1051 
1052 static int
in_place_variant_conversion_possible(conv)1053 in_place_variant_conversion_possible(conv)
1054 IOConversionPtr conv;
1055 {
1056     switch (conv->conversion_type) {
1057     case copy_dynamic_portion:
1058 	/*
1059 	 * Copy_Strings differs from Buffer_and_convert in that it
1060 	 * means size-changing conversions are required for the
1061 	 * variant part of the record.
1062 	 */
1063 	return FALSE;		/* no in-place conversion */
1064     case buffer_and_convert:
1065 	/*
1066 	 * Buffer_and_convert differs from Copy_Strings in that it
1067 	 * means no size-changing conversions need be done on the
1068 	 * variant part of the record.
1069 	 */
1070 	return TRUE;		/* yes, variant in-place conversion is
1071 				 * possible */
1072     case none_required:
1073     case direct_to_mem:
1074 	return TRUE;
1075     default:
1076 	assert(FALSE);
1077     }
1078     /* NOTREACHED */
1079     return FALSE;
1080 }
1081 
1082 extern int
decode_in_place_possible(FFSTypeHandle format)1083 decode_in_place_possible(FFSTypeHandle format)
1084 {
1085     return FFSdecode_in_place_possible(format);
1086 }
1087 
1088 extern int
FFSdecode_in_place_possible(FFSTypeHandle format)1089 FFSdecode_in_place_possible(FFSTypeHandle format)
1090 {
1091     if (format->conversion != NULL) {
1092 	if (format->body->variant) {
1093 	    return in_place_base_conversion_possible(format->conversion) &&
1094 		in_place_variant_conversion_possible(format->conversion);
1095 	} else {
1096 	    return in_place_base_conversion_possible(format->conversion);
1097 	}
1098     } else {
1099 	return 0;
1100     }
1101 }
1102 
1103 #define expand_size_to_align(size) ((((size) & 0x7) == 0) ? (size) : (((size) + 8) & (int) -8))
1104 
1105 static int
set_conversion_params(ioformat,input_record_len,conv,params)1106 set_conversion_params(ioformat, input_record_len, conv, params)
1107 FFSTypeHandle ioformat;
1108 int input_record_len;
1109 IOConversionPtr conv;
1110 conversion_action_ptr params;
1111 {
1112     FFSContext c = ioformat->context;
1113     int final_base_size;
1114     int src_base_size;
1115     int possible_converted_variant_size;
1116     int orig_variant_size;
1117 
1118     long dest_offset;
1119     void *dest_address;
1120     long src_offset;
1121     void *src_address;
1122     long src_string_offset;
1123     void *src_string_address;
1124     long final_string_offset;
1125     void *final_string_address;
1126 
1127     final_base_size = expand_size_to_align(ioformat->body->record_length + conv->base_size_delta);
1128     src_base_size = expand_size_to_align(ioformat->body->record_length);
1129     possible_converted_variant_size =
1130 	final_variant_size_for_record(input_record_len, conv);
1131     orig_variant_size = input_record_len - expand_size_to_align(ioformat->body->record_length);
1132 
1133     make_tmp_buffer(&c->tmp, 0);
1134     /* set base dest values */
1135     if (params->final_base == NULL) {
1136 	/* need memory for at least the base record in temp area */
1137 	int buffer_required = Max(final_base_size, src_base_size);
1138 	dest_offset = add_to_tmp_buffer(&c->tmp, buffer_required);
1139 	dest_address = NULL;
1140 	if (dest_offset == -1) return 0;
1141     } else {
1142 	dest_address = params->final_base;
1143 	dest_offset = 0;
1144     }
1145 
1146     /* set base src values */
1147     if (in_place_base_conversion_possible(conv)) {
1148 	/*
1149 	 * we can convert in place, so just use the already determined
1150 	 * destination for the src values
1151 	 */
1152 	src_offset = dest_offset;
1153 	src_address = dest_address;
1154     } else {
1155 	/* no converting in place, so source must be different than base */
1156 	if ((params->cur_base == NULL) ||
1157 	    (params->cur_base == (char *) dest_address)) {
1158 	    /*
1159 	     * either the source is not in memory or it is the same as
1160 	     * where we want the record to end up.  Need temporary space.
1161 	     */
1162 	    int source_base_size = expand_size_to_align(ioformat->body->record_length);
1163 	    src_offset = add_to_tmp_buffer(&c->tmp, source_base_size);
1164 	    src_address = NULL;
1165 	    if (src_offset == -1) return 0;
1166 	} else {
1167 	    src_offset = 0;
1168 	    src_address = params->cur_base;
1169 	}
1170     }
1171 
1172     /* set final string address */
1173     if ((params->final_base == NULL) || (!params->variant_with_base)) {
1174 	/*
1175 	 * either they didn't specified a specific base address, or they said
1176 	 * to put the variant in temporary memory.  Either way, we need
1177 	 * temporary memory for the final variant part.
1178 	 *
1179 	 * NOTE: the record length may have provided padding essential to the
1180 	 * alignment of variant arrays in the string area.  Get a little extra
1181 	 * memory so we can modify the base if necessary.
1182 	 */
1183 	int align_pad = (8 - ioformat->body->record_length) & 0x7;
1184 	int buffer_required = Max(possible_converted_variant_size + align_pad,
1185 				  orig_variant_size + align_pad);
1186 	buffer_required = expand_size_to_align(buffer_required);
1187 	final_string_offset = add_to_tmp_buffer(&c->tmp, buffer_required);
1188 	final_string_address = NULL;
1189 	if (final_string_offset == -1) return 0;
1190     } else {
1191 	final_string_offset = 0;
1192 	final_string_address =
1193 	    params->final_base + expand_size_to_align(ioformat->body->record_length +
1194 							  conv->base_size_delta);
1195     }
1196 
1197     /* set variant src values */
1198     if (in_place_variant_conversion_possible(conv)) {
1199 	/*
1200 	 * we can convert in place, so just use the already determined
1201 	 * destination for the src values
1202 	 */
1203 	src_string_offset = final_string_offset;
1204 	src_string_address = final_string_address;
1205     } else {
1206 	/* no converting in place, so source must be different than base */
1207 	if ((params->cur_variant == NULL) ||
1208 	    (params->cur_base == (char *) dest_address)) {
1209 	    /*
1210 	     * either the source is not in memory or it is the same as
1211 	     * where we want the record to end up.  Need temporary space.
1212 	     */
1213 	    int source_variant_size =	/* plus possible alignment of 8 */
1214 		input_record_len - ioformat->body->record_length + 8;
1215 	    src_string_offset = add_to_tmp_buffer(&c->tmp, source_variant_size);
1216 	    src_string_address = NULL;
1217 	    if (src_string_offset == -1) return 0;
1218 	} else {
1219 	    src_string_offset = 0;
1220 	    src_string_address = params->cur_variant;
1221 	}
1222     }
1223     if (dest_address == NULL) {
1224 	params->dest_address = (char *) c->tmp.tmp_buffer + dest_offset;
1225     } else {
1226 	params->dest_address = dest_address;
1227     }
1228     if (src_address == NULL) {
1229 	params->src_address = (char *) c->tmp.tmp_buffer + src_offset;
1230     } else {
1231 	params->src_address = src_address;
1232     }
1233     if (final_string_address == NULL) {
1234 	params->final_string_address = (char *) c->tmp.tmp_buffer + final_string_offset;
1235     } else {
1236 	params->final_string_address = final_string_address;
1237     }
1238     if (src_string_address == NULL) {
1239 	params->src_string_address = (char *) c->tmp.tmp_buffer + src_string_offset;
1240     } else {
1241 	params->src_string_address = src_string_address;
1242     }
1243     return 1;
1244 }
1245 
1246 static int
final_variant_size_for_record(input_record_len,conv)1247 final_variant_size_for_record(input_record_len, conv)
1248 int input_record_len;
1249 IOConversionPtr conv;
1250 {
1251     return (int) ((input_record_len - conv->ioformat->body->record_length)
1252 		  * conv->max_var_expansion);
1253 }
1254 
1255 extern int
FFS_decode_length_format(FFSContext context,FFSTypeHandle ioformat,long record_length)1256 FFS_decode_length_format(FFSContext context, FFSTypeHandle ioformat,
1257 			 long record_length)
1258 {
1259     IOConversionPtr conv;
1260     int variant_part, final_base_size, src_base_size;
1261 
1262     if (ioformat == NULL)
1263 	return -1;
1264     conv = ioformat->conversion;
1265     if (!ioformat->conversion)
1266 	return record_length;
1267     variant_part = final_variant_size_for_record(record_length,
1268 						 ioformat->conversion);
1269     final_base_size = expand_size_to_align(ioformat->body->record_length +
1270 					   conv->base_size_delta);
1271     src_base_size = expand_size_to_align(ioformat->body->record_length);
1272     return variant_part + Max(final_base_size, src_base_size);
1273 }
1274 
1275 extern long
1276 FFS_est_decode_length(context, src, record_length)
1277 FFSContext context;
1278 char *src;
1279 long record_length;
1280 {
1281     FFSTypeHandle ioformat = FFSTypeHandle_from_encode(context, src);
1282     return FFS_decode_length_format(context, ioformat, record_length);
1283 }
1284 
1285 extern int
FFSheader_size(FFSTypeHandle ioformat)1286 FFSheader_size(FFSTypeHandle ioformat)
1287 {
1288     int header_size = ioformat->body->server_ID.length;
1289     int align_pad;
1290     if (ioformat->body->variant) {
1291 	header_size += sizeof(FILE_INT);
1292     }
1293     align_pad = (8 - header_size) & 0x7;
1294     return header_size + align_pad;
1295 }
1296 
1297 extern
1298 int
1299 FFShas_conversion(ioformat)
1300 FFSTypeHandle ioformat;
1301 {
1302     return (ioformat->conversion != NULL);
1303 }
1304 
1305 static int
FFSinternal_decode(ioformat,src,dest,to_buffer)1306 FFSinternal_decode(ioformat, src, dest, to_buffer)
1307 FFSTypeHandle ioformat;
1308 char *src;			/* incoming data to be decoded */
1309 void *dest;			/* area to hold decoded data */
1310 int to_buffer;
1311 {
1312     FFSContext iofile = ioformat->context;
1313     IOConversionPtr conv;
1314     int input_record_len;
1315     IOConversionStruct null_conv;
1316     int align_pad;
1317     int header_size = FFSheader_size(ioformat);
1318     int data_align_pad;
1319     conversion_action params;
1320 
1321     conv = ioformat->conversion;
1322 
1323     if (conv == NULL) {
1324 	null_conv.conversion_type = none_required;
1325 	null_conv.max_var_expansion = 1.0;
1326 	null_conv.conv_count = 0;
1327 	null_conv.base_size_delta = 0;
1328 	null_conv.context = iofile;
1329 	null_conv.ioformat = ioformat;
1330 	null_conv.native_field_list = NULL;
1331 	conv = &null_conv;
1332     }
1333     if (iofile != conv->context) {
1334 	fprintf(stderr, "IOFile and conversion mismatch\n");
1335 	return -1;
1336     }
1337     if (ioformat == NULL)
1338 	return 0;
1339 
1340     if (ioformat->body->variant) {
1341 	FILE_INT record_len;
1342 	int len_align_pad = (4 - ioformat->body->server_ID.length) & 3;
1343 	FILE_INT *len_ptr = (FILE_INT *) (src + ioformat->body->server_ID.length +
1344 					  len_align_pad);
1345 	memcpy(&record_len, len_ptr, sizeof(FILE_INT));
1346 	if (ioformat->body->byte_reversal)
1347 	    byte_swap((char *) &record_len, 4);
1348 	input_record_len = record_len;
1349     } else {
1350 	input_record_len = ioformat->body->record_length;
1351     }
1352     align_pad = (8 - header_size) & 0x7;
1353     header_size += align_pad;
1354     data_align_pad = (8 - ioformat->body->record_length) & 0x7;
1355 
1356     params.cur_base = src + header_size;
1357     params.cur_variant = params.cur_base + ioformat->body->record_length +
1358 	data_align_pad;
1359     params.final_base = dest;
1360     params.variant_with_base = to_buffer;
1361     if (!set_conversion_params(ioformat, input_record_len, conv, &params))
1362 	return 0;
1363 
1364     /* update stats
1365     iofile->stats.decode_bytes += input_record_len;
1366     iofile->stats.decode_msg_count++;*/
1367 
1368     if (params.src_address != params.cur_base) {
1369 	memcpy(params.src_address, params.cur_base, ioformat->body->record_length);
1370     }
1371     if (params.src_string_address != params.cur_variant) {
1372 	if (input_record_len - ioformat->body->record_length - data_align_pad > 0) {
1373 	    memcpy(params.src_string_address, params.cur_variant,
1374 		   input_record_len - ioformat->body->record_length - data_align_pad);
1375 	}
1376     }
1377     if (conv->conversion_type != none_required) {
1378 	FFSconvert_record(conv, params.src_address, params.dest_address,
1379 			 params.final_string_address,
1380 			 params.src_string_address);
1381     }
1382     return 1;
1383 }
1384 
1385 static int
check_conversion(ioformat)1386 check_conversion(ioformat)
1387 FFSTypeHandle ioformat;
1388 {
1389     if (ioformat->conversion == NULL) {
1390 	if (ioformat->status == not_checked) {
1391 	    FFS_determine_conversion(ioformat->context, ioformat);
1392 	}
1393 	if (ioformat->status == none_available) {
1394 	    fprintf(stderr, "FFS Warning:  Attempting to decode when no conversion has been set.  \n  Record is of type \"%s\", ioformat 0x%lx.\n  No data returned.\n",
1395 		    ioformat->body->format_name, (long) ioformat);
1396 	    ioformat->status = none_available;
1397 	    return 0;
1398 	}
1399     }
1400     return 1;
1401 }
1402 
1403 extern int
1404 FFSdecode(iocontext, src, dest)
1405 FFSContext iocontext;
1406 char *src;			/* incoming data to be decoded */
1407 char *dest;			/* area to hold decoded data */
1408 {
1409     FFSTypeHandle ioformat;
1410     ioformat = FFSTypeHandle_from_encode(iocontext, src);
1411     if (ioformat == NULL) {
1412 	return 0;
1413     }
1414     if (!check_conversion(ioformat)) {
1415 	return 0;
1416     }
1417     return FFSinternal_decode(ioformat, src, dest, 0);
1418 }
1419 
1420 extern int
1421 FFSdecode_in_place(iocontext, src, dest_ptr)
1422 FFSContext iocontext;
1423 char *src;			/* incoming data to be decoded */
1424 void **dest_ptr;		/* area to hold pointer to decoded data */
1425 {
1426     FFSTypeHandle ioformat = FFSTypeHandle_from_encode(iocontext, src);
1427     int header_size;
1428     int ret;
1429 
1430     if (ioformat == NULL) {
1431 	return 0;
1432     }
1433     if (!check_conversion(ioformat)) {
1434 	*dest_ptr = NULL;
1435 	return 0;
1436     }
1437     header_size = FFSheader_size(ioformat);
1438     ret = FFSinternal_decode(ioformat, src, src + header_size, 1);
1439     *dest_ptr = src + header_size;
1440     return ret;
1441 }
1442 
1443 extern int
1444 FFSdecode_to_buffer(iocontext, src, dest)
1445 FFSContext iocontext;
1446 char *src;			/* incoming data to be decoded */
1447 void *dest;			/* area to hold decoded data */
1448 {
1449     FFSTypeHandle ioformat;
1450     ioformat = FFSTypeHandle_from_encode(iocontext, src);
1451     if (ioformat == NULL) {
1452 	return 0;
1453     }
1454     if (!check_conversion(ioformat)) {
1455 	return 0;
1456     }
1457     return FFSinternal_decode(ioformat, src, dest, 1);
1458 }
1459 
1460 extern FFSTypeHandle
1461 FFS_target_from_encode(c, data)
1462 FFSContext c;
1463 char *data;			/* incoming data to be decoded */
1464 {
1465     FFSTypeHandle f;
1466     /* first element in encoded buffer is format ID */
1467     f = FFSTypeHandle_from_encode(c, data);
1468     if (f == NULL) return NULL;
1469     if (f->status == not_checked) {
1470 	FFS_determine_conversion(c, f);
1471     }
1472     if (f->status == none_available) return NULL;
1473     if (f->status == conversion_set) return f->conversion_target;
1474     assert(0);
1475     return NULL;
1476 }
1477 
1478 static void
byte_swap(data,size)1479 byte_swap(data, size)
1480 char *data;
1481 int size;
1482 {
1483     int i;
1484     assert((size % 2) == 0);
1485     for (i = 0; i < size / 2; i++) {
1486 	char tmp = data[i];
1487 	data[i] = data[size - i - 1];
1488 	data[size - i - 1] = tmp;
1489     }
1490 }
1491 
1492 char *
FFSTypeHandle_name(FFSTypeHandle f)1493 FFSTypeHandle_name(FFSTypeHandle f)
1494 {
1495     return f->body->format_name;
1496 }
1497 
1498 #define TMP_BUFFER_INIT_SIZE 1024
1499 
1500 FFSBuffer
create_FFSBuffer()1501 create_FFSBuffer()
1502 {
1503     FFSBuffer buf = malloc(sizeof(struct _FFSBuffer));
1504     buf->tmp_buffer = NULL;
1505     buf->tmp_buffer_size = 0;
1506     buf->tmp_buffer_in_use_size = 0;
1507     return buf;
1508 }
1509 
1510 FFSBuffer
create_fixed_FFSBuffer(char * buffer,int size)1511 create_fixed_FFSBuffer(char *buffer, int size)
1512 {
1513     FFSBuffer buf = malloc(sizeof(struct _FFSBuffer));
1514     buf->tmp_buffer = buffer;
1515     buf->tmp_buffer_size = -size;
1516     buf->tmp_buffer_in_use_size = 0;
1517     return buf;
1518 }
1519 
1520 void
free_FFSBuffer(buf)1521 free_FFSBuffer(buf)
1522 FFSBuffer buf;
1523 {
1524     if ((buf->tmp_buffer_size > 0) && buf->tmp_buffer)
1525 	free(buf->tmp_buffer);
1526     free(buf);
1527 }
1528 
1529 extern
1530 char *
1531 make_tmp_buffer(buf, size)
1532 FFSBuffer buf;
1533 int size;
1534 {
1535     if (buf->tmp_buffer_size < 0) {
1536 	/* fixed size buffer */
1537 	if (size > (-buf->tmp_buffer_size)) return NULL;
1538 	return buf->tmp_buffer;
1539     }
1540     if (buf->tmp_buffer_size == 0) {
1541 	int tmp_size = Max(size, TMP_BUFFER_INIT_SIZE);
1542 	buf->tmp_buffer = malloc(tmp_size);
1543 	buf->tmp_buffer_size = tmp_size;
1544     }
1545     if (size > buf->tmp_buffer_size) {
1546 	buf->tmp_buffer = realloc(buf->tmp_buffer, size);
1547 	if (buf->tmp_buffer) {
1548 	    buf->tmp_buffer_size = size;
1549 	} else {
1550 	    buf->tmp_buffer_size = 0;
1551 	}
1552     }
1553     buf->tmp_buffer_in_use_size = size;
1554     return buf->tmp_buffer;
1555 }
1556 
1557 static
1558 long
add_to_tmp_buffer(buf,size)1559 add_to_tmp_buffer(buf, size)
1560 FFSBuffer buf;
1561 int size;
1562 {
1563     long old_size = buf->tmp_buffer_in_use_size;
1564     size += old_size;
1565 
1566     if (buf->tmp_buffer_size < 0) {
1567 	/* fixed size buffer */
1568 	if (size > (-buf->tmp_buffer_size)) return -1;
1569     } else {
1570 	if (buf->tmp_buffer_size == 0) {
1571 	    int tmp_size = Max(size, TMP_BUFFER_INIT_SIZE);
1572 	    buf->tmp_buffer = malloc(tmp_size);
1573 	}
1574 	if (size > buf->tmp_buffer_size) {
1575 	    buf->tmp_buffer = realloc(buf->tmp_buffer, size);
1576 	    buf->tmp_buffer_size = size;
1577 	}
1578     }
1579     if (!buf->tmp_buffer) {
1580 	buf->tmp_buffer_size = 0;
1581 	return -1;
1582     } else {
1583 	buf->tmp_buffer_in_use_size = size;
1584     }
1585 
1586     return old_size;
1587 }
1588 
1589 #if SIZEOF_LONG != 8
1590 static int words_bigendian = -1;
1591 
1592 static int
set_bigendian()1593 set_bigendian () {
1594   /* Are we little or big endian?  From Harbison&Steele.  */
1595   union
1596   {
1597     long l;
1598     char c[sizeof (long)];
1599   } u;
1600   u.l = 1;
1601   words_bigendian = (u.c[sizeof (long) - 1] == 1);
1602   return words_bigendian;
1603 }
1604 
1605 #define WORDS_BIGENDIAN ((words_bigendian == -1) ? set_bigendian() : words_bigendian)
1606 #endif
1607 
1608 static unsigned long
quick_get_ulong(iofield,data)1609 quick_get_ulong(iofield, data)
1610 FMFieldPtr iofield;
1611 void *data;
1612 {
1613     data = (void *) ((char *) data + iofield->offset);
1614     /* only used when field type is an integer and aligned by its size */
1615     switch (iofield->size) {
1616     case 1:
1617 	return (unsigned long) (*((unsigned char *) data));
1618     case 2:
1619 	return (unsigned long) (*((unsigned short *) data));
1620     case 4:
1621 	return (unsigned long) (*((unsigned int *) data));
1622     case 8:
1623 #if SIZEOF_LONG == 8
1624 	if ((((long) data) & 0x0f) == 0) {
1625 	    /* properly aligned */
1626 	    return (unsigned long) (*((unsigned long *) data));
1627 	} else {
1628 	    union {
1629 		unsigned long tmp;
1630 		int tmpi[2];
1631 	    } u;
1632 	    u.tmpi[0] = ((int *) data)[0];
1633 	    u.tmpi[1] = ((int *) data)[1];
1634 	    return u.tmp;
1635 	}
1636 #else
1637 	/* must be fetching 4 bytes of the 8 available */
1638 	if (WORDS_BIGENDIAN)
1639 	    return (*(((unsigned long *) data) +1));
1640 	else
1641 	    return (*((unsigned long *) data));
1642 
1643 #endif
1644     }
1645     return 0;
1646 }
1647 
1648 static void *
quick_get_pointer(iofield,data)1649 quick_get_pointer(iofield, data)
1650 FMFieldPtr iofield;
1651 void *data;
1652 {
1653     union {
1654 	void *p;
1655 	unsigned long tmp;
1656 	int tmpi[2];
1657     } u;
1658     data = (void *) ((char *) data + iofield->offset);
1659     /* only used when field type is an integer and aligned by its size */
1660     switch (iofield->size) {
1661     case 1:
1662 	u.tmp = (unsigned long) (*((unsigned char *) data));
1663 	break;
1664     case 2:
1665 	u.tmp = (unsigned long) (*((unsigned short *) data));
1666 	break;
1667     case 4:
1668     {
1669 	unsigned int tmpi;
1670 	memcpy(&tmpi, data, 4);
1671 	u.tmp = (unsigned long) tmpi;
1672 	break;
1673     }
1674     case 8:
1675 #if SIZEOF_LONG == 8
1676 	memcpy(&u.p, data, 8);
1677 #else
1678 	{
1679 	  int tmp;
1680 	  /* must be fetching 4 bytes of the 8 available */
1681 	  if (WORDS_BIGENDIAN)
1682 	    memcpy(&tmp, data + 4, 4);
1683 	  else
1684 	    memcpy(&tmp, data, 4);
1685 	  u.tmp = (unsigned long) tmp;
1686 	}
1687 #endif
1688 	break;
1689     }
1690     return u.p;
1691 }
1692 
1693 void
quick_put_ulong(iofield,value,data)1694 quick_put_ulong(iofield, value, data)
1695 FMFieldPtr iofield;
1696 unsigned long value;
1697 void *data;
1698 {
1699     data = (void *) ((char *) data + iofield->offset);
1700     /* only used when field type is an integer and aligned by its size */
1701     switch (iofield->size) {
1702     case 1:
1703 	*((unsigned char *) data) = (unsigned char) value;
1704 	break;
1705     case 2:
1706 	*((unsigned short *) data) = (unsigned short) value;
1707 	break;
1708     case 4:{
1709 	unsigned int tmp = (unsigned int) value;
1710 	memcpy(data, &value, 4);
1711 	break;
1712 	}
1713     case 8:{
1714 	unsigned long tmp = value;
1715 	memcpy(data, &value, 8);
1716 	break;
1717 	}
1718     }
1719 }
1720 
1721