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, ¶ms))
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