source: trunk/MagicSoft/Simulation/Corsika/Mmcs614/eventio.c

Last change on this file was 1444, checked in by blanch, 22 years ago
*** empty log message ***
File size: 101.2 KB
Line 
1/**
2 * @file eventio.c
3 * @short Basic functions for eventio data format.
4 *
5 * @author Konrad Bernloehr
6 * @date 1991 to 2000
7 * $Date: 2002-07-25 17:52:42 $
8 * $Revision: 1.1 $
9
10@verbatim
11 ================ General comments to eventio.c ======================
12
13 'eventio.c' provides an interface for an (almost) machine-independent
14 way to write and read event data, configuration data and Monte Carlo data.
15 Byte ordering of the data is unimportant and data written in both
16 byte orders are correctly read on any supported architecture.
17 Usually the data is written to/read from a file (or separate files for
18 different data types) to be opened before calling any eventio function.
19 Other ways to 'save' data (e.g. into memory or via dedicated networking
20 procedures can easily be incorporated by assigning an input and/or
21 output function to an I/O buffer instead of a file handle or pointer.
22 The data structure is designed to allow reading of a mixture of
23 different types of items from a single file. For this purpose, 'items'
24 (see below) should not be interspersed with low-level material and,
25 therefore, low-level functions should not be called from anywhere
26 outside eventio.c.
27
28 -----------------------------------------------------------------------
29
30 An 'item' has the following structure:
31
32 Component Type Content Description
33 --------- ---- ------- -----------
34 sync-tag long 0xD41F8A37 Signature of start of any item
35 (only for top item, not for sub-items).
36 type/version long ... Item type (bits 0 to 15), reserved bits
37 (16 to 19), and version of this item
38 type (bits 20 to 31).
39 ident long ... Unique identification number of the
40 item or -1.
41 length long ... No. of bytes following for this item
42 (bits 0 to 29) and a flag indicating
43 whether the item consists entirely of
44 sub-items with known length (bit 30).
45 Bit 31 must be 0. The bytes needed
46 to pad the item to the next 4-byte
47 boundary are included in the length.
48 data ... ... Item data (may consist of elementary
49 data and of sub-items)
50
51 Field 'sync-tag':
52 The sync-tag is used to check that input is still synchronized.
53 In the case of a synchronisation failure, all data should be skipped
54 up to the next occurence of that byte combination or its reverse.
55 The byte ordering of the sync-tag defines also the byte ordering
56 of all data in the item. Only byte orders 0-1-2-3 and 3-2-1-0 are
57 accepted at present.
58
59 Field 'type/version':
60 This field consists of a type number in bits 0 to 15 (values
61 0 to 65535), reserved bits 16 to 19 (must be 0), and an item
62 version number in bits 20 to 31 (values 0 to 4095). Whenever the
63 format of an item changes in a way which is incompatible with
64 older reading software the version number has to be increased.
65
66 Field 'ident':
67 Items of the same type can be distinguished if an identification
68 number is supplied. Negative values are interpreted as 'no ident
69 supplied'.
70
71 Field 'length':
72 Each item and sub-item must have the number of bytes in its
73 data area, including padding bytes, in bits 0 to 30 of this field.
74 If an item consists entirely of sub-items and no atomic data, it can
75 be searched for a specific type of sub-item without having to 'decode'
76 (read from the buffer) any of the sub-items. Such an item is kind of
77 a directory of sub-items and is marked by setting bit 30 of the
78 length field on. The longest possible item length is thus (2^30 - 1).
79 Note that the length field specifies the length of the rest of the
80 item but not the sync-tag, type/version number, and length fields.
81 All (sub-) items are padded to make the total length a multiple of 4
82 bytes and the no. of padded bytes must be included in 'length'.
83
84 Data:
85 Data of an item may be either sub-items or atomic data. An item may
86 even consist of a mixture of both but in that case the sub-items
87 are not accessible via 'directory' functions and can be processed
88 only when the item data is 'decoded' by its corresponding 'read_...'
89 function.
90 The beginning of the data field is aligned on a 4-byte boundary to
91 allow efficient access to data if the byte order needs not to be
92 changed and if the data itself obeys the required alignment.
93
94 -----------------------------------------------------------------------
95
96 The 'atomic' data types are kept as close as possible to internal
97 data types. This data is only byte-aligned unless all atomic data
98 of an item obeys a 2-byte or 4-byte alignement.
99 Note that the ANSI C internal type int32_t typically corresponds to
100 both 'int' and 'long' on 32-bit machines but to 'int' only on
101 64-bit machines and to 'long' only on 16-bit systems.
102 Use the int32_t/uint32_t etc. types where the same length of
103 internal variables is required.
104 64-bit integers are not yet implemented in eventio.
105
106 Type Int. type Size (bytes) Comments
107 ---- --------- ------------ --------
108 byte [u]int8_t 1 Character or very short integer.
109 short [u]int16_t 2 Short integer (signed or unsigned).
110 long [u]int32_t 4 Long integer (signed or unsigned).
111 int64 [u]int64_t 8 Caution: not available on all systems.
112 string - 2+length Preceded by 2-byte length of string.
113 long str. - 4+length Preceded by 4-byte length of string.
114 real float 4 32-bit IEEE floating point number with
115 the same byte order as a long integer.
116 double double 8 64-bit IEEE floating point number.
117
118 The byte-ordering of integers in input data is defined by that of
119 the sync-tag (magic number) preceding top-level items. Therefore,
120 the byte-ordering in a top-level item may differ from the ordering
121 in a previous item. For output data the default ordering is so far to
122 have the least-significant bytes first. This is the natural byte
123 order on Mips R3000 and higher (under Ultrix), DEC Alpha, VAX, and Intel
124 (80)x86 CPUs but the inverse of the natural byte order on Motorola 680x0,
125 RS6000, PowerPC, and Sparc CPUs. The ordering may change without
126 notice and without changing version numbers. Except for performance
127 considerations, the byte-ordering should not be relevant as long as
128 only the 0-1-2-3 and 3-2-1-0 orders are considered, and byte ordering
129 of floating point numbers is the same as for long integers.
130 Byte ordering for writing may be changed during run-time with the
131 'byte_order' element of the I/O buffer structure.
132 Note that on CPUs with non-IEEE floating point format like VAX writing
133 and reading of floating point numbers is likely to be less efficient
134 than on IEEE-format CPUs.
135
136 Note that if an 'int' variable is written via 'put_short()'
137 and then read again via 'get_short()' not only the
138 upper two bytes (on a 32-bit machine) are lost but
139 also the sign bit is propagated from bit 15 to the
140 upper 16 bits. Similarly, if a 'long' variable is written
141 via 'put_long()' and later read via 'get_long()' on a
142 64-bit-machine, not only the upper 4 bytes are lost but
143 also the sign in bit 31 is propagated to the upper 32 bits.
144
145 -----------------------------------------------------------------------
146
147 Do not modify this file to include project-specific things!
148
149 ====================================================================
150@endverbatim
151*/
152
153#include "initial.h" /* This file includes others as required. */
154#define NO_FOREIGN_PROTOTYPES 1
155#include "io_basic.h" /* This file includes others as required. */
156#ifndef FSTAT_NOT_AVAILABLE
157#include <sys/types.h>
158#include <sys/stat.h>
159#endif
160#ifdef OS_UNIX
161#include <unistd.h>
162#endif
163
164#define IO_BUFFER_MINIMUM_SIZE 32L
165
166/* Author: Konrad Bernloehr */
167
168/* #define READ_BYTES(fd,buf,nb) read(fd,buf,nb) */
169/* #define READ_BYTES(fd,buf,nb) fread(buf,1,nb,&_iob[fd]) */
170#define READ_BYTES(fd,buf,nb) ((fd==0) ? \
171 fread((void *)buf,(size_t)1,(size_t)nb,stdin) : read(fd,buf,(size_t)nb))
172
173/* ----------------------- allocate_io_buffer ------------------ */
174/**
175 * @short Dynamic allocation of an I/O buffer.
176 *
177 * Dynamic allocation of an I/O buffer. The actual length of
178 * the buffer is passed as an argument.
179 * The buffer descriptor is initialized.
180 *
181 * @param buflen The length of the actual buffer in bytes.
182 * A safety margin of 4 bytes is added.
183 *
184 * @return Pointer to I/O buffer or NULL if allocation failed.
185 */
186
187#ifdef ANSI_C
188IO_BUFFER *allocate_io_buffer (size_t buflen)
189#else
190IO_BUFFER *allocate_io_buffer (buflen)
191 size_t buflen;
192#endif
193{
194 IO_BUFFER *buf;
195
196 if ( sizeof(BYTE) != 1 )
197 {
198 Error("Sizes of bytes is not as expected.");
199 Error("You better modify the sources and recompile.");
200 Error("No buffers will be allocated.");
201 return NULL;
202 }
203
204 if ( sizeof(int16_t) != 2 || sizeof(int32_t) != 4 )
205 {
206 Error("Sizes of 16-bit and 32-bit integers are not as expected.");
207 Error("You better modify the sources and recompile.");
208 Error("No buffers will be allocated.");
209 return NULL;
210 }
211 if ( sizeof(uint16_t) != 2 || sizeof(uint32_t) != 4 )
212 {
213 Error("Sizes of 16-bit and 32-bit unsigned integers are not as expected.");
214 Error("You better modify the sources and recompile.");
215 Error("No buffers will be allocated.");
216 return NULL;
217 }
218#ifdef SIXTY_FOUR_BITS
219 if ( sizeof(long) != 8 )
220 {
221 Error("Size of long integers is not 64 bits as expected.");
222 Error("You better modify the sources and recompile.");
223 Error("No buffers will be allocated.");
224 return NULL;
225 }
226#else
227 if ( sizeof(long) != 4 )
228 {
229 Error("Size of long integers is not 32 bits as expected.");
230 Error("You better modify the sources and recompile.");
231 Error("No buffers will be allocated.");
232 return NULL;
233 }
234#endif
235
236 if ( (buf = (IO_BUFFER *) malloc(sizeof(IO_BUFFER))) ==
237 (IO_BUFFER *) NULL )
238 {
239 Warning("Allocating I/O buffer failed");
240 return(buf);
241 }
242
243 if ( buflen <= 0 )
244 buflen = IO_BUFFER_INITIAL_LENGTH;
245 else if ( buflen < IO_BUFFER_MINIMUM_SIZE )
246 buflen = IO_BUFFER_MINIMUM_SIZE;
247
248 /* If the allocation of the actual buffer fails, free the desciptor again */
249 if ( (buf->buffer = (BYTE *) malloc((size_t)(buflen+4))) == (BYTE *) NULL )
250 {
251 char msg[256];
252 (void) sprintf(msg,"Allocating %ld bytes for I/O buffer failed",
253 (long)((size_t)(buflen+4)));
254 Warning(msg);
255 free((void *)buf);
256 return((IO_BUFFER *) NULL);
257 }
258
259 buf->is_allocated = 1;
260
261 buf->buflen = buf->w_remaining = buflen;
262 buf->r_remaining = 0;
263 buf->data = buf->buffer;
264 buf->item_start_offset[0] = 0;
265 buf->item_level = 0;
266 buf->input_fileno = buf->output_fileno = -1;
267 buf->input_file = buf->output_file = (FILE *) NULL;
268 buf->regular = 0;
269 buf->user_function = NULL;
270 buf->item_length[0] = buf->sub_item_length[0] = 0;
271 buf->data_pending = -1;
272 buf->min_length = buflen;
273 buf->max_length = IO_BUFFER_MAXIMUM_LENGTH;
274
275#if ( defined(CPU_68K) || defined(CPU_RS6000) || defined(CPU_PowerPC) )
276# ifndef REVERSE_BYTE_ORDER
277 buf->byte_order = 1; /* Reverse byte order by default */
278# else
279 buf->byte_order = 0; /* Natural byte order if wanted */
280# endif
281#else
282# ifndef REVERSE_BYTE_ORDER
283 buf->byte_order = 0; /* Write with native byte order */
284# else
285 buf->byte_order = 1; /* Reverse byte order if wanted */
286# endif
287#endif
288
289 return(buf);
290}
291
292/* ---------------------- extend_io_buffer ------------------------- */
293/**
294 * @short Extend the dynamically allocated I/O buffer.
295 *
296 * Extend the dynamically allocated I/O buffer and if an item
297 * has been started and the argument 'next_byte' is smaller
298 * than 256 that argument will be appended as the next
299 * byte to the buffer.
300 *
301 * @param iobuf The I/O buffer descriptor
302 * @param next_byte The value of the next byte or >= 256
303 * @param increment The no. of bytes by which to increase
304 * the buffer beyond the current point.
305 * If there is remaining space for
306 * writing, the buffer is extended by
307 * less than 'increment'.
308 *
309 * @return next_byte (modulo 256) if successful, -1 for failure
310 */
311
312#ifdef ANSI_C
313int extend_io_buffer (IO_BUFFER *iobuf, unsigned next_byte, long increment)
314#else
315int extend_io_buffer (iobuf, next_byte, increment)
316 IO_BUFFER *iobuf;
317 unsigned next_byte;
318 long increment;
319#endif
320{
321 long new_length, offset, remaining;
322 BYTE *tptr;
323 static long last_failed_length;
324
325 /* NULL argument passed? */
326 if ( iobuf == (IO_BUFFER *) NULL )
327 return -1;
328 /* No buffer content? */
329 if ( iobuf->buffer == (BYTE *) NULL )
330 return -1;
331 /* Was the buffer obtained by other means than allocate_io_buffer()? */
332 if ( !iobuf->is_allocated )
333 return -1;
334 if ( increment < 1048576 && iobuf->buflen >= 8388608 )
335 increment = 1048576;
336 else if ( increment < 262144 && iobuf->buflen >= 2097152 )
337 increment = 262144;
338 else if ( increment < 131072 && iobuf->buflen >= 1048567 )
339 increment = 131072;
340 else if ( increment < 8192 )
341 increment = 8192;
342 if ( iobuf->item_level > 0 )
343 {
344 remaining = iobuf->buflen - (long) (iobuf->data-iobuf->buffer);
345 if ( remaining >= increment )
346 {
347 iobuf->w_remaining += increment;
348 if ( next_byte < 256 )
349 *(iobuf->data++) = (BYTE) next_byte;
350 return((int)next_byte&0xff);
351 }
352 else if ( increment > remaining )
353 increment -= remaining;
354 }
355
356 /* If the reallocation fails give a warning but not each time if */
357 /* this function is called many times in an output loop before the */
358 /* buffer status is actually checked. */
359 if ( (new_length = iobuf->buflen + increment) > iobuf->max_length )
360 {
361 /* The following comparison is not strictly multi-threading safe */
362 /* but is not considered a problem since it can only result in */
363 /* too many warning messages and is only encountered in rare cases. */
364 if ( iobuf->buflen != last_failed_length )
365 {
366 char msg[256];
367 last_failed_length = iobuf->buflen;
368 (void) sprintf(msg,
369 "Cannot extend I/O buffer of length %ld by another %ld bytes",
370 iobuf->buflen+4,increment);
371 Warning(msg);
372 }
373 iobuf->w_remaining = -1;
374 return -1;
375 }
376 offset = iobuf->data - iobuf->buffer;
377
378 if ( (tptr = (BYTE *)
379 realloc((void *)iobuf->buffer,(size_t)(new_length+4))) ==
380 (BYTE *) NULL )
381 {
382 char msg[256];
383 (void) sprintf(msg,
384 "Insufficient memory for extending I/O block to %ld bytes",
385 (long) ((size_t)(new_length+4)));
386 Warning(msg);
387 iobuf->w_remaining = -1;
388 return -1;
389 }
390 else
391 {
392 char msg[256];
393 sprintf(msg,"I/O block extended by %ld to %ld bytes",
394 increment,new_length+4);
395 Information(msg);
396 iobuf->buffer = tptr;
397 iobuf->data = iobuf->buffer + offset;
398 iobuf->buflen = new_length;
399 iobuf->w_remaining += increment;
400 if ( iobuf->item_level > 0 && next_byte < 256 )
401 *(iobuf->data++) = (BYTE) next_byte;
402 }
403
404 return (int)(next_byte&0xff);
405}
406
407/* ----------------------- free_io_buffer ---------------------- */
408/**
409 * @short Free an I/O buffer that has been allocated at run-time.
410 *
411 * Free an I/O buffer that has been allocated at
412 * run-time (e.g. by a call to allocate_io_buf()).
413 *
414 * @param iobuf The buffer descriptor to be de-allocated.
415 *
416 * @return (none)
417 */
418
419#ifdef ANSI_C
420void free_io_buffer (IO_BUFFER *iobuf)
421#else
422void free_io_buffer (iobuf)
423 IO_BUFFER *iobuf;
424#endif
425{
426 if ( iobuf != (IO_BUFFER *) NULL )
427 {
428 if ( iobuf->buffer != (BYTE *) NULL && iobuf->is_allocated )
429 free((void *)iobuf->buffer);
430 free((void *)iobuf);
431 }
432}
433
434/* --------------------- put_vector_of_byte -------------------- */
435/**
436 * Put a vector of bytes into an I/O buffer.
437 *
438 * @param vec Byte data vector.
439 * @param num Number of bytes to be put.
440 * @param iobuf I/O buffer descriptor.
441 *
442 * @return (none)
443 */
444
445#ifdef ANSI_C
446void put_vector_of_byte (BYTE *vec, int num, IO_BUFFER *iobuf)
447#else
448void put_vector_of_byte (vec, num, iobuf)
449 BYTE *vec;
450 int num;
451 IO_BUFFER *iobuf;
452#endif
453{
454 if ( num <= 0 )
455 return;
456
457 if ( (iobuf->w_remaining-=num) < 0 )
458 if ( extend_io_buffer(iobuf,256,(IO_BUFFER_LENGTH_INCREMENT)) < 0 )
459 return;
460
461 if ( vec == (BYTE *) NULL )
462 memset((void *)iobuf->data,0,(size_t)num);
463 else
464 COPY_BYTES((void *)iobuf->data,(void *)vec,(size_t)num);
465
466 iobuf->data += num;
467}
468
469/* --------------------- get_vector_of_byte -------------------- */
470/**
471 * Get a vector of bytes from an I/O buffer.
472 *
473 * @param vec -- Byte data vector.
474 * @param num -- Number of bytes to get.
475 * @param iobuf -- I/O buffer descriptor.
476 *
477 * @return (none)
478 */
479
480#ifdef ANSI_C
481void get_vector_of_byte (BYTE *vec, int num, IO_BUFFER *iobuf)
482#else
483void get_vector_of_byte (vec, num, iobuf)
484 BYTE *vec;
485 int num;
486 IO_BUFFER *iobuf;
487#endif
488{
489 if ( num <= 0 )
490 return;
491
492 if ( (iobuf->r_remaining-=num) < 0 )
493 return;
494
495 if ( vec != (BYTE *) NULL )
496 COPY_BYTES((void *)vec,(void *)iobuf->data,(size_t)num);
497 iobuf->data += num;
498}
499
500/* -------------------------- put_short ------------------------ */
501/**
502 * @short Put a two-byte integer on an I/O buffer.
503 *
504 * Put a two-byte integer on an I/O buffer with least
505 * significant byte first. Should be machine independent
506 * as long as 'short' and 'unsigned short' are 16-bit integers,
507 * the two's complement is used for negative numbers, and
508 * the '>>' operator does a logical shift with unsigned short.
509 * Although the 'num' argument is a 4-byte integer on most
510 * machines, the value shoud be in the range -32768 to 32767.
511 *
512 * @param num The number to be saved. Should fit into a
513 * short integer and will be truncated otherwise.
514 * @param iobuf The output buffer descriptor.
515 *
516 * @return (none)
517 */
518
519#ifdef ANSI_C
520void put_short(int num, IO_BUFFER *iobuf)
521#else
522void put_short(num,iobuf)
523 int num;
524 IO_BUFFER *iobuf;
525#endif
526{
527 union
528 {
529 int16_t sval;
530 BYTE cval[2];
531 } val[2];
532
533 if ( (iobuf->w_remaining-=2) < 0 )
534 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
535 return;
536
537 if ( iobuf->byte_order == 0)
538 val[1].sval = (int16_t) num;
539 else
540 {
541 val[0].sval = (int16_t) num;
542 val[1].cval[0] = val[0].cval[1];
543 val[1].cval[1] = val[0].cval[0];
544 }
545
546 COPY_BYTES((void *)iobuf->data,(void *)&val[1].sval,(size_t)2);
547 iobuf->data += 2;
548}
549
550/* ---------------------- put_vector_of_short --------------------- */
551/**
552 * @short Put a vector of 2-byte integers on an I/O buffer.
553 *
554 * Put a vector of 2-byte integers on an I/O buffer. This may be
555 * relaced by a more efficient but machine-dependent version later.
556 * May be called by a number of elements equal to 0. In this
557 * case, nothing is done.
558 */
559
560#ifdef ANSI_C
561void put_vector_of_short (short *vec, int num, IO_BUFFER *iobuf)
562#else
563void put_vector_of_short (vec, num, iobuf)
564 short *vec;
565 int num;
566 IO_BUFFER *iobuf;
567#endif
568{
569 REGISTER int i;
570
571 if ( vec == (short *) NULL )
572 {
573 for (i=0; i<num; i++)
574 put_short(0,iobuf);
575 return;
576 }
577
578 for (i=0; i<num; i++)
579 put_short((int)vec[i],iobuf);
580}
581
582/* ---------------------- put_vector_of_int --------------------- */
583/**
584 * @short Put a vector of integers (range -32768 to 32767) into I/O buffer.
585 *
586 * Put a vector of integers (with actual values in the range
587 * -32768 to 32767) into an I/O buffer. This may be relaced by a
588 * more efficient but machine-dependent version later.
589 */
590
591#ifdef ANSI_C
592void put_vector_of_int (int *vec, int num, IO_BUFFER *iobuf)
593#else
594void put_vector_of_int (vec, num, iobuf)
595 int *vec;
596 int num;
597 IO_BUFFER *iobuf;
598#endif
599{
600 REGISTER int i;
601
602 if ( vec == (int *) NULL )
603 {
604 for (i=0; i<num; i++)
605 put_short(0,iobuf);
606 return;
607 }
608
609 for (i=0; i<num; i++)
610 put_short(vec[i],iobuf);
611}
612
613/* ----------------- put_vector_of_uint16 ---------------------- */
614/**
615 * @short Put a vector of unsigned shorts into an I/O buffer.
616 *
617 * Put a vector of unsigned shorts into an I/O buffer with least
618 * significant byte first. The values are in the range 0 to 65535.
619 * The function should be used where sign propagation is of concern.
620 *
621 * @param uval The vector of values to be saved.
622 * @param num The number of elements to save.
623 * @param iobuf The output buffer descriptor.
624 *
625 * @return (none)
626 */
627
628#ifdef ANSI_C
629void put_vector_of_uint16 (uint16_t *uval, int num, IO_BUFFER *iobuf)
630#else
631void put_vector_of_uint16 (uval,num,iobuf)
632 uint16_t *uval;
633 int num;
634 IO_BUFFER *iobuf;
635#endif
636{
637 int i;
638 union
639 {
640 uint16_t uval;
641 BYTE cval[2];
642 } val[2];
643
644 for (i=0; i<num; i++)
645 {
646 if ( (iobuf->w_remaining-=2) < 0 )
647 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
648 return;
649
650 if ( iobuf->byte_order == 0)
651 {
652 COPY_BYTES((void *)iobuf->data,(void *)(uval+i),(size_t)2);
653 }
654 else
655 {
656 val[0].uval = uval[i];
657 val[1].cval[0] = val[0].cval[1];
658 val[1].cval[1] = val[0].cval[0];
659 COPY_BYTES((void *)iobuf->data,(void *)&val[1].uval,(size_t)2);
660 }
661
662 iobuf->data += 2;
663 }
664}
665
666/* ----------------- get_vector_of_uint16 ---------------------- */
667/**
668 * @short Get a vector of unsigned shorts from an I/O buffer.
669 *
670 * Get a vector of unsigned shorts from an I/O buffer with least
671 * significant byte first. The values are in the range 0 to 65535.
672 * The function should be used where sign propagation is of concern.
673 *
674 * @param uval The vector where the values should be loaded.
675 * @param num The number of elements to load.
676 * @param iobuf The output buffer descriptor.
677 *
678 * @return (none)
679 */
680
681#ifdef ANSI_C
682void get_vector_of_uint16 (uint16_t *uval, int num, IO_BUFFER *iobuf)
683#else
684void get_vector_of_uint16 (uval,num,iobuf)
685 uint16_t *uval;
686 int num;
687 IO_BUFFER *iobuf;
688#endif
689{
690 int i;
691 union
692 {
693 uint16_t uval;
694 BYTE cval[2];
695 } val[2];
696
697 for (i=0; i<num; i++)
698 {
699 if ( (iobuf->r_remaining-=2) < 0 )
700 return;
701
702 if ( iobuf->byte_order == 0)
703 {
704 COPY_BYTES((void *)(uval+i),(void *)iobuf->data,(size_t)2);
705 }
706 else
707 {
708 COPY_BYTES((void *)&val[0].uval,(void *)iobuf->data,(size_t)2);
709 val[1].cval[0] = val[0].cval[1];
710 val[1].cval[1] = val[0].cval[0];
711 uval[i] = val[1].uval;
712 }
713
714 iobuf->data += 2;
715 }
716}
717
718/* --------------------------- get_short ---------------------- */
719/**
720 * @short Get a two-byte integer from an I/O buffer.
721 *
722 * Get a two-byte integer with least significant byte
723 * first. Should be machine-independent (see put_short()).
724 */
725
726#ifdef ANSI_C
727int get_short(IO_BUFFER *iobuf)
728#else
729int get_short(iobuf)
730 IO_BUFFER *iobuf;
731#endif
732{
733
734 int16_t num;
735
736 union
737 {
738 int16_t sval;
739 BYTE cval[2];
740 } val[2];
741
742 if ( (iobuf->r_remaining-=2) < 0 )
743 return -1;
744
745 if ( iobuf->byte_order == 0 )
746 COPY_BYTES((void *) &num,(void *) iobuf->data,(size_t)2);
747 else
748 {
749 COPY_BYTES((void *)&val[0].sval,(void *)iobuf->data,(size_t)2);
750 val[1].cval[0] = val[0].cval[1];
751 val[1].cval[1] = val[0].cval[0];
752 num = val[1].sval;
753 }
754
755 iobuf->data += 2;
756
757 /* Note that a sign propagation may happen here */
758 return ((int) num);
759}
760
761/* -------------------- get_vector_of_short ------------------ */
762/**
763 * Get a vector of short integers from I/O buffer.
764 */
765
766#ifdef ANSI_C
767void get_vector_of_short (short *vec, int num, IO_BUFFER *iobuf)
768#else
769void get_vector_of_short (vec, num, iobuf)
770 short *vec;
771 int num;
772 IO_BUFFER *iobuf;
773#endif
774{
775 REGISTER int i;
776
777 if ( vec == (short *) NULL )
778 {
779 if ( (iobuf->r_remaining-=(2*num)) >= 0 )
780 iobuf->data += 2*num;
781 return;
782 }
783
784 for (i=0; i<num; i++)
785 vec[i] = (short) get_short(iobuf);
786}
787
788/* --------------------- get_vector_of_int --------------------- */
789/**
790 * Get a vector of (small) integers from I/O buffer.
791 */
792
793#ifdef ANSI_C
794void get_vector_of_int (int *vec, int num, IO_BUFFER *iobuf)
795#else
796void get_vector_of_int (vec, num, iobuf)
797 int *vec;
798 int num;
799 IO_BUFFER *iobuf;
800#endif
801{
802 REGISTER int i;
803
804 if ( vec == (int *) NULL )
805 {
806 if ( (iobuf->r_remaining-=(2*num)) >= 0 )
807 iobuf->data += 2*num;
808 return;
809 }
810
811 for (i=0; i<num; i++)
812 vec[i] = get_short(iobuf);
813}
814
815/* --------------------------- put_int32 ----------------------- */
816/**
817 * @short Write a four-byte integer to an I/O buffer.
818 *
819 * Write a four-byte integer with least significant bytes
820 * first. Should be machine independent (see put_short()).
821 */
822
823#ifdef ANSI_C
824void put_int32(int32_t num, IO_BUFFER *iobuf)
825#else
826void put_int32(num,iobuf)
827 int32_t num;
828 IO_BUFFER *iobuf;
829#endif
830{
831 union
832 {
833 int32_t lval;
834 BYTE cval[4];
835 } val[2];
836 int32_t ival;
837
838 if ( (iobuf->w_remaining-=4) < 0 )
839 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
840 return;
841
842 if ( iobuf->byte_order == 0 )
843 {
844 ival = (int32_t) num;
845 COPY_BYTES((void *)iobuf->data,(void *) &ival,(size_t)4);
846 }
847 else
848 {
849 val[0].lval = (int32_t) num;
850 val[1].cval[0] = val[0].cval[3];
851 val[1].cval[1] = val[0].cval[2];
852 val[1].cval[2] = val[0].cval[1];
853 val[1].cval[3] = val[0].cval[0];
854 COPY_BYTES((void *)iobuf->data,(void *)&val[1].lval,(size_t)4);
855 }
856
857 iobuf->data += 4;
858}
859
860/* ---------------------- put_vector_of_int32 ------------------ */
861/**
862 * Put a vector of 32 bit integers into I/O buffer.
863 */
864
865#ifdef ANSI_C
866void put_vector_of_int32 (int32_t *vec, int num, IO_BUFFER *iobuf)
867#else
868void put_vector_of_int32 (vec, num, iobuf)
869 int32_t *vec;
870 int num;
871 IO_BUFFER *iobuf;
872#endif
873{
874 REGISTER int i;
875
876 if ( vec == (int32_t *) NULL )
877 {
878 for (i=0; i<num; i++)
879 put_int32(0L,iobuf);
880 return;
881 }
882
883 for (i=0; i<num; i++)
884 put_int32(vec[i],iobuf);
885}
886
887/* --------------------------- get_int32 ----------------------- */
888/**
889 * @short Read a four byte integer from an I/O buffer.
890 * Read a four byte integer with little-endian or big-endian
891 * byte order from memory. Should be machine independent
892 * (see put_short()).
893 *
894 */
895
896#ifdef ANSI_C
897int32_t get_int32(IO_BUFFER *iobuf)
898#else
899int32_t get_int32(iobuf)
900 IO_BUFFER *iobuf;
901#endif
902{
903 int32_t num;
904
905 union
906 {
907 int32_t lval;
908 BYTE cval[4];
909 } val[2];
910
911 if ( (iobuf->r_remaining-=4) < 0 )
912 return -1L;
913
914 if ( iobuf->byte_order == 0 )
915 COPY_BYTES((void *) &num,(void *)iobuf->data,(size_t)4);
916 else
917 {
918 COPY_BYTES((void *)&val[0].lval,(void *)iobuf->data,(size_t)4);
919 val[1].cval[0] = val[0].cval[3];
920 val[1].cval[1] = val[0].cval[2];
921 val[1].cval[2] = val[0].cval[1];
922 val[1].cval[3] = val[0].cval[0];
923 num = val[1].lval;
924 }
925
926 iobuf->data += 4;
927
928 return num;
929}
930
931/* ---------------------- get_vector_of_int32 ------------------ */
932/**
933 * Get a vector of 32 bit integers from I/O buffer.
934 */
935
936#ifdef ANSI_C
937void get_vector_of_int32 (int32_t *vec, int num, IO_BUFFER *iobuf)
938#else
939void get_vector_of_int32 (vec, num, iobuf)
940 int32_t *vec;
941 int num;
942 IO_BUFFER *iobuf;
943#endif
944{
945 REGISTER int i;
946
947 union
948 {
949 int32_t lval;
950 BYTE cval[4];
951 } val[2];
952
953 if ( num <= 0 )
954 return;
955
956 if ( (iobuf->r_remaining-=4*num) < 0 )
957 return;
958
959 if ( vec == NULL )
960 {
961 iobuf->data += 4*num;
962 return;
963 }
964
965 if ( iobuf->byte_order == 0 )
966 {
967 COPY_BYTES((void *) vec,(void *)iobuf->data,(size_t)(4*num));
968 iobuf->data += 4*num;
969 }
970 else
971 {
972 for ( i=0; i<num; i++ )
973 {
974 COPY_BYTES((void *)&val[0].lval,(void *)iobuf->data,(size_t)4);
975 val[1].cval[0] = val[0].cval[3];
976 val[1].cval[1] = val[0].cval[2];
977 val[1].cval[2] = val[0].cval[1];
978 val[1].cval[3] = val[0].cval[0];
979 vec[i] = val[1].lval;
980 iobuf->data += 4;
981 }
982 }
983}
984
985/* --------------------------- put_int32 ----------------------- */
986/**
987 * @short Put a four-byte integer into an I/O buffer.
988 *
989 * Write a four-byte integer with least significant bytes
990 * first. Should be machine independent (see put_short()).
991 */
992
993#ifdef ANSI_C
994void put_uint32(uint32_t num, IO_BUFFER *iobuf)
995#else
996void put_uint32(num,iobuf)
997 uint32_t num;
998 IO_BUFFER *iobuf;
999#endif
1000{
1001 union
1002 {
1003 uint32_t lval;
1004 BYTE cval[4];
1005 } val[2];
1006 uint32_t ival;
1007
1008 if ( (iobuf->w_remaining-=4) < 0 )
1009 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
1010 return;
1011
1012 if ( iobuf->byte_order == 0 )
1013 {
1014 ival = (uint32_t) num;
1015 COPY_BYTES((void *)iobuf->data,(void *) &ival,(size_t)4);
1016 }
1017 else
1018 {
1019 val[0].lval = (uint32_t) num;
1020 val[1].cval[0] = val[0].cval[3];
1021 val[1].cval[1] = val[0].cval[2];
1022 val[1].cval[2] = val[0].cval[1];
1023 val[1].cval[3] = val[0].cval[0];
1024 COPY_BYTES((void *)iobuf->data,(void *)&val[1].lval,(size_t)4);
1025 }
1026
1027 iobuf->data += 4;
1028}
1029
1030/* ---------------------- put_vector_of_uint32 ------------------ */
1031/**
1032 * Put a vector of 32 bit integers into I/O buffer.
1033 */
1034
1035#ifdef ANSI_C
1036void put_vector_of_uint32 (uint32_t *vec, int num, IO_BUFFER *iobuf)
1037#else
1038void put_vector_of_uint32 (vec, num, iobuf)
1039 uint32_t *vec;
1040 int num;
1041 IO_BUFFER *iobuf;
1042#endif
1043{
1044 REGISTER int i;
1045
1046 if ( vec == (uint32_t *) NULL )
1047 {
1048 for (i=0; i<num; i++)
1049 put_uint32(0L,iobuf);
1050 return;
1051 }
1052
1053 for (i=0; i<num; i++)
1054 put_uint32(vec[i],iobuf);
1055}
1056
1057/* --------------------------- get_uint32 ----------------------- */
1058/**
1059 * @short Get a four-byte unsigned integer from an I/O buffer.
1060 *
1061 * Read a four byte integer with little-endian or big-endian
1062 * byte order from memory. Should be machine independent
1063 * (see put_short()).
1064 *
1065 */
1066
1067#ifdef ANSI_C
1068uint32_t get_uint32(IO_BUFFER *iobuf)
1069#else
1070uint32_t get_uint32(iobuf)
1071 IO_BUFFER *iobuf;
1072#endif
1073{
1074 uint32_t num;
1075
1076 union
1077 {
1078 uint32_t lval;
1079 BYTE cval[4];
1080 } val[2];
1081
1082 if ( (iobuf->r_remaining-=4) < 0 )
1083 return -1L;
1084
1085 if ( iobuf->byte_order == 0 )
1086 COPY_BYTES((void *) &num,(void *)iobuf->data,(size_t)4);
1087 else
1088 {
1089 COPY_BYTES((void *)&val[0].lval,(void *)iobuf->data,(size_t)4);
1090 val[1].cval[0] = val[0].cval[3];
1091 val[1].cval[1] = val[0].cval[2];
1092 val[1].cval[2] = val[0].cval[1];
1093 val[1].cval[3] = val[0].cval[0];
1094 num = val[1].lval;
1095 }
1096
1097 iobuf->data += 4;
1098
1099 return num;
1100}
1101
1102/* ---------------------- get_vector_of_uint32 ------------------ */
1103/**
1104 * Get a vector of 32 bit integers from I/O buffer.
1105 */
1106
1107#ifdef ANSI_C
1108void get_vector_of_uint32 (uint32_t *vec, int num, IO_BUFFER *iobuf)
1109#else
1110void get_vector_of_uint32 (vec, num, iobuf)
1111 uint32_t *vec;
1112 int num;
1113 IO_BUFFER *iobuf;
1114#endif
1115{
1116 REGISTER int i;
1117
1118 union
1119 {
1120 uint32_t lval;
1121 BYTE cval[4];
1122 } val[2];
1123
1124 if ( num <= 0 )
1125 return;
1126
1127 if ( (iobuf->r_remaining-=4*num) < 0 )
1128 return;
1129
1130 if ( vec == NULL )
1131 {
1132 iobuf->data += 4*num;
1133 return;
1134 }
1135
1136 if ( iobuf->byte_order == 0 )
1137 {
1138 COPY_BYTES((void *) vec,(void *)iobuf->data,(size_t)(4*num));
1139 iobuf->data += 4*num;
1140 }
1141 else
1142 {
1143 for ( i=0; i<num; i++ )
1144 {
1145 COPY_BYTES((void *)&val[0].lval,(void *)iobuf->data,(size_t)4);
1146 val[1].cval[0] = val[0].cval[3];
1147 val[1].cval[1] = val[0].cval[2];
1148 val[1].cval[2] = val[0].cval[1];
1149 val[1].cval[3] = val[0].cval[0];
1150 vec[i] = val[1].lval;
1151 iobuf->data += 4;
1152 }
1153 }
1154}
1155
1156/* --------------------------- put_long ----------------------- */
1157/**
1158 * @short Put a four-byte integer taken from a 'long' into an I/O buffer.
1159 *
1160 * Write a four-byte integer with least significant bytes
1161 * first. Should be machine independent (see put_short()).
1162 */
1163
1164#ifdef ANSI_C
1165void put_long(long num, IO_BUFFER *iobuf)
1166#else
1167void put_long(num,iobuf)
1168 long num;
1169 IO_BUFFER *iobuf;
1170#endif
1171{
1172 union
1173 {
1174 int32_t lval;
1175 BYTE cval[4];
1176 } val[2];
1177 int32_t ival;
1178
1179 if ( (iobuf->w_remaining-=4) < 0 )
1180 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
1181 return;
1182
1183 if ( iobuf->byte_order == 0 )
1184 {
1185 ival = (int32_t) num;
1186 COPY_BYTES((void *)iobuf->data,(void *) &ival,(size_t)4);
1187 }
1188 else
1189 {
1190 val[0].lval = (int32_t) num;
1191 val[1].cval[0] = val[0].cval[3];
1192 val[1].cval[1] = val[0].cval[2];
1193 val[1].cval[2] = val[0].cval[1];
1194 val[1].cval[3] = val[0].cval[0];
1195 COPY_BYTES((void *)iobuf->data,(void *)&val[1].lval,(size_t)4);
1196 }
1197
1198 iobuf->data += 4;
1199}
1200
1201/* ---------------------- put_vector_of_long ------------------ */
1202/**
1203 * Put a vector of long int as 4-byte integers into an I/O buffer.
1204 */
1205
1206#ifdef ANSI_C
1207void put_vector_of_long (long *vec, int num, IO_BUFFER *iobuf)
1208#else
1209void put_vector_of_long (vec, num, iobuf)
1210 long *vec;
1211 int num;
1212 IO_BUFFER *iobuf;
1213#endif
1214{
1215 REGISTER int i;
1216
1217 if ( vec == (long *) NULL )
1218 {
1219 for (i=0; i<num; i++)
1220 put_long(0L,iobuf);
1221 return;
1222 }
1223
1224 for (i=0; i<num; i++)
1225 put_long(vec[i],iobuf);
1226}
1227
1228/* --------------------------- get_long ----------------------- */
1229/**
1230 * @short Get 4-byte integer from I/O buffer and return as a long int.
1231 *
1232 * Read a four byte integer with little-endian or big-endian
1233 * byte order from memory. Should be machine independent
1234 * (see put_short()).
1235 */
1236
1237#ifdef ANSI_C
1238long get_long(IO_BUFFER *iobuf)
1239#else
1240long get_long(iobuf)
1241 IO_BUFFER *iobuf;
1242#endif
1243{
1244 int32_t num;
1245
1246 union
1247 {
1248 int32_t lval;
1249 BYTE cval[4];
1250 } val[2];
1251
1252 if ( (iobuf->r_remaining-=4) < 0 )
1253 return -1L;
1254
1255 if ( iobuf->byte_order == 0 )
1256 COPY_BYTES((void *) &num,(void *)iobuf->data,(size_t)4);
1257 else
1258 {
1259 COPY_BYTES((void *)&val[0].lval,(void *)iobuf->data,(size_t)4);
1260 val[1].cval[0] = val[0].cval[3];
1261 val[1].cval[1] = val[0].cval[2];
1262 val[1].cval[2] = val[0].cval[1];
1263 val[1].cval[3] = val[0].cval[0];
1264 num = val[1].lval;
1265 }
1266
1267 iobuf->data += 4;
1268
1269 /* Note that for 64-bit machines a sign propagation may happen here */
1270 return (long) num;
1271}
1272
1273/* ---------------------- get_vector_of_long ------------------ */
1274/**
1275 * Get a vector of 4-byte integers as long int from I/O buffer.
1276 */
1277
1278#ifdef ANSI_C
1279void get_vector_of_long (long *vec, int num, IO_BUFFER *iobuf)
1280#else
1281void get_vector_of_long (vec, num, iobuf)
1282 long *vec;
1283 int num;
1284 IO_BUFFER *iobuf;
1285#endif
1286{
1287 REGISTER int i;
1288
1289 union
1290 {
1291 int32_t lval;
1292 BYTE cval[4];
1293 } val[2];
1294
1295 if ( num <= 0 )
1296 return;
1297
1298 if ( (iobuf->r_remaining-=4*num) < 0 )
1299 return;
1300
1301 if ( vec == (long *) NULL )
1302 {
1303 iobuf->data += 4*num;
1304 return;
1305 }
1306
1307 if ( iobuf->byte_order == 0 )
1308 {
1309#ifdef SIXTY_FOUR_BITS
1310 for ( i=0; i<num; i++ )
1311 {
1312 COPY_BYTES((void *)&val[1].lval,(void *)iobuf->data,(size_t)4);
1313 /* Note the possible sign propagation */
1314 vec[i] = (long) val[1].lval;
1315 iobuf->data += 4;
1316 }
1317#else
1318 COPY_BYTES((void *) vec,(void *)iobuf->data,(size_t)(4*num));
1319 iobuf->data += 4*num;
1320#endif
1321 }
1322 else
1323 {
1324 for ( i=0; i<num; i++ )
1325 {
1326 COPY_BYTES((void *)&val[0].lval,(void *)iobuf->data,(size_t)4);
1327 val[1].cval[0] = val[0].cval[3];
1328 val[1].cval[1] = val[0].cval[2];
1329 val[1].cval[2] = val[0].cval[1];
1330 val[1].cval[3] = val[0].cval[0];
1331 /* Note the possible sign propagation on 64-bit machines */
1332 vec[i] = (long) val[1].lval;
1333 iobuf->data += 4;
1334 }
1335 }
1336}
1337
1338#ifdef HAVE_64BIT_INT
1339
1340/* ----------------- put_vector_of_int64 ---------------------- */
1341/**
1342 * @short Put a vector of signed 64-bit integers into an I/O buffer.
1343 *
1344 * The function is only available where int64_t/uint64_t data
1345 * types are implemented in the C compiler.
1346 *
1347 * @param uval The vector of values to be saved.
1348 * @param num The number of elements to save.
1349 * @param iobuf The output buffer descriptor.
1350 *
1351 * @return (none)
1352 *
1353 */
1354
1355#ifdef ANSI_C
1356void put_vector_of_int64 (int64_t *ival, int num, IO_BUFFER *iobuf)
1357#else
1358void put_vector_of_int64 (ival,num,iobuf)
1359 int64_t *ival;
1360 int num;
1361 IO_BUFFER *iobuf;
1362#endif
1363{
1364 int i;
1365 union
1366 {
1367 int64_t ival;
1368 BYTE cval[8];
1369 } val[2];
1370
1371 for (i=0; i<num; i++)
1372 {
1373 if ( (iobuf->w_remaining-=8) < 0 )
1374 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
1375 return;
1376
1377 if ( iobuf->byte_order == 0)
1378 {
1379 COPY_BYTES((void *)iobuf->data,(void *)(ival+i),(size_t)8);
1380 }
1381 else
1382 {
1383 val[0].ival = ival[i];
1384 val[1].cval[0] = val[0].cval[7];
1385 val[1].cval[1] = val[0].cval[6];
1386 val[1].cval[2] = val[0].cval[5];
1387 val[1].cval[3] = val[0].cval[4];
1388 val[1].cval[4] = val[0].cval[3];
1389 val[1].cval[5] = val[0].cval[2];
1390 val[1].cval[6] = val[0].cval[1];
1391 val[1].cval[7] = val[0].cval[0];
1392 COPY_BYTES((void *)iobuf->data,(void *)&val[1].ival,(size_t)8);
1393 }
1394
1395 iobuf->data += 8;
1396 }
1397}
1398
1399/* ----------------- get_vector_of_int64 ---------------------- */
1400/**
1401 * @short Get a vector of signed 64-bit integers from an I/O buffer.
1402 *
1403 * The function is only available where int64_t/uint64_t data
1404 * types are implemented in the C compiler.
1405 *
1406 * @param uval The vector where the values should be loaded.
1407 * @param num The number of elements to load.
1408 * @param iobuf The output buffer descriptor.
1409 *
1410 * @return (none)
1411 */
1412
1413#ifdef ANSI_C
1414void get_vector_of_int64 (int64_t *ival, int num, IO_BUFFER *iobuf)
1415#else
1416void get_vector_of_int64 (ival,num,iobuf)
1417 int64_t *ival;
1418 int num;
1419 IO_BUFFER *iobuf;
1420#endif
1421{
1422 int i;
1423 union
1424 {
1425 int64_t ival;
1426 BYTE cval[8];
1427 } val[2];
1428
1429 for (i=0; i<num; i++)
1430 {
1431 if ( (iobuf->r_remaining-=8) < 0 )
1432 return;
1433
1434 if ( iobuf->byte_order == 0)
1435 {
1436 COPY_BYTES((void *)(ival+i),(void *)iobuf->data,(size_t)8);
1437 }
1438 else
1439 {
1440 COPY_BYTES((void *)&val[0].ival,(void *)iobuf->data,(size_t)8);
1441 val[1].cval[0] = val[0].cval[7];
1442 val[1].cval[1] = val[0].cval[6];
1443 val[1].cval[2] = val[0].cval[5];
1444 val[1].cval[3] = val[0].cval[4];
1445 val[1].cval[4] = val[0].cval[3];
1446 val[1].cval[5] = val[0].cval[2];
1447 val[1].cval[6] = val[0].cval[1];
1448 val[1].cval[7] = val[0].cval[0];
1449 ival[i] = val[1].ival;
1450 }
1451
1452 iobuf->data += 8;
1453 }
1454}
1455
1456/* ----------------- put_vector_of_uint64 ---------------------- */
1457/**
1458 * @short Put a vector of unsigned 64-bit integers into an I/O buffer.
1459 *
1460 * The function is only available where int64_t/uint64_t data
1461 * types are implemented in the C compiler.
1462 *
1463 * @param uval The vector of values to be saved.
1464 * @param num The number of elements to save.
1465 * @param iobuf The output buffer descriptor.
1466 *
1467 * @return (none)
1468 */
1469
1470#ifdef ANSI_C
1471void put_vector_of_uint64 (uint64_t *uval, int num, IO_BUFFER *iobuf)
1472#else
1473void put_vector_of_uint64 (uval,num,iobuf)
1474 uint64_t *uval;
1475 int num;
1476 IO_BUFFER *iobuf;
1477#endif
1478{
1479 int i;
1480 union
1481 {
1482 uint64_t uval;
1483 BYTE cval[8];
1484 } val[2];
1485
1486 for (i=0; i<num; i++)
1487 {
1488 if ( (iobuf->w_remaining-=8) < 0 )
1489 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
1490 return;
1491
1492 if ( iobuf->byte_order == 0)
1493 {
1494 COPY_BYTES((void *)iobuf->data,(void *)(uval+i),(size_t)8);
1495 }
1496 else
1497 {
1498 val[0].uval = uval[i];
1499 val[1].cval[0] = val[0].cval[7];
1500 val[1].cval[1] = val[0].cval[6];
1501 val[1].cval[2] = val[0].cval[5];
1502 val[1].cval[3] = val[0].cval[4];
1503 val[1].cval[4] = val[0].cval[3];
1504 val[1].cval[5] = val[0].cval[2];
1505 val[1].cval[6] = val[0].cval[1];
1506 val[1].cval[7] = val[0].cval[0];
1507 COPY_BYTES((void *)iobuf->data,(void *)&val[1].uval,(size_t)8);
1508 }
1509
1510 iobuf->data += 8;
1511 }
1512}
1513
1514/* ----------------- get_vector_of_uint64 ---------------------- */
1515/**
1516 * @short Get a vector of unsigned 64-bit integers from an I/O buffer.
1517 *
1518 * The function is only available where int64_t/uint64_t data
1519 * types are implemented in the C compiler.
1520 *
1521 * @param uval The vector where the values should be loaded.
1522 * @param num The number of elements to load.
1523 * @param iobuf The output buffer descriptor.
1524 *
1525 * @return (none)
1526 */
1527
1528#ifdef ANSI_C
1529void get_vector_of_uint64 (uint64_t *uval, int num, IO_BUFFER *iobuf)
1530#else
1531void get_vector_of_uint64 (uval,num,iobuf)
1532 uint64_t *uval;
1533 int num;
1534 IO_BUFFER *iobuf;
1535#endif
1536{
1537 int i;
1538 union
1539 {
1540 uint64_t uval;
1541 BYTE cval[8];
1542 } val[2];
1543
1544 for (i=0; i<num; i++)
1545 {
1546 if ( (iobuf->r_remaining-=8) < 0 )
1547 return;
1548
1549 if ( iobuf->byte_order == 0)
1550 {
1551 COPY_BYTES((void *)(uval+i),(void *)iobuf->data,(size_t)8);
1552 }
1553 else
1554 {
1555 COPY_BYTES((void *)&val[0].uval,(void *)iobuf->data,(size_t)8);
1556 val[1].cval[0] = val[0].cval[7];
1557 val[1].cval[1] = val[0].cval[6];
1558 val[1].cval[2] = val[0].cval[5];
1559 val[1].cval[3] = val[0].cval[4];
1560 val[1].cval[4] = val[0].cval[3];
1561 val[1].cval[5] = val[0].cval[2];
1562 val[1].cval[6] = val[0].cval[1];
1563 val[1].cval[7] = val[0].cval[0];
1564 uval[i] = val[1].uval;
1565 }
1566
1567 iobuf->data += 8;
1568 }
1569}
1570
1571#endif
1572
1573/* ------------------------ put_string --------------------- */
1574/**
1575 * @short Put a string of ASCII characters into an I/O buffer.
1576 *
1577 * Put a string of ASCII characters with leading count of
1578 * bytes into an I/O buffer.
1579 *
1580 * @param s The null-terminated ASCII string.
1581 * @param iobuf The I/O buffer descriptor.
1582 *
1583 * @return Length of string
1584 *
1585 */
1586
1587#ifdef ANSI_C
1588int put_string (char *s, IO_BUFFER *iobuf)
1589#else
1590int put_string (s, iobuf)
1591 char *s;
1592 IO_BUFFER *iobuf;
1593#endif
1594{
1595 int len = 0;
1596
1597 if ( s == (char *) NULL )
1598 put_short(0,iobuf);
1599 else
1600 {
1601 len = (int) strlen(s);
1602 put_short(len,iobuf);
1603 put_vector_of_byte((BYTE *) s,len,iobuf);
1604 }
1605
1606 return len;
1607}
1608
1609/* ----------------------- get_string ---------------------- */
1610/**
1611 * @short Get a string of ASCII characters from an I/O buffer.
1612 *
1613 * Get a string of ASCII characters with leading count of
1614 * bytes from an I/O buffer.
1615 *
1616 * NOTE: the nmax count does now account for the trailing zero
1617 * byte which will be appended. This was different in an earlier
1618 * version of this function where one additional byte had to
1619 * be available for the trailing zero byte.
1620 *
1621 */
1622
1623#ifdef ANSI_C
1624int get_string (char *s, int nmax, IO_BUFFER *iobuf)
1625#else
1626int get_string (s, nmax, iobuf)
1627 char *s;
1628 int nmax;
1629 IO_BUFFER *iobuf;
1630#endif
1631{
1632 int nbytes, nread;
1633
1634 nbytes = get_short(iobuf);
1635 nread = (nmax-1<nbytes) ? nmax-1 : nbytes; /* minimum of both */
1636 /* Read up to the accepted maximum length */
1637 get_vector_of_byte((BYTE *) s, nread, iobuf);
1638 /* Ignore the rest of the string */
1639 if ( nbytes > nread )
1640 {
1641 iobuf->r_remaining -= (nbytes-nread);
1642 iobuf->data += (nbytes-nread);
1643 }
1644 /* Terminate string with null character */
1645 s[nread] = '\0';
1646
1647 return(nbytes);
1648}
1649
1650/* ------------------------ put_long_string --------------------- */
1651/**
1652 * @short Put a long string of ASCII characters into an I/O buffer.
1653 *
1654 * Put a long string of ASCII characters with leading count of
1655 * bytes into an I/O buffer. This is expected to work properly
1656 * for strings of more than 32k only on machines with sizeof(int) > 2
1657 * because 16-bit machines may not be able to represent lengths
1658 * of long strings (as obtained with strlen).
1659 *
1660 * @param s The null-terminated ASCII string.
1661 * @param iobuf The I/O buffer descriptor.
1662 *
1663 * @return Length of string
1664 *
1665 */
1666
1667#ifdef ANSI_C
1668int put_long_string (char *s, IO_BUFFER *iobuf)
1669#else
1670int put_long_string (s, iobuf)
1671 char *s;
1672 IO_BUFFER *iobuf;
1673#endif
1674{
1675 int32_t len = 0;
1676
1677 if ( s == (char *) NULL )
1678 put_short(0,iobuf);
1679 else
1680 {
1681 len = (int32_t) strlen(s);
1682 put_int32(len,iobuf);
1683 put_vector_of_byte((BYTE *) s,len,iobuf);
1684 }
1685
1686 return (int) len;
1687}
1688
1689/* ----------------------- get_long_string ---------------------- */
1690/**
1691 * @short Get a long string of ASCII characters from an I/O buffer.
1692 *
1693 * Get a long string of ASCII characters with leading count of
1694 * bytes from an I/O buffer. Strings can be up to 2^31-1 bytes long
1695 * (assuming you have so much memory).
1696 *
1697 * To work properly with strings longer than 32k, a machine with
1698 * sizeof(int) > 2 is actually required.
1699 *
1700 * NOTE: the nmax count does account also for the trailing zero
1701 * byte which will be appended.
1702 *
1703 */
1704
1705#ifdef ANSI_C
1706int get_long_string (char *s, int nmax, IO_BUFFER *iobuf)
1707#else
1708int get_long_string (s, nmax, iobuf)
1709 char *s;
1710 int nmax;
1711 IO_BUFFER *iobuf;
1712#endif
1713{
1714 int32_t nbytes, nread;
1715
1716 nbytes = get_int32(iobuf);
1717 /* minimum of both */
1718 nread = (nmax-1<nbytes) ? nmax-1 : nbytes;
1719 /* Read up to the accepted maximum length */
1720 get_vector_of_byte((BYTE *) s, nread, iobuf);
1721 /* Ignore the rest of the string */
1722 if ( nbytes > nread )
1723 {
1724 iobuf->r_remaining -= (nbytes-nread);
1725 iobuf->data += (nbytes-nread);
1726 }
1727 /* Terminate string with null character */
1728 s[nread] = '\0';
1729
1730 return(nbytes);
1731}
1732
1733/* ----------------------- put_real ------------------------ */
1734/**
1735 * @short Put a 4-byte floating point number into an I/O buffer.
1736 *
1737 * Put a 'double' (floating point) number in a
1738 * specific but (almost) machine-independent format into
1739 * an I/O buffer.
1740 * Not the full precision of a 'double' is saved but
1741 * a 32 bit IEEE floating point number is written (with the
1742 * same byte ordering as long integers). On machines with
1743 * other floating point format than IEEE the input number
1744 * is converted to a IEEE number first. An optimized (machine-
1745 * specific) version should compute the output data by shift and
1746 * add operations rather than by log(), divide, and multiply
1747 * operations on such non-IEEE-format machines (implemented
1748 * for VAX only).
1749 *
1750 * @param dnum The number to be put into the I/O buffer.
1751 * @param iobuf The I/O buffer descriptor.
1752 *
1753 * @return (none)
1754 *
1755 */
1756
1757#ifdef ANSI_C
1758void put_real (double dnum, IO_BUFFER *iobuf)
1759#else
1760void put_real (dnum, iobuf)
1761 double dnum;
1762 IO_BUFFER *iobuf;
1763#endif
1764{
1765
1766#ifdef IEEE_FLOAT_FORMAT
1767
1768 union
1769 {
1770 float fnum;
1771 int32_t lnum;
1772 } val;
1773
1774 val.fnum = (float) dnum;
1775 put_int32(val.lnum,iobuf);
1776
1777#else
1778# ifdef VAX_FLOAT_FORMAT
1779
1780 union
1781 {
1782 float real;
1783 unsigned short words[2];
1784 } rswapit;
1785 union
1786 {
1787 long lword;
1788 unsigned short words[1];
1789 } lswapit;
1790
1791 rswapit.real = (float) (dnum*0.25);
1792 lswapit.words[1] = rswapit.words[0];
1793 lswapit.words[0] = rswapit.words[1];
1794 put_long(lswapit.lword,iobuf);
1795
1796# else
1797
1798 unsigned long sign, exponent, mantissa, rnum;
1799 static double log2 = 0.6931471805599453;
1800 static double two23 = 8388608.;
1801 double tnum;
1802
1803 if ( dnum==0. )
1804 sign = exponent = mantissa = 0;
1805 else
1806 {
1807 if ( dnum < 0 )
1808 {
1809 sign = 0x80000000L;
1810 dnum = -1.*dnum;
1811 }
1812 else
1813 sign = 0;
1814 /* Take care to avoid a factor of 2 effect due to tiny round-off */
1815 /* error with input numbers like 1.99999999 */
1816 exponent = (unsigned long) (127. + log(dnum)/log2);
1817 tnum = dnum/pow(2.,(double)exponent-127.);
1818 if ( (tnum-1.) * two23 + 0.499 >= two23 )
1819 {
1820 tnum /= 2;
1821 exponent += 1;
1822 }
1823 mantissa = ((unsigned long) ((tnum-1.) * two23 + 0.499)) & 0x007fffffL;
1824 exponent = (exponent&0xff) << 23;
1825 }
1826
1827 rnum = sign|exponent|mantissa,iobuf;
1828 put_long(rnum,iobuf);
1829
1830# endif
1831#endif
1832
1833}
1834
1835/* ------------------ put_vector_of_real ------------------ */
1836/**
1837 * Put a vector of doubles as IEEE 'float' numbers into an I/O buffer.
1838 */
1839
1840#ifdef ANSI_C
1841void put_vector_of_real (double *dvec, int num, IO_BUFFER *iobuf)
1842#else
1843void put_vector_of_real (dvec, num, iobuf)
1844 double *dvec;
1845 int num;
1846 IO_BUFFER *iobuf;
1847#endif
1848{
1849 int i;
1850
1851 if ( dvec == (double *) NULL )
1852 {
1853 for (i=0; i<num; i++)
1854 put_real(0.0,iobuf);
1855 return;
1856 }
1857
1858 for (i=0; i<num; i++)
1859 put_real(dvec[i],iobuf);
1860}
1861
1862/* ------------------ put_vector_of_float ------------------ */
1863/**
1864 * Put a vector of floats as IEEE 'float' numbers into an I/O buffer.
1865 */
1866
1867#ifdef ANSI_C
1868void put_vector_of_float (float *fvec, int num, IO_BUFFER *iobuf)
1869#else
1870void put_vector_of_float (fvec, num, iobuf)
1871 float *fvec;
1872 int num;
1873 IO_BUFFER *iobuf;
1874#endif
1875{
1876 int i;
1877
1878 if ( fvec == (float *) NULL )
1879 {
1880 for (i=0; i<num; i++)
1881 put_real(0.0,iobuf);
1882 return;
1883 }
1884
1885 for (i=0; i<num; i++)
1886 put_real((double)fvec[i],iobuf);
1887}
1888
1889/* --------------------- get_real ------------------------- */
1890/**
1891 * @short Get a floating point number (as written by put_real) from the I/O buffer.
1892 *
1893 * @param iobuf The I/O buffer descriptor;
1894 *
1895 * @return The floating point number.
1896 *
1897 */
1898
1899#ifdef ANSI_C
1900double get_real (IO_BUFFER *iobuf)
1901#else
1902double get_real (iobuf)
1903 IO_BUFFER *iobuf;
1904#endif
1905{
1906
1907#ifdef IEEE_FLOAT_FORMAT
1908
1909 /* This is the simple way which can be used on most computers. */
1910
1911 union
1912 {
1913 float fnum;
1914 int32_t lnum;
1915 } val;
1916
1917 val.lnum = get_int32(iobuf);
1918# if ( defined(OS_LYNX) && defined(CPU_PowerPC) )
1919 /* Trick against compiler optimizer bug: */
1920 if ( val.fnum == 0. || val.lnum == 0 )
1921 return 0.;
1922# endif
1923 return((double)val.fnum);
1924
1925#else
1926# ifdef VAX_FLOAT_FORMAT
1927
1928 /* On VAX computers it is a bit more complicated. */
1929
1930 union
1931 {
1932 float real;
1933 uint16_t words[2];
1934 } rswapit;
1935 union
1936 {
1937 int32_t lword;
1938 uint16_t words[2];
1939 } lswapit;
1940
1941 /* A value with sign bit ON and exponent==0 might cause a */
1942 /* 'reserved operand fault' and abnormal program termination on a VAX. */
1943 if ( ((lswapit.lword = get_long(iobuf)) & 0x0000FF80L) == 0x00001000L )
1944 lswapit.lword = 0;
1945 rswapit.words[1] = lswapit.words[0];
1946 rswapit.words[0] = lswapit.words[1];
1947 return(4.0*(double)rswapit.real);
1948
1949# else
1950
1951 /* This way to obtain IEEE floating-point numbers can be used even */
1952 /* when the machine-dependent representation of floating-point numbers */
1953 /* is not known. */
1954
1955 static double two23 = 8388608.;
1956 uint32_t rnum, exponent, mantissa;
1957 double dnum;
1958
1959 rnum = (uint32_t) get_long(iobuf);
1960 exponent = (rnum & 0x7F800000L) >> 23;
1961 mantissa = (rnum & 0x007fffffL);
1962
1963 dnum = ((double)mantissa/two23+1.)*pow(2.,(double)exponent-127.);
1964 if ( rnum & 0x80000000L )
1965 dnum *= -1;
1966
1967 return(dnum);
1968
1969# endif
1970#endif
1971
1972}
1973
1974/* ------------------- get_vector_of_real -------------------- */
1975/**
1976 * Get a vector of floating point numbers as 'doubles' from an I/O buffer.
1977 */
1978
1979#ifdef ANSI_C
1980void get_vector_of_real (double *dvec, int num, IO_BUFFER *iobuf)
1981#else
1982void get_vector_of_real (dvec, num, iobuf)
1983 double *dvec;
1984 int num;
1985 IO_BUFFER *iobuf;
1986#endif
1987{
1988 int i;
1989
1990 if ( dvec == (double *) NULL )
1991 {
1992 if ( (iobuf->r_remaining-=(4*num)) >= 0 )
1993 iobuf->data += 4*num;
1994 return;
1995 }
1996
1997 for (i=0; i<num; i++)
1998 dvec[i] = get_real(iobuf);
1999}
2000
2001/* ------------------- get_vector_of_float -------------------- */
2002/**
2003 * Get a vector of floating point numbers as 'floats' from an I/O buffer.
2004 */
2005
2006#ifdef ANSI_C
2007void get_vector_of_float (float *fvec, int num, IO_BUFFER *iobuf)
2008#else
2009void get_vector_of_float (fvec, num, iobuf)
2010 float *fvec;
2011 int num;
2012 IO_BUFFER *iobuf;
2013#endif
2014{
2015 int i;
2016
2017 if ( fvec == (float *) NULL )
2018 {
2019 if ( (iobuf->r_remaining-=(4*num)) >= 0 )
2020 iobuf->data += 4*num;
2021 return;
2022 }
2023
2024 for (i=0; i<num; i++)
2025 fvec[i] = (float) get_real(iobuf);
2026}
2027
2028#ifdef IEEE_FLOAT_FORMAT
2029
2030/* ----------------------- put_double ------------------------ */
2031/**
2032 * @short Put a 'double' as such into an I/O buffer.
2033 *
2034 * Put a 'double' (floating point) number in a
2035 * specific but (almost) machine-independent format into
2036 * an I/O buffer.
2037 * This implementation requires the machine to use IEEE
2038 * double-precision floating point numbers. Only byte
2039 * order conversion is done.
2040 *
2041 * @param dnum The number to be put into the I/O buffer.
2042 * @param iobuf The I/O buffer descriptor.
2043 *
2044 * @return (none)
2045 */
2046
2047#ifdef ANSI_C
2048void put_double (double dnum, IO_BUFFER *iobuf)
2049#else
2050void put_double (dnum, iobuf)
2051 double dnum;
2052 IO_BUFFER *iobuf;
2053#endif
2054{
2055
2056 union
2057 {
2058 double dnum;
2059 char cval[8];
2060 } val[2];
2061
2062 val[0].dnum = dnum;
2063
2064 if ( (iobuf->w_remaining-=8) < 0 )
2065 if ( extend_io_buffer(iobuf,256,IO_BUFFER_LENGTH_INCREMENT) < 0 )
2066 return;
2067
2068 if ( iobuf->byte_order == 0 )
2069 {
2070 COPY_BYTES((void *) iobuf->data, (void *) val[0].cval, (size_t)8);
2071 }
2072 else
2073 {
2074 val[1].cval[0] = val[0].cval[7];
2075 val[1].cval[1] = val[0].cval[6];
2076 val[1].cval[2] = val[0].cval[5];
2077 val[1].cval[3] = val[0].cval[4];
2078 val[1].cval[4] = val[0].cval[3];
2079 val[1].cval[5] = val[0].cval[2];
2080 val[1].cval[6] = val[0].cval[1];
2081 val[1].cval[7] = val[0].cval[0];
2082 COPY_BYTES((void *) iobuf->data, (void *) val[1].cval, (size_t)8);
2083 }
2084
2085 iobuf->data += 8;
2086}
2087
2088/* ------------------ put_vector_of_double ------------------ */
2089/**
2090 * @short Put a vector of doubles into an I/O buffer.
2091 *
2092 * Put a vector of 'double' floating point numbers as IEEE
2093 * 'double' numbers into an I/O buffer.
2094 *
2095 */
2096
2097#ifdef ANSI_C
2098void put_vector_of_double (double *dvec, int num, IO_BUFFER *iobuf)
2099#else
2100void put_vector_of_double (dvec, num, iobuf)
2101 double *dvec;
2102 int num;
2103 IO_BUFFER *iobuf;
2104#endif
2105{
2106 int i;
2107
2108 if ( dvec == (double *) NULL )
2109 {
2110 for (i=0; i<num; i++)
2111 put_double(0.0,iobuf);
2112 return;
2113 }
2114
2115 for (i=0; i<num; i++)
2116 put_double(dvec[i],iobuf);
2117}
2118
2119/* --------------------- get_double ------------------------- */
2120/**
2121 * @short Get a double from the I/O buffer.
2122 *
2123 * Get a double-precision floating point number (as written by
2124 * put_double) from the I/O buffer.
2125 * The current implementation is only for machines using
2126 * IEEE format internally.
2127 *
2128 * @param iobuf -- The I/O buffer descriptor;
2129 *
2130 * @retunr The floating point number.
2131 *
2132 */
2133
2134#ifdef ANSI_C
2135double get_double (IO_BUFFER *iobuf)
2136#else
2137double get_double (iobuf)
2138 IO_BUFFER *iobuf;
2139#endif
2140{
2141
2142 /* This is the simple way which can be used on most computers. */
2143 /* Requires that the internal floating-point representation is in */
2144 /* IEEE format and only byte-order conversions are needed. */
2145
2146 union
2147 {
2148 double dnum;
2149 char cval[8];
2150 } val[2];
2151
2152 if ( (iobuf->r_remaining-=8) < 0 )
2153 return -1L;
2154
2155 if ( iobuf->byte_order == 0 )
2156 COPY_BYTES((void *) val[1].cval, (void *) iobuf->data, (size_t)8);
2157 else
2158 {
2159 COPY_BYTES((void *) val[0].cval, (void *) iobuf->data, (size_t)8);
2160 val[1].cval[0] = val[0].cval[7];
2161 val[1].cval[1] = val[0].cval[6];
2162 val[1].cval[2] = val[0].cval[5];
2163 val[1].cval[3] = val[0].cval[4];
2164 val[1].cval[4] = val[0].cval[3];
2165 val[1].cval[5] = val[0].cval[2];
2166 val[1].cval[6] = val[0].cval[1];
2167 val[1].cval[7] = val[0].cval[0];
2168 }
2169
2170 iobuf->data += 8;
2171
2172 return val[1].dnum;
2173}
2174
2175/* ------------------- get_vector_of_double -------------------- */
2176/**
2177 * Get a vector of floating point numbers as 'doubles' from an I/O buffer.
2178 */
2179
2180#ifdef ANSI_C
2181void get_vector_of_double (double *dvec, int num, IO_BUFFER *iobuf)
2182#else
2183void get_vector_of_double (dvec, num, iobuf)
2184 double *dvec;
2185 int num;
2186 IO_BUFFER *iobuf;
2187#endif
2188{
2189 int i;
2190
2191 if ( dvec == (double *) NULL )
2192 {
2193 if ( (iobuf->r_remaining-=(4*num)) >= 0 )
2194 iobuf->data += 4*num;
2195 return;
2196 }
2197
2198 for (i=0; i<num; i++)
2199 dvec[i] = get_double(iobuf);
2200}
2201
2202#endif /* IEEE_FLOAT_FORMAT */
2203
2204/* ------------------------ put_item_begin ------------------------ */
2205/**
2206 * @short Begin putting another (sub-) item into the output buffer.
2207 *
2208 * When putting another item to the output buffer which may
2209 * be either a top item or a sub-item, put_item_begin()
2210 * initializes the buffer (for a top item) and puts the item
2211 * header on the buffer.
2212 *
2213 * @param iobuf The output buffer descriptor.
2214 * @param item_header The item header descriptor.
2215 *
2216 * @return 0 (O.k.) or -1 (error)
2217 *
2218 */
2219
2220#ifdef ANSI_C
2221int put_item_begin (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2222#else
2223int put_item_begin (iobuf, item_header)
2224 IO_BUFFER *iobuf;
2225 IO_ITEM_HEADER *item_header;
2226#endif
2227{
2228 REGISTER int ilevel;
2229 unsigned long this_type;
2230
2231 if ( iobuf == (IO_BUFFER *) NULL )
2232 return -1;
2233 if ( !item_header->type )
2234 return -1;
2235 ilevel = item_header->level = iobuf->item_level;
2236 iobuf->r_remaining = -1;
2237
2238 if ( ilevel >= MAX_IO_ITEM_LEVEL )
2239 {
2240 char msg[256];
2241 (void) sprintf(msg,
2242 "Maximum level of sub-items in I/O Buffer exceeded for item type %ld",
2243 item_header->type);
2244 Warning(msg);
2245 item_header->level = MAX_IO_ITEM_LEVEL - 1;
2246 return -1;
2247 }
2248
2249 /* When starting a top item, additional work has to be done. */
2250 if ( ilevel == 0 )
2251 {
2252 if ( iobuf->buffer == (BYTE *) NULL ||
2253 iobuf->buflen < 16 )
2254 return -1;
2255 iobuf->data = iobuf->buffer;
2256 iobuf->w_remaining = iobuf->buflen;
2257 put_long((long)0xD41F8A37L,iobuf);
2258 }
2259
2260 if ( iobuf->w_remaining < 12 )
2261 return -1;
2262
2263 this_type = (unsigned long) (item_header->type & 0x0000ffffL) |
2264 ((unsigned long) item_header->version << 20);
2265 put_long((long)this_type, iobuf);
2266
2267 /* Write the identification number as supplied */
2268 put_long(item_header->ident,iobuf);
2269
2270 /* The length of the item is stored at the next 4 bytes which cannot */
2271 /* be done immediately but only when the item or sub-item is completely */
2272 /* on the buffer. */
2273 iobuf->item_length[ilevel] = 0;
2274 put_long(0L,iobuf);
2275
2276 /* Add this item's header length to the sub-item lengths of superiour items. */
2277 if ( ilevel > 0 )
2278 iobuf->sub_item_length[ilevel-1] += 12;
2279
2280 /* Keep track where the data of this item starts. Because the actual */
2281 /* buffer might be dynamically reallocated and moved, only offsets with */
2282 /* respect to the beginning of the buffer are saved but no pointers. */
2283 iobuf->item_start_offset[ilevel] = /* item_header->start_of_data = */
2284 (long) (iobuf->data-iobuf->buffer);
2285 iobuf->sub_item_length[ilevel] = 0;
2286
2287 iobuf->item_level++;
2288
2289 return 0;
2290}
2291
2292/* ------------------------- put_item_end ------------------------- */
2293/**
2294 * @short End of putting an item into the output buffer.
2295 *
2296 * When finished with putting an item to the output buffer,
2297 * check for errors and do housekeeping.
2298 *
2299 * @param iobuf The output buffer descriptor.
2300 * @param item_header The item header descriptor.
2301 *
2302 * @return 0 (O.k.) or -1 (error)
2303 *
2304 */
2305
2306#ifdef ANSI_C
2307int put_item_end (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2308#else
2309int put_item_end (iobuf, item_header)
2310 IO_BUFFER *iobuf;
2311 IO_ITEM_HEADER *item_header;
2312#endif
2313{
2314 int rc;
2315 REGISTER int ilevel;
2316 long length, padding, j;
2317 BYTE *save_data_ptr;
2318
2319 if ( item_header->level >= iobuf->item_level )
2320 {
2321 Warning("Attempt to finish putting an item which is no more active");
2322 return -1;
2323 }
2324 if ( iobuf->item_level <= 0 || item_header->level < 0 )
2325 return -1;
2326
2327 /* There might be more than one item level having to be finished. */
2328 for ( ilevel = (--iobuf->item_level); ilevel>=item_header->level; ilevel-- )
2329 {
2330 /* The length of the item is the distance of the current write */
2331 /* position from the beginning of data of the item. */
2332 length = (long) (iobuf->data - iobuf->buffer) -
2333 iobuf->item_start_offset[ilevel];
2334 padding = (4 - length%4) % 4;
2335 for ( j=0; j<padding; j++ )
2336 put_byte(0,iobuf);
2337 length += padding;
2338 iobuf->item_length[ilevel] = length;
2339 /* In order to keep track if an item can be searched for sub-items, */
2340 /* the sub-item length must be increased also by the no. of bytes padded. */
2341 iobuf->sub_item_length[ilevel] += padding;
2342
2343 /* Add this item's length to the sub-item lengths of superiour items. */
2344 if ( ilevel > 0 )
2345 iobuf->sub_item_length[ilevel-1] += iobuf->item_length[ilevel];
2346
2347 /* Now save the length field at its place right in front of the */
2348 /* beginning of data of that item. */
2349 save_data_ptr = iobuf->data;
2350 if ( iobuf->w_remaining < 0 )
2351 return -1; /* Report error in case of buffer overflow */
2352 iobuf->w_remaining += 4;
2353 iobuf->data = iobuf->buffer +
2354 (iobuf->item_start_offset[ilevel] - 4);
2355 /* If that item consists entirely of sub-items with known lengths */
2356 /* set bit 30 of the length field to mark that we can search for */
2357 /* sub-items in this item. */
2358 if ( iobuf->item_length[ilevel] == iobuf->sub_item_length[ilevel] )
2359 put_long(iobuf->item_length[ilevel] | 0x40000000L, iobuf);
2360 else
2361 put_long(iobuf->item_length[ilevel], iobuf);
2362 iobuf->data = save_data_ptr;
2363 }
2364
2365 rc = 0;
2366
2367 /* For a top-level item, write the whole data now. */
2368 if ( (iobuf->item_level=item_header->level) == 0 )
2369 rc = write_io_block(iobuf);
2370
2371 return rc;
2372}
2373
2374/* ------------------------- unput_item -------------------------- */
2375/**
2376 * @short Undo writing at the present level.
2377 *
2378 * When writing to an I/O buffer, revert anything yet written
2379 * at the present level. If the buffer was extended, the last
2380 * length is kept.
2381 *
2382 * @param iobuf I/O buffer descriptor.
2383 * @param item_header Header of item last read.
2384 *
2385 * @return 0 (ok), -1 (error)
2386 *
2387 */
2388
2389#ifdef ANSI_C
2390int unput_item (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2391#else
2392int unput_item (iobuf, item_header)
2393 IO_BUFFER *iobuf;
2394 IO_ITEM_HEADER *item_header;
2395#endif
2396{
2397 int old_level;
2398
2399 /* Have we been in writing mode ? Or was it reading? */
2400 if ( iobuf->r_remaining != -1 )
2401 return -1;
2402 /* At what level of nesting was this item created ? */
2403 old_level = item_header->level;
2404 if ( old_level < 0 || old_level >= MAX_IO_ITEM_LEVEL ||
2405 old_level >= iobuf->item_level )
2406 return -1;
2407 /* Set the data pointer back to before the current item */
2408 if ( (iobuf->item_level = old_level) == 0 )
2409 iobuf->data = iobuf->buffer;
2410 else
2411 iobuf->data = iobuf->buffer +
2412 iobuf->item_start_offset[old_level] - 12;
2413 /* The rest of the buffer is available for writing */
2414 iobuf->w_remaining = iobuf->buflen -
2415 (long) (iobuf->data-iobuf->buffer);
2416
2417 return 0;
2418}
2419
2420/* ------------------------ get_item_begin ----------------------- */
2421/**
2422 * @short Begin reading an item. Reads the header of an item.
2423 *
2424 * Reads the header of an item. If a specific item
2425 * type is requested but a different type is found and the
2426 * length of that item is known, the item is skipped.
2427 *
2428 * @param iobuf The input buffer descriptor.
2429 * @param item_header The item header descriptor.
2430 *
2431 * @return 0 (O.k.), -1 (error), -2 (end-of-buffer) or
2432 * -3 (wrong item type).
2433 *
2434 */
2435
2436#ifdef ANSI_C
2437int get_item_begin (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2438#else
2439int get_item_begin (iobuf,item_header)
2440 IO_BUFFER *iobuf;
2441 IO_ITEM_HEADER *item_header;
2442#endif
2443{
2444 long sync_tag;
2445 unsigned long this_type;
2446 unsigned long wanted_type;
2447 REGISTER int ilevel;
2448 BYTE *previous_position;
2449 long previous_remaining;
2450 int previous_level, previous_order;
2451 long length;
2452
2453 if ( iobuf == (IO_BUFFER *) NULL )
2454 return -1;
2455
2456 iobuf->w_remaining = -1;
2457
2458 previous_position = iobuf->data;
2459 previous_remaining = iobuf->r_remaining;
2460 previous_level = ilevel = iobuf->item_level;
2461 previous_order = iobuf->byte_order;
2462
2463 if ( ilevel >= MAX_IO_ITEM_LEVEL )
2464 {
2465 Warning("Maximum level of sub-items in I/O Buffer exceeded");
2466 iobuf->r_remaining = -1;
2467 }
2468
2469 /* Are we beyond the last sub-item? */
2470 if ( ilevel > 0 )
2471 {
2472 /* First check if we are already beyond the top item and then if we */
2473 /* will be beyond the next smaller level (superiour) item after */
2474 /* reading this item's header. */
2475 if ( (long) (iobuf->data-iobuf->buffer) >= iobuf->item_length[0] + 16 ||
2476 (long) (iobuf->data-iobuf->buffer) + 12 >=
2477 iobuf->item_start_offset[ilevel-1] + iobuf->item_length[ilevel-1] )
2478 return -2;
2479 }
2480 /* When starting a top item, additional work has to be done. */
2481 else if ( ilevel == 0 )
2482 {
2483 if ( iobuf->data_pending < 0 )
2484 {
2485 Warning("You must get an I/O block before you can read items");
2486 return -1;
2487 }
2488 /* Make sure that buffer memory has been allocated. */
2489 if ( iobuf->buffer == (BYTE *) NULL )
2490 {
2491 Warning("No memory allocated for I/O buffer");
2492 return -1;
2493 }
2494 iobuf->data = iobuf->buffer;
2495 iobuf->r_remaining = iobuf->buflen;
2496
2497 /* Reset the byte-order flag and then check the byte order. */
2498 iobuf->byte_order = 0;
2499 sync_tag = get_long(iobuf);
2500
2501#ifdef SIXTY_FOUR_BITS
2502 if ( (int32_t) sync_tag == (int32_t) 0xD41F8A37 )
2503 iobuf->byte_order = 0;
2504 else if ( (int32_t) sync_tag == (int32_t) 0x378A1FD4 )
2505 iobuf->byte_order = 1;
2506#else
2507 if ( sync_tag == 0xD41F8A37L )
2508 iobuf->byte_order = 0;
2509 else if ( sync_tag == 0x378A1FD4L )
2510 iobuf->byte_order = 1;
2511#endif
2512 else
2513 {
2514 Warning("Invalid byte ordering of input data");
2515 return -1;
2516 }
2517 }
2518
2519 /* Remember the requested item type. */
2520 wanted_type = item_header->type;
2521 /* Extract the actual type and version from the 'type/version' field. */
2522 this_type = (unsigned long) get_long(iobuf);
2523 item_header->type = this_type & 0x0000ffffL;
2524 item_header->version = (unsigned) (this_type >> 20) & 0xfff;
2525
2526 /* Extract the identification number */
2527 item_header->ident = get_long(iobuf);
2528
2529 /* If bit 30 of length is set the item consists only of sub-items. */
2530 if ( ((length = get_long(iobuf)) & 0x40000000L) != 0 )
2531 {
2532 item_header->can_search = 1;
2533 length &= ~0x40000000L; /* Clear bit 30 */
2534 iobuf->sub_item_length[ilevel] = length;
2535 }
2536 else
2537 {
2538 item_header->can_search = 0;
2539 iobuf->sub_item_length[ilevel] = 0;
2540 }
2541 iobuf->item_length[ilevel] = length;
2542
2543 /* The present position in the I/O buffer is the start of item data. */
2544 iobuf->item_start_offset[ilevel] = (long) (iobuf->data - iobuf->buffer);
2545
2546 /* Only data up to the end of the top item may be read, not up to */
2547 /* end of the allocated I/O buffer memory. */
2548 if ( ilevel == 0 )
2549 iobuf->r_remaining = iobuf->item_length[0];
2550
2551 /* If a specified item-type is wanted but a different one is */
2552 /* found, the previous state is restored. */
2553 if ( wanted_type > 0 && wanted_type != item_header->type )
2554 {
2555 iobuf->data = previous_position;
2556 iobuf->r_remaining = previous_remaining;
2557 iobuf->item_level = previous_level;
2558 iobuf->byte_order = previous_order;
2559 return -3;
2560 }
2561
2562 /* The current item level is saved and then incremented. */
2563 item_header->level = iobuf->item_level++;
2564
2565 if ( iobuf->r_remaining < 0 )
2566 return -1;
2567
2568 return 0;
2569}
2570
2571/* ------------------------ get_item_end ------------------------- */
2572/**
2573 * @short End reading an item.
2574 *
2575 * Finish reading an item. The pointer in the I/O buffer is at
2576 * the end of the item after this call, if succesful.
2577 *
2578 * @param iobuf I/O buffer descriptor.
2579 * @param item_header Header of item last read.
2580 *
2581 * @return 0 (ok), -1 (error)
2582 *
2583 */
2584
2585#ifdef ANSI_C
2586int get_item_end (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2587#else
2588int get_item_end (iobuf, item_header)
2589 IO_BUFFER *iobuf;
2590 IO_ITEM_HEADER *item_header;
2591#endif
2592{
2593 long length;
2594 REGISTER int ilevel;
2595
2596 if ( item_header->level != iobuf->item_level-1 )
2597 {
2598 if ( item_header->level >= iobuf->item_level )
2599 {
2600 Warning("Attempt to finish getting an item which is not active");
2601 return 0; /* This item level is (no more) active -- forget it */
2602 }
2603 else
2604 Warning("Item level is inconsistent");
2605 }
2606 if (item_header->level >= 0 && item_header->level <= MAX_IO_ITEM_LEVEL)
2607 ilevel = iobuf->item_level = item_header->level;
2608 else
2609 return -1;
2610
2611 /* If the item has a length specified, check it. */
2612 if ( iobuf->item_length[ilevel] >= 0 )
2613 if ( iobuf->item_length[ilevel] !=
2614 (length = (long) (iobuf->data - iobuf->buffer) -
2615 iobuf->item_start_offset[ilevel]) )
2616 {
2617 if ( length > iobuf->item_length[ilevel] )
2618 {
2619 char msg[256];
2620 (void) sprintf(msg,
2621 "Actual length of item type %lu exceeds specified length",
2622 item_header->type);
2623 Warning(msg);
2624 }
2625 iobuf->data = iobuf->buffer +
2626 (iobuf->item_start_offset[ilevel] + iobuf->item_length[ilevel]);
2627 }
2628
2629 /* After having finished a top item no further data may be read. */
2630 if ( iobuf->item_level == 0 )
2631 iobuf->r_remaining = -1L;
2632 else
2633 iobuf->r_remaining = iobuf->item_length[0] + 16 -
2634 (long) (iobuf->data - iobuf->buffer);
2635 iobuf->w_remaining = 0;
2636
2637 return 0;
2638}
2639
2640/* ------------------------- unget_item -------------------------- */
2641/**
2642 * @short Go back to the beginning of an item being read.
2643 *
2644 * When reading from an I/O buffer, go back to the beginning of
2645 * an item (more precisely: its header) currently being read.
2646 *
2647 * @param iobuf I/O buffer descriptor.
2648 * @param item_header Header of item last read.
2649 *
2650 * @return 0 (ok), -1 (error)
2651 *
2652 */
2653
2654#ifdef ANSI_C
2655int unget_item (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2656#else
2657int unget_item (iobuf, item_header)
2658 IO_BUFFER *iobuf;
2659 IO_ITEM_HEADER *item_header;
2660#endif
2661{
2662 int old_level;
2663
2664 old_level = item_header->level;
2665 if ( old_level < 0 || old_level >= MAX_IO_ITEM_LEVEL ||
2666 old_level >= iobuf->item_level )
2667 return -1;
2668 if ( (iobuf->item_level = old_level) == 0 )
2669 iobuf->data = iobuf->buffer;
2670 else
2671 iobuf->data = iobuf->buffer +
2672 iobuf->item_start_offset[old_level] - 12;
2673 iobuf->r_remaining = iobuf->item_length[0] + 16 -
2674 (long) (iobuf->data-iobuf->buffer);
2675 iobuf->w_remaining = -1;
2676
2677 return 0;
2678}
2679
2680/* ------------------------ next_subitem_type ----------------------- */
2681/**
2682 * Reads the header of a sub-item and return the type of it.
2683 *
2684 * @param iobuf The input buffer descriptor.
2685 *
2686 * @return >= 0 (O.k.), -1 (error), -2 (end-of-buffer).
2687 */
2688
2689#ifdef ANSI_C
2690int next_subitem_type (IO_BUFFER *iobuf)
2691#else
2692int next_subitem_type (iobuf)
2693 IO_BUFFER *iobuf;
2694#endif
2695{
2696 int this_type;
2697 REGISTER int ilevel;
2698 BYTE *previous_position;
2699
2700 if ( iobuf == (IO_BUFFER *) NULL )
2701 return -1;
2702
2703 previous_position = iobuf->data;
2704 ilevel = iobuf->item_level;
2705
2706 if ( ilevel >= MAX_IO_ITEM_LEVEL )
2707 {
2708 Warning("Maximum level of sub-items in I/O Buffer exceeded");
2709 iobuf->r_remaining = -1;
2710 }
2711
2712 /* Are we beyond the last sub-item? */
2713 if ( ilevel > 0 )
2714 {
2715 /* First check if we are already beyond the top item and then if we */
2716 /* will be beyond the next smaller level (superiour) item after */
2717 /* reading this item's header. */
2718 if ( (long) (iobuf->data-iobuf->buffer) >= iobuf->item_length[0] + 16 ||
2719 (long) (iobuf->data-iobuf->buffer) + 12 >=
2720 iobuf->item_start_offset[ilevel-1] + iobuf->item_length[ilevel-1] )
2721 return -2;
2722 }
2723 /* Not for top-level items */
2724 else if ( ilevel == 0 )
2725 return -1;
2726
2727 /* Extract the actual type and version from the 'type/version' field. */
2728 this_type = (int) ((unsigned long) get_long(iobuf)) & 0x0000ffffL;
2729 iobuf->data = previous_position;
2730
2731 return this_type;
2732}
2733
2734/* ------------------------ next_subitem_type ----------------------- */
2735/**
2736 * Reads the header of a sub-item and return the length of it.
2737 *
2738 * @param iobuf The input buffer descriptor.
2739 *
2740 * @return >= 0 (O.k.), -1 (error), -2 (end-of-buffer).
2741 */
2742
2743#ifdef ANSI_C
2744long next_subitem_length (IO_BUFFER *iobuf)
2745#else
2746long next_subitem_length (iobuf)
2747 IO_BUFFER *iobuf;
2748#endif
2749{
2750 IO_ITEM_HEADER item_header;
2751 int rc;
2752 long len;
2753
2754 item_header.type = 0;
2755 if ( (rc = get_item_begin(iobuf,&item_header)) < 0 )
2756 return rc;
2757 len = iobuf->item_length[iobuf->item_level-1];
2758 if ( (rc = get_item_end(iobuf,&item_header)) < 0 )
2759 return rc;
2760 return len;
2761}
2762
2763/* ----------------------- skip_subitem ----------------------------- */
2764/**
2765 * When the next sub-item is of no interest, it can be skipped.
2766 *
2767 * @param iobuf I/O buffer descriptor.
2768 * @param item_header Header of item last read.
2769 *
2770 * @return 0 (ok), -1 (error)
2771 *
2772 */
2773
2774#ifdef ANSI_C
2775int skip_subitem (IO_BUFFER *iobuf)
2776#else
2777int skip_subitem (iobuf)
2778 IO_BUFFER *iobuf;
2779#endif
2780{
2781 IO_ITEM_HEADER item_header;
2782 int rc;
2783
2784 item_header.type = 0;
2785 if ( (rc = get_item_begin(iobuf,&item_header)) < 0 )
2786 return rc;
2787 return get_item_end(iobuf,&item_header);
2788}
2789
2790/* ---------------------- search_sub_item ------------------------ */
2791/**
2792 * @short Search for an item of a specified type.
2793 *
2794 * Search for an item of a specified type, starting at the current
2795 * position in the I/O buffer. After successful action the
2796 * buffer data pointer points to the beginning of the header
2797 * of the first item of that type. If no such item is found,
2798 * it points right after the end of the item of
2799 * the next higher level.
2800 *
2801 * @param iobuf The I/O buffer descriptor.
2802 * @param type The requested item type.
2803 *
2804 * @return 0 (O.k., sub-item was found),
2805 * -1 (error),
2806 * -2 (no such sub-item),
2807 * -3 (cannot skip sub-items),
2808 *
2809 */
2810
2811#ifdef ANSI_C
2812int search_sub_item (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header,
2813 IO_ITEM_HEADER *sub_item_header)
2814#else
2815int search_sub_item (iobuf, item_header, sub_item_header)
2816 IO_BUFFER *iobuf;
2817 IO_ITEM_HEADER *item_header;
2818 IO_ITEM_HEADER *sub_item_header;
2819#endif
2820{
2821 int rc;
2822 unsigned long type;
2823 int old_level;
2824
2825 if ( !item_header->can_search )
2826 return -3;
2827 old_level = item_header->level;
2828 sub_item_header->level = old_level + 1;
2829 type = sub_item_header->type;
2830
2831 while ( iobuf->r_remaining > 0 )
2832 {
2833 sub_item_header->type = 0;
2834 rc = get_item_begin(iobuf,sub_item_header);
2835 if ( rc == -1 || rc == -2)
2836 {
2837 iobuf->item_level = old_level + 1;
2838 return(rc); /* Error or end of the item. */
2839 }
2840 if ( sub_item_header->type == type || type <= 0 )
2841 {
2842 iobuf->data = iobuf->buffer +
2843 iobuf->item_start_offset[iobuf->item_level-1] - 12;
2844 iobuf->r_remaining = iobuf->item_length[0] + 16 -
2845 (long) (iobuf->data-iobuf->buffer);
2846 iobuf->item_level = old_level + 1;
2847 return 0; /* This is the right type of item. */
2848 }
2849 if ( iobuf->item_length[iobuf->item_level-1] == -1L )
2850 return -3; /* Cannot skip because length is unknown. */
2851 get_item_end(iobuf,sub_item_header);
2852 }
2853
2854 return -2;
2855}
2856
2857/* ---------------------- rewind_item ----------------------- */
2858/**
2859 * @short Go back to the beginning of an item.
2860 * When reading from an I/O buffer, go back to the beginning
2861 * of the data area of an item. This is typically used when
2862 * searching for different types of sub-blocks but processing
2863 * should not depend on the relative order of them.
2864 *
2865 * @param iobuf I/O buffer descriptor.
2866 * @param item_header Header of item last read.
2867 *
2868 * @return 0 (ok), -1 (error)
2869 */
2870
2871#ifdef ANSI_C
2872int rewind_item (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2873#else
2874int rewind_item (iobuf, item_header)
2875 IO_BUFFER *iobuf;
2876 IO_ITEM_HEADER *item_header;
2877#endif
2878{
2879 int old_level;
2880
2881 old_level = item_header->level;
2882 if ( old_level < 0 || old_level >= MAX_IO_ITEM_LEVEL ||
2883 old_level >= iobuf->item_level )
2884 return -1;
2885 iobuf->item_level = old_level + 1;
2886 iobuf->data = iobuf->buffer + iobuf->item_start_offset[old_level];
2887 iobuf->r_remaining = iobuf->item_length[0] + 16 -
2888 (long) (iobuf->data-iobuf->buffer);
2889 iobuf->w_remaining = -1;
2890
2891 return 0;
2892}
2893
2894/* -------------------- remove_item ----------------------- */
2895/**
2896 * @short Remove an item from an I/O buffer.
2897 *
2898 * If writing an item has already started and then some
2899 * condition was found to remove the item again, this is
2900 * the function for it. The item to be removed should be the
2901 * last one written, since anything following it will be forgotten too.
2902 *
2903 * @param iobuf I/O buffer descriptor.
2904 * @param item_header Header of item to be removed.
2905 *
2906 * @return 0 (ok), -1 (error)
2907 */
2908
2909#ifdef ANSI_C
2910int remove_item (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
2911#else
2912int remove_item (iobuf, item_header)
2913 IO_BUFFER *iobuf;
2914 IO_ITEM_HEADER *item_header;
2915#endif
2916{
2917 REGISTER int ilevel, jlevel;
2918 BYTE *save_data_ptr;
2919 long old_length;
2920
2921 if ( (ilevel = (--iobuf->item_level)) < 0 )
2922 return -1;
2923 if ( iobuf->item_length[ilevel] < 0 || iobuf->item_length[ilevel] +
2924 iobuf->item_start_offset[ilevel]
2925 > iobuf->buflen )
2926 return -1;
2927
2928 old_length = iobuf->item_length[0] + 16;
2929
2930 for (jlevel=ilevel-1; jlevel>=0; jlevel--)
2931 {
2932 if (iobuf->item_length[jlevel] >= iobuf->item_length[ilevel] )
2933 iobuf->item_length[jlevel] -= iobuf->item_length[ilevel] + 12;
2934 else
2935 iobuf->item_length[jlevel] = 0;
2936 iobuf->sub_item_length[jlevel] -= iobuf->item_length[ilevel] + 12;
2937
2938 /* Now save the length field at its place right in front of the */
2939 /* beginning of data of that item. */
2940 save_data_ptr = iobuf->data;
2941 iobuf->w_remaining = 4;
2942 iobuf->data = iobuf->buffer + (iobuf->item_start_offset[jlevel] - 4);
2943 /* If that item consists entirely of sub-items with known lengths */
2944 /* set bit 30 of the length field to mark that we can search for */
2945 /* sub-items in this item. */
2946 if ( iobuf->item_length[jlevel] == iobuf->sub_item_length[jlevel] )
2947 put_long(iobuf->item_length[jlevel] | 0x40000000L, iobuf);
2948 else
2949 put_long(iobuf->item_length[jlevel], iobuf);
2950 iobuf->data = save_data_ptr;
2951 }
2952
2953 if ( iobuf->item_length[0] > 0 )
2954 {
2955 memmove((void *)(iobuf->buffer + iobuf->item_start_offset[ilevel] - 12),
2956 (void *)(iobuf->buffer + iobuf->item_start_offset[ilevel] +
2957 iobuf->item_length[ilevel]), (size_t)(old_length -
2958 (iobuf->item_start_offset[ilevel] + iobuf->item_length[ilevel])));
2959 }
2960
2961 iobuf->data = iobuf->buffer + /* item_header->start_of_data */
2962 iobuf->item_start_offset[ilevel] - 4;
2963 item_header->type = 0;
2964 iobuf->item_length[ilevel] = 0;
2965 iobuf->r_remaining = iobuf->item_length[0] + 16 -
2966 (long) (iobuf->data - iobuf->buffer);
2967 iobuf->w_remaining = -1;
2968
2969 return 0;
2970}
2971
2972/* -------------------- list_sub_items --------------------------- */
2973/**
2974 * @short Display the contents of sub-items on standard output.
2975 *
2976 * Display the contents (item types, versions, idents and lengths)
2977 * of sub-items on standard output.
2978 *
2979 * @param iobuf I/O buffer descriptor.
2980 * @param item_header Header of the item from which to show contents.
2981 * @param maxlevel The maximum nesting depth to show contents
2982 * (counted from the top-level item on).
2983 *
2984 * @return 0 (ok), -1 (error)
2985 */
2986
2987#ifdef ANSI_C
2988int list_sub_items (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header,
2989 int maxlevel)
2990#else
2991int list_sub_items (iobuf, item_header, maxlevel)
2992 IO_BUFFER *iobuf;
2993 IO_ITEM_HEADER *item_header;
2994 int maxlevel;
2995#endif
2996{
2997 IO_ITEM_HEADER sub_item_header;
2998 int rc, i;
2999 char msg[512];
3000
3001 if ( iobuf->item_level == 0 )
3002 {
3003 item_header->type = 0;
3004 get_item_begin(iobuf,item_header);
3005 sprintf(msg,"\nType %4lu, version %u, length %ld",
3006 item_header->type, item_header->version, iobuf->item_length[0]);
3007 Output(msg);
3008 if ( item_header->ident >= 0 )
3009 {
3010 sprintf(msg," (id %ld = 0x%lx)",
3011 item_header->ident,item_header->ident);
3012 Output(msg);
3013 }
3014 Output("\n");
3015 }
3016
3017 if ( maxlevel >= 0 && maxlevel < iobuf->item_level )
3018 return 0;
3019 if ( (long) (iobuf->data-iobuf->buffer) >= iobuf->item_length[0] + 12 )
3020 return 0;
3021
3022 sub_item_header.type = 0;
3023 iobuf->data = iobuf->buffer +
3024 iobuf->item_start_offset[iobuf->item_level-1];
3025 while ( (rc=search_sub_item(iobuf,item_header,&sub_item_header)) == 0 )
3026 {
3027 get_item_begin(iobuf,&sub_item_header);
3028 for (i=0; i<iobuf->item_level-1; i++)
3029 Output(" ");
3030 sprintf(msg,"Type %4lu, version %u, length %ld",
3031 sub_item_header.type, sub_item_header.version,
3032 iobuf->item_length[iobuf->item_level-1]);
3033 Output(msg);
3034 if ( sub_item_header.ident >= 0 )
3035 {
3036 sprintf(msg," (id %ld = 0x%lx)",sub_item_header.ident,
3037 sub_item_header.ident);
3038 Output(msg);
3039 }
3040 Output("\n");
3041 if ( sub_item_header.can_search )
3042 if ( (i=list_sub_items(iobuf,&sub_item_header,maxlevel)) < 0 )
3043 {
3044 sprintf(msg," (rc=%d)\n",i);
3045 Output(msg);
3046 }
3047 get_item_end(iobuf,&sub_item_header);
3048 sub_item_header.type = 0;
3049 }
3050 if ( iobuf->item_level == 0 )
3051 Output("\n");
3052
3053 if ( item_header->level == 0 )
3054 get_item_end(iobuf,item_header);
3055 if ( rc == -2 )
3056 return 0;
3057 else
3058 return rc;
3059}
3060
3061/* ----------------------- reset_io_block ------------------------ */
3062/**
3063 * Reset an I/O block to its empty status.
3064 *
3065 * @param iobuf The I/O buffer descriptor.
3066 *
3067 * @return 0 (O.k.), -1 (error)
3068 *
3069 */
3070
3071#ifdef ANSI_C
3072int reset_io_block (IO_BUFFER *iobuf)
3073#else
3074int reset_io_block (iobuf)
3075 IO_BUFFER *iobuf;
3076#endif
3077{
3078 BYTE *tptr;
3079
3080 if ( iobuf == (IO_BUFFER *) NULL )
3081 return -1;
3082 iobuf->w_remaining = iobuf->r_remaining = -1L;
3083 iobuf->item_level = 0;
3084 iobuf->item_length[0] = iobuf->sub_item_length[0] = 0;
3085 iobuf->data_pending = -1;
3086 iobuf->data = iobuf->buffer;
3087 if ( iobuf->buflen != iobuf->min_length )
3088 {
3089 tptr = (BYTE *) realloc((void *)iobuf->buffer,
3090 (size_t)iobuf->min_length);
3091 if ( tptr != (BYTE *) NULL )
3092 {
3093 iobuf->buffer = tptr;
3094 iobuf->buflen = iobuf->min_length;
3095 }
3096 }
3097 iobuf->data = iobuf->buffer;
3098 iobuf->regular = 0;
3099 return 0;
3100}
3101
3102/* ----------------------- write_io_block ------------------------ */
3103/**
3104 * @short Write an I/O block to the block's output.
3105 *
3106 * The complete I/O block is written to the output destination,
3107 * which can be raw I/O (through write), buffered I/O (through
3108 * fwrite) or user-defined I/O (through a user funtion).
3109 * All items must have been closed before.
3110 *
3111 * @param iobuf The I/O buffer descriptor.
3112 *
3113 * @return 0 (O.k.), -1 (error), -2 (item has no data)
3114 *
3115 */
3116
3117#ifdef ANSI_C
3118int write_io_block (IO_BUFFER *iobuf)
3119#else
3120int write_io_block (iobuf)
3121 IO_BUFFER *iobuf;
3122#endif
3123{
3124 int rc;
3125 int length;
3126
3127 if ( iobuf == (IO_BUFFER *) NULL )
3128 return -1;
3129#ifdef OS_MSDOS
3130 if ( (long) (iobuf->data-iobuf->buffer) > 32767 )
3131 {
3132 Warning("Cannot write item of length exceeding 32767 bytes");
3133 return -1;
3134 }
3135#endif
3136 /* length = (int) (iobuf->data-iobuf->buffer); */
3137 /* Empty top items are not written */
3138 /* if ( length < 16 ) */
3139 /* return -2; */
3140 length = 16 + iobuf->item_length[0];
3141
3142 rc = 0;
3143 if ( iobuf->item_level > 0 )
3144 {
3145 Warning("Output cancelled because item level is not 0");
3146 rc = -1;
3147 }
3148 else if ( iobuf->item_length[0] < 0L )
3149 {
3150 Warning("Output cancelled due to invalid length of top item");
3151 rc = -1;
3152 }
3153 else if ( iobuf->output_fileno >= 0 )
3154 {
3155 if (write(iobuf->output_fileno,(char *)iobuf->buffer,(size_t)length) == -1 )
3156 {
3157 Warning("Output error for I/O buffer");
3158 rc = -1;
3159 }
3160 }
3161 else if ( iobuf->output_file != (FILE *) NULL )
3162 {
3163 if ( fwrite((void *)iobuf->buffer,(size_t)1,(size_t)length,
3164 iobuf->output_file) != length )
3165 if ( ferror(iobuf->output_file) )
3166 {
3167 Warning("Output error for I/O buffer");
3168 clearerr(iobuf->output_file);
3169 rc = -1;
3170 }
3171 }
3172 else if ( iobuf->user_function != NULL )
3173 {
3174 rc = (iobuf->user_function)(iobuf->buffer,(long)length,1);
3175 }
3176 else
3177 {
3178 Warning("Output cancelled because no output file/function set.");
3179 rc = -1;
3180 }
3181
3182 iobuf->data = iobuf->buffer;
3183 iobuf->w_remaining = iobuf->r_remaining = -1L;
3184
3185 return rc;
3186}
3187
3188/* ----------------------- find_io_block ------------------------ */
3189/**
3190 * @short Find the beginning of the next I/O data block in the input.
3191 *
3192 * Read byte for byte from the input file specified
3193 * for the I/O buffer and look for the sync-tag (magic
3194 * number in little-endian or big-endian byte order.
3195 * As long as the input is properly synchronized this
3196 * sync-tag should be found in the first four bytes.
3197 * Otherwise, input data is skipped until the next
3198 * sync-tag is found. After the sync tag 10 more bytes
3199 * (item type, version number, and length field) are read.
3200 * The type of I/O (raw, buffered, or user-defined) depends
3201 * on the settings of the I/O block.
3202 *
3203 * @param iobuf The I/O buffer descriptor.
3204 * @param type The requested item type.
3205 *
3206 * @return 0 (O.k.), -1 (error), or -2 (end-of-file)
3207 *
3208 */
3209
3210#ifdef ANSI_C
3211int find_io_block (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
3212#else
3213int find_io_block (iobuf, item_header)
3214 IO_BUFFER *iobuf;
3215 IO_ITEM_HEADER *item_header;
3216#endif
3217{
3218 long sync_count = 0;
3219 int block_found, byte_number, byte_order;
3220 int rc = 0;
3221#ifdef ANSI_C_99
3222 const BYTE sync_tag_byte[] = { 0xD4, 0x1F, 0x8A, 0x37 };
3223#else
3224 static BYTE sync_tag_byte[] = { 0xD4, 0x1F, 0x8A, 0x37 };
3225#endif
3226
3227 if ( iobuf == (IO_BUFFER *) NULL || item_header == (IO_ITEM_HEADER *) NULL )
3228 return -1;
3229 if ( iobuf->data_pending > 0 )
3230 {
3231 Warning("You forgot to read or skip the data of the previous I/O block");
3232 return -1;
3233 }
3234 iobuf->item_level = 0;
3235 iobuf->data = iobuf->buffer;
3236 iobuf->w_remaining = iobuf->r_remaining = -1L;
3237 if ( iobuf->buffer == (BYTE *) NULL || iobuf->buflen < 16 )
3238 {
3239 Warning("Attempt to read data failed due to invalid I/O buffer");
3240 return -1;
3241 }
3242 if ( iobuf->input_fileno < 0 && iobuf->input_file == (FILE *) NULL &&
3243 iobuf->user_function == NULL )
3244 {
3245 Warning("No file specified from which I/O buffer should be read");
3246 return -1;
3247 }
3248
3249 if ( iobuf->input_fileno >= 0 || iobuf->input_file != (FILE *) NULL )
3250 {
3251 for ( sync_count=(-4L), block_found=byte_number=byte_order=0;
3252 !block_found; sync_count++ )
3253 {
3254 if ( iobuf->input_fileno >= 0 ) /* Use system read function */
3255 rc = READ_BYTES(iobuf->input_fileno,
3256 (char *)(iobuf->buffer+byte_number),1L);
3257 else if ( (char) (*(char *)(iobuf->buffer+byte_number) = (char)
3258 getc(iobuf->input_file)) != (char) EOF ) /* Use getc macro */
3259 rc = 1;
3260 else if ( ferror(iobuf->input_file) ) /* EOF may be valid byte */
3261 {
3262 clearerr(iobuf->input_file);
3263 rc = -1;
3264 }
3265 else if ( feof(iobuf->input_file) )
3266 {
3267#ifdef OS_OS9
3268 cleareof(iobuf->input_file);
3269#else
3270 clearerr(iobuf->input_file);
3271#endif
3272 rc = 0;
3273 }
3274 if ( rc <= 0 ) /* End-of-file or read error */
3275 {
3276 item_header->type = 0;
3277 iobuf->item_length[0] = 0;
3278 if ( rc == 0 ) /* EOF */
3279 return -2;
3280 else /* input error */
3281 return -1;
3282 }
3283 if ( byte_order == 0 )
3284 {
3285 if ( *iobuf->buffer == (BYTE) sync_tag_byte[0] )
3286 byte_order = 1;
3287 else if ( *iobuf->buffer == (BYTE) sync_tag_byte[3] )
3288 byte_order = -1;
3289 else
3290 continue;
3291 byte_number = 1;
3292 }
3293 else if ( byte_order == 1 )
3294 {
3295 if ( iobuf->buffer[byte_number] != sync_tag_byte[byte_number] )
3296 {
3297 byte_order = byte_number = 0;
3298 continue;
3299 }
3300 byte_number++;
3301 }
3302 else if ( byte_order == -1 )
3303 {
3304 if ( iobuf->buffer[byte_number] != sync_tag_byte[3-byte_number] )
3305 {
3306 byte_order = byte_number = 0;
3307 continue;
3308 }
3309 byte_number++;
3310 }
3311 if ( byte_number == 4 )
3312 block_found = 1;
3313 }
3314
3315 if ( iobuf->input_fileno >= 0 ) /* Use system read function */
3316 rc = READ_BYTES(iobuf->input_fileno,(char *)(iobuf->buffer+4),12L);
3317 else if ( (rc = fread((void *)(iobuf->buffer+4),(size_t)1,(size_t)12,
3318 iobuf->input_file)) == 0 )
3319 if ( ferror(iobuf->input_file) )
3320 rc = -1;
3321 if ( rc > 0 && rc != 12 )
3322 {
3323 char msg[256];
3324 sprintf(msg,
3325 "Wrong number of bytes were read (%d instead of %d)",rc,12);
3326 Warning(msg);
3327 return -1;
3328 }
3329 }
3330 else if ( iobuf->user_function != NULL )
3331 {
3332 rc = (iobuf->user_function)(iobuf->buffer,16L,2);
3333 }
3334
3335 if ( rc <= 0 ) /* End-of-file or read error */
3336 {
3337 item_header->type = 0;
3338 iobuf->item_length[0] = 0;
3339 item_header->can_search = 0;
3340 if ( rc == 0 ) /* EOF */
3341 return -2;
3342 else /* input error */
3343 return -1;
3344 }
3345
3346 item_header->type = 0;
3347 iobuf->data_pending = 1;
3348 if ( get_item_begin(iobuf,item_header) != 0 )
3349 return -1;
3350 iobuf->item_level = 0;
3351
3352 if ( sync_count > 0 )
3353 {
3354 char msg[256];
3355 (void) sprintf(msg,
3356 "Synchronization error. %ld bytes of data have been skipped",
3357 sync_count);
3358 Warning(msg);
3359 }
3360
3361 return 0;
3362}
3363
3364/* ------------------------ read_io_block ------------------------ */
3365/**
3366 * @short Read the data of an I/O block from the input.
3367 *
3368 * This function is called for reading data after an I/O data block
3369 * has been found (with find_io_block) on input.
3370 * The type of I/O (raw, buffered, or user-defined) depends
3371 * on the settings of the I/O block.
3372 *
3373 * @param iobuf The I/O buffer descriptor.
3374 * @param item_header The item header descriptor.
3375 *
3376 * @return 0 (O.k.),
3377 * -1 (error),
3378 * -2 (end-of-file),
3379 * -3 (block skipped because it is too large)
3380 *
3381 */
3382
3383#ifdef ANSI_C
3384int read_io_block (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
3385#else
3386int read_io_block (iobuf, item_header)
3387 IO_BUFFER *iobuf;
3388 IO_ITEM_HEADER *item_header;
3389#endif
3390{
3391 int rc = 0;
3392 int length;
3393
3394 if ( iobuf == (IO_BUFFER *) NULL || item_header == (IO_ITEM_HEADER *) NULL )
3395 return -1;
3396
3397 if ( iobuf->data_pending <= 0 )
3398 {
3399 Warning("You must find an I/O block before you can read it");
3400 return -1;
3401 }
3402
3403 if ( iobuf->item_level != 0 ||
3404 iobuf->item_length[0] < 0 )
3405 return -1;
3406#ifdef OS_MSDOS
3407 if ( iobuf->item_length[0] > 32767 )
3408 {
3409 Warning("Cannot read item of length exceeding 32767 bytes");
3410 return -1;
3411 }
3412#endif
3413 length = (size_t) iobuf->item_length[0];
3414
3415 if ( iobuf->buffer == (BYTE *) NULL )
3416 return -1;
3417
3418 if ( iobuf->buflen < iobuf->item_length[0]+16 )
3419 {
3420 if ( extend_io_buffer(iobuf,0,
3421 iobuf->item_length[0]+16-iobuf->buflen) == -1 )
3422 {
3423 Warning("I/O buffer too small; I/O block is skipped");
3424 if ( (rc = skip_io_block(iobuf,item_header)) < 0 )
3425 return rc;
3426 else
3427 return -3;
3428 }
3429 }
3430
3431 if ( length > 0 )
3432 {
3433 if ( iobuf->input_fileno >= 0 || iobuf->input_file != (FILE *) NULL )
3434 {
3435 if ( iobuf->input_fileno >= 0 )
3436 rc = READ_BYTES(iobuf->input_fileno,(char *)(iobuf->buffer+16),length);
3437 else if ( (rc = fread((void *)(iobuf->buffer+16),(size_t)1,(size_t)length,
3438 iobuf->input_file)) == 0 )
3439 if ( ferror(iobuf->input_file) )
3440 rc = -1;
3441 if ( rc > 0 && rc != length )
3442 {
3443 char msg[256];
3444 sprintf(msg,
3445 "Wrong number of bytes were read (%d instead of %d)",rc,length);
3446 Warning(msg);
3447 return -1;
3448 }
3449 }
3450 else if ( iobuf->user_function != NULL )
3451 rc = (iobuf->user_function)(iobuf->buffer+16,(long)length,3);
3452 else
3453 rc = -1;
3454 }
3455 else if ( length < 0 )
3456 rc = -1;
3457
3458 if ( rc <= 0 && length != 0 ) /* End-of-file or read error */
3459 {
3460 item_header->type = 0;
3461 iobuf->item_length[0] = 0;
3462 if ( rc == 0 ) /* EOF */
3463 return -2;
3464 else /* input error */
3465 return -1;
3466 }
3467
3468 iobuf->data_pending = 0;
3469 return 0;
3470}
3471
3472/* ------------------------ skip_io_block ------------------------ */
3473/**
3474 * @short Skip the data of an I/O block from the input.
3475 *
3476 * Skip the data of an I/O block from the input
3477 * (after the block's header was read).
3478 * This is the alternative to read_io_block() after having
3479 * found an I/O block with find_io_block but realizing that
3480 * this is a type of block you don't know how to read or
3481 * simply not interested in.
3482 * The type of I/O (raw, buffered, or user-defined) depends
3483 * on the settings of the I/O block.
3484 *
3485 * @param iobuf The I/O buffer descriptor.
3486 * @param item_header The item header descriptor.
3487 *
3488 * @return 0 (O.k.), -1 (error) or -2 (end-of-file)
3489 *
3490 */
3491
3492#ifdef ANSI_C
3493int skip_io_block (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header)
3494#else
3495int skip_io_block (iobuf, item_header)
3496 IO_BUFFER *iobuf;
3497 IO_ITEM_HEADER *item_header;
3498#endif
3499{
3500 char tbuf[512];
3501 long nbuf, ibuf, length;
3502 int rbuf, rc = 0;
3503#ifndef FSTAT_NOT_AVAILABLE
3504 struct stat st;
3505#endif
3506
3507 if ( iobuf == (IO_BUFFER *) NULL || item_header == (IO_ITEM_HEADER *) NULL )
3508 return -1;
3509 if ( iobuf->data_pending <= 0 )
3510 {
3511 Warning("You must find an I/O block before you can skip it");
3512 return -1;
3513 }
3514 if ( iobuf->item_level != 0 || iobuf->item_length[0] < 0 )
3515 return -1;
3516 length = iobuf->item_length[0];
3517
3518 if ( iobuf->input_fileno < 0 && iobuf->user_function != NULL )
3519 return((iobuf->user_function)(iobuf->buffer,length,4));
3520
3521#ifndef FSTAT_NOT_AVAILABLE
3522 if ( iobuf->regular >= 0 )
3523 {
3524 if ( iobuf->input_fileno > 0 )
3525 {
3526 if ( iobuf->regular == 0 )
3527 {
3528 fstat(iobuf->input_fileno,&st);
3529#ifdef S_IFREG
3530 if ( st.st_mode & S_IFREG )
3531 iobuf->regular = 1;
3532 else
3533#endif
3534 iobuf->regular = -1;
3535 }
3536 if ( iobuf->regular == 1 )
3537 {
3538#ifdef __USE_LARGEFILE64
3539 /* Although blocks must be less than 2^31 bytes, we may */
3540 /* have to take care of large files on 32 bit machines. */
3541 if ( lseek64(iobuf->input_fileno,(off64_t)length,SEEK_CUR) == -1 )
3542 return -1;
3543#else
3544 if ( lseek(iobuf->input_fileno,length,SEEK_CUR) == -1 )
3545 return -1;
3546#endif
3547 iobuf->item_length[0] = 0;
3548 iobuf->data_pending = 0;
3549 return 0;
3550 }
3551 }
3552 else if ( iobuf->input_file != (FILE *) NULL )
3553 {
3554 if ( iobuf->regular == 0 )
3555 {
3556 fstat(fileno(iobuf->input_file),&st);
3557#ifdef S_IFREG
3558 if ( st.st_mode & S_IFREG )
3559 iobuf->regular = 1;
3560 else
3561#endif
3562 iobuf->regular = -1;
3563 }
3564 if ( iobuf->regular == 1 )
3565 {
3566#ifdef __USE_LARGEFILE64
3567 /* Although blocks must be less than 2^31 bytes, we may */
3568 /* have to take care of large files on 32 bit machines. */
3569 if ( fseeko64(iobuf->input_file,(off64_t)length,SEEK_CUR) == -1 )
3570 return -1;
3571#else
3572 if ( fseek(iobuf->input_file,length,SEEK_CUR) == -1 )
3573 return -1;
3574#endif
3575 iobuf->item_length[0] = 0;
3576 iobuf->data_pending = 0;
3577 return 0;
3578 }
3579 }
3580 }
3581#endif
3582
3583 nbuf = length/512;
3584 rbuf = length%512;
3585 if ( iobuf->input_fileno >= 0 )
3586 {
3587 for ( ibuf=0; ibuf<nbuf; ibuf++ )
3588 rc = READ_BYTES(iobuf->input_fileno,tbuf,512L);
3589 if ( rbuf > 0 )
3590 rc = READ_BYTES(iobuf->input_fileno,tbuf,rbuf);
3591 }
3592 else if ( iobuf->input_file != (FILE *) NULL )
3593 {
3594 for ( ibuf=0; ibuf<nbuf; ibuf++ )
3595 rc = fread((void *)tbuf,(size_t)1,(size_t)512,iobuf->input_file);
3596 if ( rbuf > 0 )
3597 rc = fread((void *)tbuf,(size_t)1,(size_t)rbuf,iobuf->input_file);
3598 if ( ferror(iobuf->input_file) )
3599 rc = -1;
3600 }
3601
3602 if ( rc <= 0 ) /* End-of-file or read error */
3603 {
3604 item_header->type = 0;
3605 if ( rc == 0 ) /* EOF */
3606 return -2;
3607 else /* input error */
3608 return -1;
3609 }
3610
3611 iobuf->data_pending = 0;
3612 return 0;
3613}
3614
3615/* ---------------------- list_io_blocks ------------------------- */
3616/**
3617 * Show the top-level item of an I/O block on standard output.
3618 *
3619 * List type, version, ident, and length) of the top item of all
3620 * I/O blocks in input file onto standard output.
3621 *
3622 * @param iobuf The I/O buffer descriptor.
3623 * @param item_header The item header descriptor.
3624 *
3625 * @return 0 (O.k.), -1 (error)
3626 *
3627 */
3628
3629#ifdef ANSI_C
3630int list_io_blocks (IO_BUFFER *iobuf)
3631#else
3632int list_io_blocks (iobuf)
3633 IO_BUFFER *iobuf;
3634#endif
3635{
3636 IO_ITEM_HEADER item_header;
3637 int rc;
3638 char msg[512];
3639
3640 Output("\n");
3641
3642 while ( (rc = find_io_block(iobuf,&item_header)) == 0 )
3643 {
3644 sprintf(msg,"Type %4lu, version %u, length %ld",
3645 item_header.type, item_header.version, iobuf->item_length[0]);
3646 Output(msg);
3647 if ( item_header.ident >= 0 )
3648 {
3649 sprintf(msg," (id %ld = 0x%lx)",
3650 item_header.ident,item_header.ident);
3651 Output(msg);
3652 }
3653 if ( iobuf->byte_order )
3654 Output(" with inverse byte order");
3655 Output("\n");
3656 if ( (rc = skip_io_block(iobuf,&item_header)) < 0 )
3657 {
3658 sprintf(msg,"(skip_io_block returned %d)\n\n",rc);
3659 Output(msg);
3660 return rc;
3661 }
3662 }
3663
3664 if ( rc != -2 )
3665 {
3666 sprintf(msg,"(find_io_block returned %d)\n\n",rc);
3667 Output(msg);
3668 return rc;
3669 }
3670 else
3671 {
3672 Output("\n");
3673 return 0;
3674 }
3675}
3676
3677/* ------------------ copy_item_to_io_block -------------------- */
3678/**
3679 * Copy a sub-item to another I/O buffer as top-level item.
3680 *
3681 * @param iobuf2 Target I/O buffer descriptor.
3682 * @param iobuf Source I/O buffer descriptor.
3683 * @param item_header Header for the item in iobuf that
3684 * should be copied to iobuf2.
3685 *
3686 * @return 0 (o.k.), -1 (error), -2 (not enough memory etc.)
3687 *
3688 */
3689
3690#ifdef ANSI_C
3691int copy_item_to_io_block (IO_BUFFER *iobuf2, IO_BUFFER *iobuf,
3692 IO_ITEM_HEADER *item_header)
3693#else
3694int copy_item_to_io_block (iobuf2, iobuf, item_header)
3695 IO_BUFFER *iobuf2;
3696 IO_BUFFER *iobuf;
3697 IO_ITEM_HEADER *item_header;
3698#endif
3699{
3700 int length;
3701 int ilevel;
3702
3703 if ( iobuf == (IO_BUFFER *) NULL || iobuf2 == (IO_BUFFER *) NULL ||
3704 item_header == (IO_ITEM_HEADER *) NULL )
3705 return -1;
3706 if ( iobuf->buffer == (BYTE *) NULL || iobuf2->buffer == (BYTE *) NULL )
3707 return -1;
3708
3709 if ( item_header->level != iobuf->item_level-1 )
3710 {
3711 Warning("Item level is inconsistent");
3712 return -1;
3713 }
3714 if (iobuf->item_level > 0 && iobuf->item_level <= MAX_IO_ITEM_LEVEL)
3715 ilevel = iobuf->item_level-1;
3716 else
3717 return -1;
3718#ifdef OS_MSDOS
3719 if ( iobuf->item_length[ilevel] > 32767 )
3720 {
3721 Warning("Cannot copy item of length exceeding 32767 bytes");
3722 return -1;
3723 }
3724#endif
3725 if ( (length = (int) iobuf->item_length[ilevel]) < 0 )
3726 return -1;
3727
3728 reset_io_block(iobuf2);
3729 iobuf2->byte_order = iobuf->byte_order;
3730
3731 if ( iobuf2->buflen < length+16 )
3732 {
3733 if ( extend_io_buffer(iobuf2,0,length+16-iobuf2->buflen) == -1 )
3734 {
3735 Warning("I/O buffer too small; item not copied");
3736 return -2;
3737 }
3738 }
3739
3740 memcpy((void *)iobuf2->buffer,(void *)iobuf->buffer,(size_t)4);
3741 memcpy((void *)(iobuf2->buffer+4),
3742 (void *)(iobuf->buffer+iobuf->item_start_offset[ilevel]-12),
3743 (size_t)(12+length));
3744 iobuf2->data = iobuf2->buffer+16+length;
3745 iobuf2->item_length[0] = length;
3746 iobuf2->sub_item_length[0] = iobuf->sub_item_length[ilevel];
3747 iobuf2->w_remaining = iobuf2->buflen - length - 16;
3748 iobuf2->item_level = 0;
3749
3750 iobuf->data = iobuf->buffer+iobuf->item_start_offset[ilevel]+length;
3751 iobuf->r_remaining -= length;
3752
3753 return 0;
3754}
3755
3756/* ---------------- append_io_block_as_item ------------------ */
3757/**
3758 * @short Append data from one I/O block into another one.
3759 *
3760 * Append the data from a complete i/o block as an additional
3761 * subitem to another i/o block.
3762 *
3763 * @param iobuf The target I/O buffer descriptor,
3764 * must be 'opened' for 'writing',
3765 * i.e. 'put_item_begin()' must be called.
3766 * @param item_header Item header of the item in
3767 * iobuf which is cuurently being filled.
3768 * @param buffer Data to be filled in. Must be all
3769 * data from an I/O buffer, including the
3770 * 4 signature bytes.
3771 * @param length The length of buffer in bytes.
3772 *
3773 * @return 0 (o.k.), -1 (error), -2 (not enough memory etc.)
3774 *
3775 */
3776
3777#ifdef ANSI_C
3778int append_io_block_as_item (IO_BUFFER *iobuf, IO_ITEM_HEADER *item_header,
3779 BYTE *buffer, long length)
3780#else
3781int append_io_block_as_item (iobuf, item_header, buffer, length)
3782 IO_BUFFER *iobuf;
3783 IO_ITEM_HEADER *item_header;
3784 BYTE *buffer;
3785 long length;
3786#endif
3787{
3788 int i, ilevel;
3789
3790 if ( iobuf == (IO_BUFFER *) NULL || buffer == (BYTE *) NULL ||
3791 item_header == (IO_ITEM_HEADER *) NULL )
3792 return -1;
3793 if ( iobuf->buffer == (BYTE *) NULL )
3794 return -1;
3795
3796 if ( iobuf->item_level <= 0 )
3797 {
3798 Warning("Cannot append to empty I/O block");
3799 return -1;
3800 }
3801 ilevel = iobuf->item_level - 1;
3802 if ( iobuf->w_remaining == -1 )
3803 {
3804 Warning("Cannot append to I/O block");
3805 return -1;
3806 }
3807
3808#ifdef OS_MSDOS
3809 if ( length > 32767 )
3810 {
3811 Warning("Cannot append block of length exceeding 32767 bytes");
3812 return -1;
3813 }
3814#endif
3815 if ( length < 16 )
3816 return -1;
3817 length -= 4;
3818
3819 for (i=0; i<4; i++)
3820 if ( iobuf->buffer[i] != buffer[i] )
3821 {
3822 if ( iobuf->buffer[0] != buffer[3] &&
3823 iobuf->buffer[1] != buffer[2] )
3824 Warning("Data to be appended is not an I/O buffer");
3825 else
3826 Warning("Cannot append to I/O block with different byte ordering");
3827 return -1;
3828 }
3829
3830 if ( iobuf->w_remaining < length )
3831 {
3832 if ( extend_io_buffer(iobuf,256,length) == -1 )
3833 {
3834 Warning("I/O buffer too small: nothing appended");
3835 return -2;
3836 }
3837 }
3838
3839 memcpy((void *)iobuf->data,(void *)(buffer+4),(size_t)(length));
3840 iobuf->data += length;
3841 iobuf->w_remaining -= length;
3842 iobuf->item_length[ilevel] += length;
3843 iobuf->sub_item_length[ilevel] += length;
3844
3845 return 0;
3846}
Note: See TracBrowser for help on using the repository browser.