1 /* ----------------------------- MNI Header -----------------------------------
2 @NAME : acr_io.c
3 @DESCRIPTION: Routines for doing basic acr_nema operations (reading and
4 writing an element).
5 @METHOD :
6 @GLOBALS :
7 @CREATED : November 10, 1993 (Peter Neelin)
8 @MODIFIED :
9 * $Log: acr_io.c,v $
10 * Revision 6.8 2008-08-12 05:00:22 rotor
11 * * large number of changes from Claude (64 bit and updates)
12 *
13 * Revision 6.7 2005/03/04 00:15:14 bert
14 * Lose public and private keywords; change acr_read_one_element to assume implicit VR format for special sequence delimiters (group 0xfffe)
15 *
16 * Revision 6.6 2004/10/29 13:08:41 rotor
17 * * rewrote Makefile with no dependency on a minc distribution
18 * * removed all references to the abominable minc_def.h
19 * * I should autoconf this really, but this is old code that
20 * is now replaced by Jon Harlaps PERL version..
21 *
22 * Revision 6.5 2000/08/16 15:53:46 neelin
23 * Added VR type UN (unknown) which has a length field similar to OB.
24 *
25 * Revision 6.4 2000/05/01 17:54:02 neelin
26 * Improved testing of input stream to figure out byte order for both
27 * implicit and expicit VR.
28 *
29 * Revision 6.3 2000/04/28 15:03:10 neelin
30 * Added support for ignoring non-fatal protocol errors (cases where redundant
31 * information is inconsistent). In particular, it is possible to ignore
32 * differences between the group length element and the true group length.
33 *
34 * Revision 6.2 1999/10/29 17:51:49 neelin
35 * Fixed Log keyword
36 *
37 * Revision 6.1 1999/10/27 20:13:15 neelin
38 * Generalized acr_test_byte_order to recognize groups without a length element.
39 *
40 * Revision 6.0 1997/09/12 13:23:59 neelin
41 * Release of minc version 0.6
42 *
43 * Revision 5.1 1997/09/08 21:53:31 neelin
44 * Added status ACR_CONNECTION_TIMEDOUT.
45 *
46 * Revision 5.0 1997/08/21 13:25:00 neelin
47 * Release of minc version 0.5
48 *
49 * Revision 4.1 1997/07/10 17:14:38 neelin
50 * Added more status codes and function to return status string.
51 *
52 * Revision 4.0 1997/05/07 20:01:23 neelin
53 * Release of minc version 0.4
54 *
55 * Revision 3.1 1997/04/21 20:21:09 neelin
56 * Updated the library to handle dicom messages.
57 *
58 * Revision 3.0 1995/05/15 19:32:12 neelin
59 * Release of minc version 0.3
60 *
61 * Revision 2.1 1995/02/08 21:16:06 neelin
62 * Changes to make irix 5 lint happy.
63 *
64 * Revision 2.0 1994/09/28 10:36:06 neelin
65 * Release of minc version 0.2
66 *
67 * Revision 1.9 94/09/28 10:35:39 neelin
68 * Pre-release
69 *
70 * Revision 1.8 94/09/23 16:42:35 neelin
71 * Changed acr_nema_io to acr_io and acr_nema_test to acr_test.
72 *
73 * Revision 1.7 94/05/18 08:47:43 neelin
74 * Changed some ACR_OTHER_ERROR's to ACR_ABNORMAL_END_OF_OUTPUT.
75 *
76 * Revision 1.6 94/04/07 10:03:40 neelin
77 * Added status ACR_ABNORMAL_END_OF_INPUT and changed some ACR_PROTOCOL_ERRORs
78 * to that or ACR_OTHER_ERROR.
79 * Added #ifdef lint to DEFINE_ELEMENT.
80 *
81 * Revision 1.5 94/01/06 13:30:57 neelin
82 * Changed acr_need_invert to a public function.
83 *
84 * Revision 1.4 93/11/30 12:18:34 neelin
85 * Handle MALLOC returning NULL because of extremely large data element length.
86 *
87 * Revision 1.3 93/11/25 10:34:34 neelin
88 * Added routine to test byte-ordering of input.
89 *
90 * Revision 1.2 93/11/24 11:24:48 neelin
91 * Changed short to unsigned short.
92 *
93 * Revision 1.1 93/11/19 12:47:35 neelin
94 * Initial revision
95 *
96 @COPYRIGHT :
97 Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre,
98 Montreal Neurological Institute, McGill University.
99 Permission to use, copy, modify, and distribute this
100 software and its documentation for any purpose and without
101 fee is hereby granted, provided that the above copyright
102 notice appear in all copies. The author and McGill University
103 make no representations about the suitability of this
104 software for any purpose. It is provided "as is" without
105 express or implied warranty.
106 ---------------------------------------------------------------------------- */
107
108 #include <stdlib.h>
109 #include <stdio.h>
110 #include <limits.h>
111 #include <acr_nema.h>
112
113 /* Define constants */
114 #if (!defined(TRUE) || !defined(FALSE))
115 # define TRUE 1
116 # define FALSE 0
117 #endif
118
119 #define ACR_BYTE_ORDER_DEFAULT ACR_LITTLE_ENDIAN
120
121 #define ACR_VR_ENCODING_DEFAULT ACR_IMPLICIT_VR
122
123 /* Define types */
124 typedef struct {
125 Acr_byte_order byte_order;
126 Acr_VR_encoding_type vr_encoding;
127 int ignore_nonfatal_protocol_errors;
128 } *Data_Info;
129
130 /* Private functions */
131 static int test_vr(char vr_to_test[2], char *vr_list[]);
132 static int is_sequence_vr(char vr_to_test[2]);
133 static int is_special_vr(char vr_to_test[2]);
134 static Data_Info get_data_info(Acr_File *afp);
135 static void invert_values(Acr_byte_order byte_order,
136 long nvals, size_t value_size,
137 void *input_value, void *mach_value);
138
139 /* Macros */
140 #define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
141
142 /* ----------------------------- MNI Header -----------------------------------
143 @NAME : is_sequence_vr
144 is_special_vr
145 @INPUT : vr_to_test - Two character array containing value representation
146 @OUTPUT : (none)
147 @RETURNS : TRUE if vr is in appropriate list
148 @DESCRIPTION: These routines test VR against various lists. is_sequence_vr
149 checks for a sequence and is_special_vr checks for a VR
150 with different fields
151 @METHOD :
152 @GLOBALS :
153 @CALLS :
154 @CREATED : January 29, 1997 (Peter Neelin)
155 @MODIFIED :
156 ---------------------------------------------------------------------------- */
test_vr(char vr_to_test[2],char * vr_list[])157 static int test_vr(char vr_to_test[2], char *vr_list[])
158 {
159 int found_special, i;
160
161 found_special = FALSE;
162 for (i=0; vr_list[i] != NULL; i++) {
163 if ((vr_to_test[0] == vr_list[i][0]) &&
164 (vr_to_test[1] == vr_list[i][1])) {
165 found_special = TRUE;
166 break;
167 }
168 }
169
170 return found_special;
171 }
172
is_sequence_vr(char vr_to_test[2])173 static int is_sequence_vr(char vr_to_test[2])
174 {
175 static char *sequence_vrs[] = {"SQ", NULL};
176 return test_vr(vr_to_test, sequence_vrs);
177 }
178
is_special_vr(char vr_to_test[2])179 static int is_special_vr(char vr_to_test[2])
180 {
181 static char *special_vrs[] = {"OB", "OW", "SQ", "UN", NULL};
182 return test_vr(vr_to_test, special_vrs);
183 }
184
185 /* ----------------------------- MNI Header -----------------------------------
186 @NAME : get_data_info
187 @INPUT : afp - i/o stream
188 @OUTPUT : (none)
189 @RETURNS : Pointer to data info
190 @DESCRIPTION: Checks that the i/o stream has the appropriate structure as
191 client data and returns a pointer to the structure.
192 @METHOD :
193 @GLOBALS :
194 @CALLS :
195 @CREATED : February 14, 1997 (Peter Neelin)
196 @MODIFIED :
197 ---------------------------------------------------------------------------- */
get_data_info(Acr_File * afp)198 static Data_Info get_data_info(Acr_File *afp)
199 {
200 Data_Info data_info;
201
202 data_info = acr_file_get_client_data(afp);
203 if (data_info == NULL) {
204 data_info = MALLOC(sizeof(*data_info));
205 data_info->byte_order = ACR_BYTE_ORDER_DEFAULT;
206 data_info->vr_encoding = ACR_VR_ENCODING_DEFAULT;
207 data_info->ignore_nonfatal_protocol_errors = FALSE;
208 acr_file_set_client_data(afp, (void *) data_info);
209 }
210 return data_info;
211 }
212
213 /* ----------------------------- MNI Header -----------------------------------
214 @NAME : acr_set_byte_order
215 @INPUT : afp - i/o stream
216 byte_order - ACR_LITTLE_ENDIAN or ACR_BIG_ENDIAN.
217 @OUTPUT : (none)
218 @RETURNS : (nothing)
219 @DESCRIPTION: Allows a user to set the byte ordering for an i/o stream.
220 @METHOD :
221 @GLOBALS :
222 @CALLS :
223 @CREATED : January 29, 1997 (Peter Neelin)
224 @MODIFIED :
225 ---------------------------------------------------------------------------- */
acr_set_byte_order(Acr_File * afp,Acr_byte_order byte_order)226 void acr_set_byte_order(Acr_File *afp, Acr_byte_order byte_order)
227 {
228 Data_Info data_info;
229
230 /* Get data info pointer */
231 data_info = get_data_info(afp);
232
233 /* Set the byte ordering */
234 data_info->byte_order = byte_order;
235
236 }
237
238 /* ----------------------------- MNI Header -----------------------------------
239 @NAME : acr_get_byte_order
240 @INPUT : afp - i/o stream
241 @OUTPUT : (none)
242 @RETURNS : Byte ordering of stream
243 @DESCRIPTION: Allows one to get the byte ordering for an i/o stream.
244 @METHOD :
245 @GLOBALS :
246 @CALLS :
247 @CREATED : January 29, 1997 (Peter Neelin)
248 @MODIFIED :
249 ---------------------------------------------------------------------------- */
acr_get_byte_order(Acr_File * afp)250 Acr_byte_order acr_get_byte_order(Acr_File *afp)
251 {
252 Data_Info data_info;
253
254 /* Get data info pointer */
255 data_info = get_data_info(afp);
256
257 /* Return the byte ordering */
258 return data_info->byte_order;
259 }
260
261 /* ----------------------------- MNI Header -----------------------------------
262 @NAME : acr_get_machine_byte_order
263 @INPUT : (none)
264 @OUTPUT : (none)
265 @RETURNS : Byte ordering for this machine.
266 @DESCRIPTION: Gets the byte ordering for the machine on which the program is
267 running.
268 @METHOD :
269 @GLOBALS :
270 @CALLS :
271 @CREATED : February 14, 1997 (Peter Neelin)
272 @MODIFIED :
273 ---------------------------------------------------------------------------- */
acr_get_machine_byte_order(void)274 int acr_get_machine_byte_order(void)
275 {
276 int dummy = 1;
277 char *ptr = (char *) &dummy;
278
279 if ((int) ptr[0] == 1)
280 return ACR_LITTLE_ENDIAN;
281 else if ((int) ptr[sizeof(int)-1] == 1)
282 return ACR_BIG_ENDIAN;
283 else {
284 (void) fprintf(stderr,
285 "Internal error: Cannot figure out machine byte order!\n");
286 exit(EXIT_FAILURE);
287 return ACR_BIG_ENDIAN;
288 }
289
290 }
291
292 /* ----------------------------- MNI Header -----------------------------------
293 @NAME : acr_need_invert
294 @INPUT : byte_order - byte_order of foreign data
295 @OUTPUT : (none)
296 @RETURNS : TRUE if need to invert shorts and longs
297 @DESCRIPTION: Indicates whether we need to swap bytes for shorts and longs
298 to convert between the given byte ordering and the machine
299 byte ordering.
300 @METHOD :
301 @GLOBALS :
302 @CALLS :
303 @CREATED : November 10, 1993 (Peter Neelin)
304 @MODIFIED : January 29, 1997 (P.N.)
305 ---------------------------------------------------------------------------- */
acr_need_invert(Acr_byte_order byte_order)306 int acr_need_invert(Acr_byte_order byte_order)
307 {
308 return (acr_get_machine_byte_order() != byte_order);
309 }
310
311 /* ----------------------------- MNI Header -----------------------------------
312 @NAME : acr_set_vr_encoding
313 @INPUT : afp - i/o stream
314 vr_encoding - ACR_EXPLICIT_VR or ACR_IMPLICIT_VR
315 @OUTPUT : (none)
316 @RETURNS : (nothing)
317 @DESCRIPTION: Allows a user to set the vr encoding type for an i/o stream.
318 @METHOD :
319 @GLOBALS :
320 @CALLS :
321 @CREATED : January 29, 1997 (Peter Neelin)
322 @MODIFIED :
323 ---------------------------------------------------------------------------- */
acr_set_vr_encoding(Acr_File * afp,Acr_VR_encoding_type vr_encoding)324 void acr_set_vr_encoding(Acr_File *afp, Acr_VR_encoding_type vr_encoding)
325 {
326 Data_Info data_info;
327
328 /* Get data info pointer */
329 data_info = get_data_info(afp);
330
331 /* Set the VR encoding */
332 data_info->vr_encoding = vr_encoding;
333
334 }
335
336 /* ----------------------------- MNI Header -----------------------------------
337 @NAME : acr_get_vr_encoding
338 @INPUT : afp - i/o stream
339 @OUTPUT : (none)
340 @RETURNS : VR encoding of stream
341 @DESCRIPTION: Allows one to get the vr encoding for an i/o stream
342 @METHOD :
343 @GLOBALS :
344 @CALLS :
345 @CREATED : January 29, 1997 (Peter Neelin)
346 @MODIFIED :
347 ---------------------------------------------------------------------------- */
acr_get_vr_encoding(Acr_File * afp)348 Acr_VR_encoding_type acr_get_vr_encoding(Acr_File *afp)
349 {
350 Data_Info data_info;
351
352 /* Get data info pointer */
353 data_info = get_data_info(afp);
354
355 /* Return the VR encoding */
356 return data_info->vr_encoding;
357
358 }
359
360 /* ----------------------------- MNI Header -----------------------------------
361 @NAME : acr_set_ignore_errors
362 @INPUT : afp - i/o stream
363 ignore_nonfatal_protocol_errors - if TRUE then non-fatal
364 protocol errors will be ignored
365 @OUTPUT : (none)
366 @RETURNS : (nothing)
367 @DESCRIPTION: Allows a user to indicate whether to ignore protocol errors
368 that can be ignored.
369 @METHOD :
370 @GLOBALS :
371 @CALLS :
372 @CREATED : April 28, 2000 (Peter Neelin)
373 @MODIFIED :
374 ---------------------------------------------------------------------------- */
acr_set_ignore_errors(Acr_File * afp,int ignore_nonfatal_protocol_errors)375 void acr_set_ignore_errors(Acr_File *afp, int ignore_nonfatal_protocol_errors)
376 {
377 Data_Info data_info;
378
379 /* Get data info pointer */
380 data_info = get_data_info(afp);
381
382 /* Set the flag */
383 data_info->ignore_nonfatal_protocol_errors =
384 ignore_nonfatal_protocol_errors;
385
386 }
387
388 /* ----------------------------- MNI Header -----------------------------------
389 @NAME : acr_ignore_protocol_errors
390 @INPUT : afp - i/o stream
391 @OUTPUT : (none)
392 @RETURNS : TRUE if stream is set to ignore nonfatal protocol errors
393 @DESCRIPTION: Allows one to get the ignore errors flag for a stream
394 @METHOD :
395 @GLOBALS :
396 @CALLS :
397 @CREATED : April 28, 2000 (Peter Neelin)
398 @MODIFIED :
399 ---------------------------------------------------------------------------- */
acr_ignore_protocol_errors(Acr_File * afp)400 int acr_ignore_protocol_errors(Acr_File *afp)
401 {
402 Data_Info data_info;
403
404 /* Get data info pointer */
405 data_info = get_data_info(afp);
406
407 /* Return the VR encoding */
408 return data_info->ignore_nonfatal_protocol_errors;
409
410 }
411
412 /* ----------------------------- MNI Header -----------------------------------
413 @NAME : acr_reverse_byte_order
414 @INPUT : nvals - number of values to invert
415 value_size - length of each value
416 input_values - pointer to array of input values
417 @OUTPUT : output_values - pointer to array of inverted values or NULL
418 @RETURNS : (nothing)
419 @DESCRIPTION: Reverses byte-ordering of an array of values. Will reverse
420 an array in place if input_values and output_values point to
421 the same array or if output_values is NULL.
422 @METHOD :
423 @GLOBALS :
424 @CALLS :
425 @CREATED : February 14, 1997 (Peter Neelin)
426 @MODIFIED :
427 ---------------------------------------------------------------------------- */
acr_reverse_byte_order(long nvals,size_t value_size,void * input_values,void * output_values)428 void acr_reverse_byte_order(long nvals, size_t value_size,
429 void *input_values, void *output_values)
430 {
431 long i, jlow, jhigh;
432 char *ptr1, *ptr2, v0, v1;
433 int nbytes;
434
435 /* Get data pointers and check whether output_values is NULL */
436 ptr1 = (char *) input_values;
437 ptr2 = (char *) output_values;
438 if (ptr2 == NULL) ptr2 = ptr1;
439
440 /* Copy values from both ends at the same time and stop in the middle */
441 nbytes = (value_size+1)/2;
442 for (i=0; i<nvals; i++) {
443 for (jlow=0; jlow<nbytes; jlow++) {
444 jhigh = value_size - jlow - 1;
445 v0 = ptr1[jhigh];
446 v1 = ptr1[jlow];
447 ptr2[jlow] = v0;
448 ptr2[jhigh] = v1;
449 }
450 ptr1 += value_size;
451 ptr2 += value_size;
452 }
453
454 }
455
456 /* ----------------------------- MNI Header -----------------------------------
457 @NAME : invert_values
458 @INPUT : byte_order - byte ordering for input values
459 nvals - number of values to invert
460 value_size - length of each value
461 input_value - pointer to array of input values
462 @OUTPUT : mach_value - pointer to array of inverted values
463 @RETURNS : (nothing)
464 @DESCRIPTION: Reverses byte-ordering of an array of values to match machine
465 byte order if necessary, otherwise the values are just copied.
466 @METHOD :
467 @GLOBALS :
468 @CALLS :
469 @CREATED : January 31, 1997 (Peter Neelin)
470 @MODIFIED :
471 ---------------------------------------------------------------------------- */
invert_values(Acr_byte_order byte_order,long nvals,size_t value_size,void * input_value,void * mach_value)472 static void invert_values(Acr_byte_order byte_order,
473 long nvals, size_t value_size,
474 void *input_value, void *mach_value)
475 {
476 long i;
477 char *ptr1, *ptr2;
478
479 /* Check whether a flip is needed */
480 if (acr_need_invert(byte_order)) {
481 acr_reverse_byte_order(nvals, value_size, input_value, mach_value);
482 }
483 else {
484 ptr1 = (char *) input_value;
485 ptr2 = (char *) mach_value;
486 for (i=0; i<nvals*value_size; i++) {
487 ptr2[i] = ptr1[i];
488 }
489 }
490
491 }
492
493 /* ----------------------------- MNI Header -----------------------------------
494 @NAME : acr_get_short
495 @INPUT : byte_order - byte ordering for input values
496 nvals - number of values to convert to short
497 input_value - pointer to array of input values
498 @OUTPUT : mach_value - pointer to array of shorts
499 @RETURNS : (nothing)
500 @DESCRIPTION: Converts input values to shorts.
501 @METHOD :
502 @GLOBALS :
503 @CALLS :
504 @CREATED : November 10, 1993 (Peter Neelin)
505 @MODIFIED :
506 ---------------------------------------------------------------------------- */
acr_get_short(Acr_byte_order byte_order,long nvals,void * input_value,Acr_Short * mach_value)507 void acr_get_short(Acr_byte_order byte_order,
508 long nvals, void *input_value,
509 Acr_Short *mach_value)
510 {
511 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_SHORT,
512 input_value, mach_value);
513 return;
514 }
515
516 /* ----------------------------- MNI Header -----------------------------------
517 @NAME : acr_get_long
518 @INPUT : byte_order - byte ordering for input values
519 nvals - number of values to convert to long
520 input_value - pointer to array of input values
521 @OUTPUT : mach_value - pointer to array of longs
522 @RETURNS : (nothing)
523 @DESCRIPTION: Converts input values to longs.
524 @METHOD :
525 @GLOBALS :
526 @CALLS :
527 @CREATED : November 10, 1993 (Peter Neelin)
528 @MODIFIED :
529 ---------------------------------------------------------------------------- */
acr_get_long(Acr_byte_order byte_order,long nvals,void * input_value,Acr_Long * mach_value)530 void acr_get_long(Acr_byte_order byte_order,
531 long nvals, void *input_value, Acr_Long *mach_value)
532 {
533 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_LONG,
534 input_value, mach_value);
535 return;
536 }
537
538 /* ----------------------------- MNI Header -----------------------------------
539 @NAME : acr_get_float
540 @INPUT : byte_order - byte ordering for input values
541 nvals - number of values to convert to float
542 input_value - pointer to array of input values
543 @OUTPUT : mach_value - pointer to array of floats
544 @RETURNS : (nothing)
545 @DESCRIPTION: Converts input values to floats. This will only work properly
546 on machines that support IEEE floating-point representation.
547 @METHOD :
548 @GLOBALS :
549 @CALLS :
550 @CREATED : February 4, 1997 (Peter Neelin)
551 @MODIFIED :
552 ---------------------------------------------------------------------------- */
acr_get_float(Acr_byte_order byte_order,long nvals,void * input_value,Acr_Float * mach_value)553 void acr_get_float(Acr_byte_order byte_order,
554 long nvals, void *input_value, Acr_Float *mach_value)
555 {
556 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_FLOAT,
557 input_value, mach_value);
558 return;
559 }
560
561 /* ----------------------------- MNI Header -----------------------------------
562 @NAME : acr_get_double
563 @INPUT : byte_order - byte ordering for input values
564 nvals - number of values to convert to double
565 input_value - pointer to array of input values
566 @OUTPUT : mach_value - pointer to array of doubles
567 @RETURNS : (nothing)
568 @DESCRIPTION: Converts input values to doubles. This will only work properly
569 on machines that support IEEE floating-point representation.
570 @METHOD :
571 @GLOBALS :
572 @CALLS :
573 @CREATED : February 4, 1997 (Peter Neelin)
574 @MODIFIED :
575 ---------------------------------------------------------------------------- */
acr_get_double(Acr_byte_order byte_order,long nvals,void * input_value,Acr_Double * mach_value)576 void acr_get_double(Acr_byte_order byte_order,
577 long nvals, void *input_value, Acr_Double *mach_value)
578 {
579 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_DOUBLE,
580 input_value, mach_value);
581 return;
582 }
583
584 /* ----------------------------- MNI Header -----------------------------------
585 @NAME : acr_put_short
586 @INPUT : byte_order - byte ordering for output values
587 nvals - number of values to convert from short
588 mach_value - pointer to array of shorts
589 @OUTPUT : output_value - pointer to array of output values
590 @RETURNS : (nothing)
591 @DESCRIPTION: Converts shorts to output values.
592 @METHOD :
593 @GLOBALS :
594 @CALLS :
595 @CREATED : November 10, 1993 (Peter Neelin)
596 @MODIFIED :
597 ---------------------------------------------------------------------------- */
acr_put_short(Acr_byte_order byte_order,long nvals,Acr_Short * mach_value,void * output_value)598 void acr_put_short(Acr_byte_order byte_order,
599 long nvals, Acr_Short *mach_value,
600 void *output_value)
601 {
602 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_SHORT,
603 mach_value, output_value);
604 return;
605 }
606
607 /* ----------------------------- MNI Header -----------------------------------
608 @NAME : acr_put_long
609 @INPUT : byte_order - byte ordering for output values
610 nvals - number of values to convert from long
611 mach_value - pointer to array of longs
612 @OUTPUT : output_value - pointer to array of output values
613 @RETURNS : (nothing)
614 @DESCRIPTION: Converts longs to output values.
615 @METHOD :
616 @GLOBALS :
617 @CALLS :
618 @CREATED : November 10, 1993 (Peter Neelin)
619 @MODIFIED :
620 ---------------------------------------------------------------------------- */
acr_put_long(Acr_byte_order byte_order,long nvals,Acr_Long * mach_value,void * output_value)621 void acr_put_long(Acr_byte_order byte_order,
622 long nvals, Acr_Long *mach_value, void *output_value)
623 {
624 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_LONG,
625 mach_value, output_value);
626 return;
627 }
628
629 /* ----------------------------- MNI Header -----------------------------------
630 @NAME : acr_put_float
631 @INPUT : byte_order - byte ordering for output values
632 nvals - number of values to convert from float
633 mach_value - pointer to array of longs
634 @OUTPUT : output_value - pointer to array of output values
635 @RETURNS : (nothing)
636 @DESCRIPTION: Converts floats to output values.
637 @METHOD :
638 @GLOBALS :
639 @CALLS :
640 @CREATED : November 10, 1993 (Peter Neelin)
641 @MODIFIED :
642 ---------------------------------------------------------------------------- */
acr_put_float(Acr_byte_order byte_order,long nvals,Acr_Float * mach_value,void * output_value)643 void acr_put_float(Acr_byte_order byte_order,
644 long nvals, Acr_Float *mach_value, void *output_value)
645 {
646 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_FLOAT,
647 mach_value, output_value);
648 return;
649 }
650
651 /* ----------------------------- MNI Header -----------------------------------
652 @NAME : acr_put_double
653 @INPUT : byte_order - byte ordering for output values
654 nvals - number of values to convert from double
655 mach_value - pointer to array of longs
656 @OUTPUT : output_value - pointer to array of output values
657 @RETURNS : (nothing)
658 @DESCRIPTION: Converts doubles to output values.
659 @METHOD :
660 @GLOBALS :
661 @CALLS :
662 @CREATED : November 10, 1993 (Peter Neelin)
663 @MODIFIED :
664 ---------------------------------------------------------------------------- */
acr_put_double(Acr_byte_order byte_order,long nvals,Acr_Double * mach_value,void * output_value)665 void acr_put_double(Acr_byte_order byte_order,
666 long nvals, Acr_Double *mach_value, void *output_value)
667 {
668 invert_values(byte_order, nvals, (size_t) ACR_SIZEOF_DOUBLE,
669 mach_value, output_value);
670 return;
671 }
672
673 /* ----------------------------- MNI Header -----------------------------------
674 @NAME : acr_skip_input_data
675 @INPUT : afp
676 nbytes_to_skip
677 @OUTPUT : (none)
678 @RETURNS : Input status. If an error occurs on the first byte, then
679 ACR_END_OF_INPUT is returned, if an error occurs elsewhere,
680 then ACR_ABNORMAL_END_OF_INPUT is returned, otherwise ACR_OK
681 is returned.
682 @DESCRIPTION: Skips over input data.
683 @METHOD :
684 @GLOBALS :
685 @CALLS :
686 @CREATED : February 12, 1997 (Peter Neelin)
687 @MODIFIED :
688 ---------------------------------------------------------------------------- */
acr_skip_input_data(Acr_File * afp,long nbytes_to_skip)689 Acr_Status acr_skip_input_data(Acr_File *afp, long nbytes_to_skip)
690 {
691 long i;
692 int ch;
693
694 for (i=0; i < nbytes_to_skip; i++) {
695 ch = acr_getc(afp);
696 if (ch == EOF) {
697 break;
698 }
699 }
700
701 /* Return the status */
702 if (i >= nbytes_to_skip) {
703 return ACR_OK;
704 }
705 else if (acr_get_io_watchpoint(afp) <= 0) {
706 return ACR_REACHED_WATCHPOINT;
707 }
708 else if (i == 0) {
709 return ACR_END_OF_INPUT;
710 }
711 else {
712 return ACR_ABNORMAL_END_OF_INPUT;
713 }
714 }
715
716 /* ----------------------------- MNI Header -----------------------------------
717 @NAME : acr_read_buffer
718 @INPUT : afp
719 nbytes_to_read
720 @OUTPUT : buffer
721 nbytes_read - if NULL, then this value is ignored, otherwise
722 the number of bytes actually read in is returned.
723 @RETURNS : Input status. If an error occurs on the first byte, then
724 ACR_END_OF_INPUT is returned, if an error occurs elsewhere,
725 then ACR_ABNORMAL_END_OF_INPUT is returned, otherwise ACR_OK
726 is returned.
727 @DESCRIPTION: Reads in a buffer of data and optionally returns the number
728 of bytes read
729 @METHOD :
730 @GLOBALS :
731 @CALLS :
732 @CREATED : February 12, 1997 (Peter Neelin)
733 @MODIFIED :
734 ---------------------------------------------------------------------------- */
acr_read_buffer(Acr_File * afp,unsigned char buffer[],long nbytes_to_read,long * nbytes_read)735 Acr_Status acr_read_buffer(Acr_File *afp, unsigned char buffer[],
736 long nbytes_to_read, long *nbytes_read)
737 {
738 long i;
739 int ch;
740
741 for (i=0; i < nbytes_to_read; i++) {
742 ch = acr_getc(afp);
743 if (ch == EOF) {
744 break;
745 }
746 buffer[i] = (unsigned char) ch;
747 }
748
749 /* Save the number of bytes read */
750 if (nbytes_read != NULL) {
751 *nbytes_read = i;
752 }
753
754 /* Return the status */
755 if (i >= nbytes_to_read) {
756 return ACR_OK;
757 }
758 else if (acr_get_io_watchpoint(afp) <= 0) {
759 return ACR_REACHED_WATCHPOINT;
760 }
761 else if (i == 0) {
762 return ACR_END_OF_INPUT;
763 }
764 else {
765 return ACR_ABNORMAL_END_OF_INPUT;
766 }
767 }
768
769 /* ----------------------------- MNI Header -----------------------------------
770 @NAME : acr_unget_buffer
771 @INPUT : afp
772 nbytes_to_unget
773 buffer
774 @OUTPUT : (none)
775 @RETURNS : Unget status.
776 @DESCRIPTION: Puts a buffer of data back into the input stream.
777 @METHOD :
778 @GLOBALS :
779 @CALLS :
780 @CREATED : February 12, 1997 (Peter Neelin)
781 @MODIFIED :
782 ---------------------------------------------------------------------------- */
acr_unget_buffer(Acr_File * afp,unsigned char buffer[],long nbytes_to_unget)783 Acr_Status acr_unget_buffer(Acr_File *afp, unsigned char buffer[],
784 long nbytes_to_unget)
785 {
786 long i;
787
788 for (i=nbytes_to_unget-1; i >= 0; i--) {
789 if (acr_ungetc((int) buffer[i], afp) == EOF) {
790 break;
791 }
792 }
793
794 /* Return the status */
795 if (i >= 0) {
796 return ACR_IO_ERROR;
797 }
798 else {
799 return ACR_OK;
800 }
801 }
802
803 /* ----------------------------- MNI Header -----------------------------------
804 @NAME : acr_write_buffer
805 @INPUT : afp
806 nbytes_to_write
807 buffer
808 @OUTPUT : nbytes_written
809 @RETURNS : Output status.
810 @DESCRIPTION: Writes out a buffer of data and optionally returns the number
811 of bytes written
812 @METHOD :
813 @GLOBALS :
814 @CALLS :
815 @CREATED : February 12, 1997 (Peter Neelin)
816 @MODIFIED :
817 ---------------------------------------------------------------------------- */
acr_write_buffer(Acr_File * afp,unsigned char buffer[],long nbytes_to_write,long * nbytes_written)818 Acr_Status acr_write_buffer(Acr_File *afp, unsigned char buffer[],
819 long nbytes_to_write, long *nbytes_written)
820 {
821 long i;
822
823 for (i=0; i < nbytes_to_write; i++) {
824 if (acr_putc(buffer[i], afp) == EOF) {
825 break;
826 }
827 }
828
829 /* Save the number of bytes written */
830 if (nbytes_written != NULL) {
831 *nbytes_written = i;
832 }
833
834 /* Return the status */
835 if (i < nbytes_to_write) {
836 return ACR_ABNORMAL_END_OF_OUTPUT;
837 }
838 else {
839 return ACR_OK;
840 }
841 }
842
843 /* ----------------------------- MNI Header -----------------------------------
844 @NAME : acr_test_byte_order
845 @INPUT : afp
846 @OUTPUT : (none)
847 @RETURNS : status.
848 @DESCRIPTION: Tests input for byte ordering to use. The test is done by
849 looking at the length of the first element. First a test is
850 done for implicit VR, assuming that the length of the first
851 element is less than 64K and greater than zero, and we try
852 the two possible byte orders. If the VR encoding is explicit,
853 then we have two shortwords (2-bytes), both of which are
854 non-zero and the longword (4 bytes) will be greater than 64K.
855 In this case, we test the 2-byte length looking for a length
856 that is less than 256 bytes. If that fails, than we revert
857 to the original byte order.
858 @METHOD :
859 @GLOBALS :
860 @CALLS :
861 @CREATED : November 10, 1993 (Peter Neelin)
862 @MODIFIED : January 29, 1997 (P.N.)
863 ---------------------------------------------------------------------------- */
acr_test_byte_order(Acr_File * afp)864 Acr_Status acr_test_byte_order(Acr_File *afp)
865 {
866 long buflen;
867 unsigned char buffer[2*ACR_SIZEOF_SHORT+ACR_SIZEOF_LONG];
868 Acr_Long data_length;
869 Acr_Short data_length2;
870 Acr_Status status;
871 Acr_byte_order byte_order, old_byte_order;
872
873 #define ACR_TEST_MAX USHRT_MAX
874 #define ACR_TEST_MAX2 UCHAR_MAX
875
876 /* Save old byte ordering */
877 old_byte_order = acr_get_byte_order(afp);
878
879 /* Read in group id, element id and length of data */
880 status = acr_read_buffer(afp, buffer, SIZEOF_ARRAY(buffer), &buflen);
881 if (status != ACR_OK) return status;
882
883 /* Put the characters back */
884 status = acr_unget_buffer(afp, buffer, buflen);
885 if (status != ACR_OK) return status;
886
887 /* Test data length (the first element should be a group length).
888 Try big-endian ordering first. */
889 byte_order = ACR_BIG_ENDIAN;
890 acr_set_byte_order(afp, byte_order);
891 acr_get_long(byte_order, 1, &buffer[2*ACR_SIZEOF_SHORT],
892 &data_length);
893
894 /* If that doesn't work, set it to little-endian ordering. */
895 if (data_length >= ACR_TEST_MAX) {
896 byte_order = ACR_LITTLE_ENDIAN;
897 acr_set_byte_order(afp, byte_order);
898 acr_get_long(byte_order, 1, &buffer[2*ACR_SIZEOF_SHORT],
899 &data_length);
900 }
901
902 /* If one of them worked, then it means that we have implicit VR
903 encoding since we didn't look for a VR field */
904 if (data_length < ACR_TEST_MAX) {
905 acr_set_vr_encoding(afp, ACR_IMPLICIT_VR);
906 }
907
908 /* Otherwise we probably have explicit vr encoding. */
909 else {
910 acr_set_vr_encoding(afp, ACR_EXPLICIT_VR);
911
912 /* Check the length in this case to see if it small. The default
913 will be little endian. */
914 byte_order = ACR_BIG_ENDIAN;
915 acr_set_byte_order(afp, byte_order);
916 acr_get_short(byte_order, 1, &buffer[3*ACR_SIZEOF_SHORT],
917 &data_length2);
918 if (data_length2 >= ACR_TEST_MAX2) {
919 byte_order = ACR_LITTLE_ENDIAN;
920 acr_set_byte_order(afp, byte_order);
921 acr_get_short(byte_order, 1, &buffer[3*ACR_SIZEOF_SHORT],
922 &data_length2);
923 }
924 if (data_length2 >= ACR_TEST_MAX2) {
925 /* If we get here, we have completely failed to make sense of
926 * the byte ordering.
927 */
928 acr_set_byte_order(afp, old_byte_order);
929 }
930 }
931
932 return ACR_OK;
933
934 }
935
936 /* ----------------------------- MNI Header -----------------------------------
937 @NAME : acr_copy_file_encoding
938 @INPUT : afp1 - source stream
939 @OUTPUT : afp2 - target stream
940 @RETURNS : (nothing)
941 @DESCRIPTION: Copies the byte ordering and VR encoding from one i/o stream
942 to another.
943 @METHOD :
944 @GLOBALS :
945 @CALLS :
946 @CREATED : February 14, 1997 (Peter Neelin)
947 @MODIFIED :
948 ---------------------------------------------------------------------------- */
acr_copy_file_encoding(Acr_File * afp1,Acr_File * afp2)949 void acr_copy_file_encoding(Acr_File *afp1, Acr_File *afp2)
950 {
951 acr_set_byte_order(afp2, acr_get_byte_order(afp1));
952 acr_set_vr_encoding(afp2, acr_get_vr_encoding(afp1));
953 }
954
955 /* ----------------------------- MNI Header -----------------------------------
956 @NAME : acr_get_element_header_size
957 @INPUT : vr_name - 2-letter name of Vr
958 vr_encoding - ACR_EXPLICIT_VR or ACR_IMPLICIT_VR
959 @OUTPUT : (none)
960 @RETURNS : length of header
961 @DESCRIPTION: Calculates the length of the element header (excluding data)
962 @METHOD :
963 @GLOBALS :
964 @CALLS :
965 @CREATED : February 4, 1997 (Peter Neelin)
966 @MODIFIED :
967 ---------------------------------------------------------------------------- */
acr_get_element_header_size(char vr_name[2],Acr_VR_encoding_type vr_encoding)968 int acr_get_element_header_size(char vr_name[2],
969 Acr_VR_encoding_type vr_encoding)
970 {
971 int length;
972
973 length = 2*ACR_SIZEOF_SHORT + ACR_SIZEOF_LONG;
974 if ((vr_encoding == ACR_EXPLICIT_VR) && is_special_vr(vr_name)) {
975 length += ACR_SIZEOF_LONG;
976 }
977 return length;
978 }
979
980 /* ----------------------------- MNI Header -----------------------------------
981 @NAME : acr_peek_at_next_element_id
982 @INPUT : afp - Acr_File pointer from which to read
983 @OUTPUT : group_id
984 element_id
985 @RETURNS : Status
986 @DESCRIPTION: Peeks ahead to get the group and element ids of the next
987 element. The file position is restored. If a read error occurs,
988 then group_id and element_id are set to INT_MIN and the status
989 is returned.
990 @METHOD :
991 @GLOBALS :
992 @CALLS :
993 @CREATED : February 5, 1997 (Peter Neelin)
994 @MODIFIED :
995 ---------------------------------------------------------------------------- */
acr_peek_at_next_element_id(Acr_File * afp,int * group_id,int * element_id)996 Acr_Status acr_peek_at_next_element_id(Acr_File *afp,
997 int *group_id, int *element_id)
998 {
999 long buflen;
1000 unsigned char buffer[2*ACR_SIZEOF_SHORT];
1001 Acr_Short svalue;
1002 Acr_Status status, status2;
1003 Acr_byte_order byte_order;
1004
1005 /* Set default values */
1006 status = ACR_OK;
1007 *group_id = INT_MIN;
1008 *element_id = INT_MIN;
1009
1010 /* Read in the values */
1011 status = acr_read_buffer(afp, buffer, SIZEOF_ARRAY(buffer), &buflen);
1012
1013 /* Put them back */
1014 status2 = acr_unget_buffer(afp, buffer, buflen);
1015 if (status == ACR_OK) status = status2;
1016
1017 /* Check for input error */
1018 if (status != ACR_OK) return status;
1019
1020 /* Get the id's */
1021 byte_order = acr_get_byte_order(afp);
1022 acr_get_short(byte_order, 1, &buffer[0], &svalue);
1023 *group_id = (int)svalue;
1024 acr_get_short(byte_order, 1, &buffer[ACR_SIZEOF_SHORT], &svalue);
1025 *element_id = (int)svalue;
1026
1027 return status;
1028
1029 }
1030
1031 /* ----------------------------- MNI Header -----------------------------------
1032 @NAME : acr_read_one_element
1033 @INPUT : afp - Acr_File pointer from which to read
1034 @OUTPUT : group_id - ACR-NEMA group id
1035 element_id - ACR-NEMA element id
1036 vr_name - 2 character string giving value representation.
1037 Two NULs are returned if VR is unknown.
1038 data_length - length of data to follow. Value
1039 ACR_VARIABLE_LENGTH is returned for undefined length elements
1040 in which case the data portion is not read in.
1041 data_pointer - pointer to data. Space is allocated by this
1042 routine. One additional byte is allocated and set to
1043 zero so that the data can be treated as a string. If a
1044 sequence is encountered, then NULL is returned.
1045 @RETURNS : Status.
1046 @DESCRIPTION: Routine to read in one ACR-NEMA element.
1047 @METHOD :
1048 @GLOBALS :
1049 @CALLS :
1050 @CREATED : November 10, 1993 (Peter Neelin)
1051 @MODIFIED : January 29, 1997 (P.N.)
1052 ---------------------------------------------------------------------------- */
acr_read_one_element(Acr_File * afp,int * group_id,int * element_id,char vr_name[],long * data_length,char ** data_pointer)1053 Acr_Status acr_read_one_element(Acr_File *afp,
1054 int *group_id, int *element_id,
1055 char vr_name[],
1056 long *data_length, char **data_pointer)
1057 {
1058 long buflen;
1059 unsigned char buffer[2*ACR_SIZEOF_SHORT+ACR_SIZEOF_LONG];
1060 Acr_Short grpid, elid, sval;
1061 Acr_Long datalen;
1062 size_t size_allocated;
1063 int offset;
1064 Acr_byte_order byte_order;
1065 Acr_Status status;
1066
1067 /* Get byte ordering */
1068 byte_order = acr_get_byte_order(afp);
1069
1070 /* Read in group id, element id and length of data */
1071 status = acr_read_buffer(afp, buffer, SIZEOF_ARRAY(buffer), &buflen);
1072 if (status != ACR_OK) return status;
1073 offset = 0;
1074 acr_get_short(byte_order, 1, &buffer[offset], &grpid);
1075 offset += ACR_SIZEOF_SHORT;
1076 *group_id = (int)grpid;
1077 acr_get_short(byte_order, 1, &buffer[offset], &elid);
1078 offset += ACR_SIZEOF_SHORT;
1079 *element_id = (int)elid;
1080
1081 /* Look for VR and length of data */
1082 if (grpid == ACR_ITEM_GROUP || acr_get_vr_encoding(afp) == ACR_IMPLICIT_VR) {
1083 vr_name[0] = '\0';
1084 vr_name[1] = '\0';
1085 acr_get_long(byte_order, 1, &buffer[offset], &datalen);
1086 offset += ACR_SIZEOF_LONG;
1087 }
1088 else {
1089 vr_name[0] = buffer[offset++];
1090 vr_name[1] = buffer[offset++];
1091 acr_get_short(byte_order, 1, &buffer[offset], &sval);
1092 offset += ACR_SIZEOF_SHORT;
1093 datalen = (Acr_Long)sval;
1094 }
1095
1096 /* Read in length for special VR's */
1097 if (is_special_vr(vr_name)) {
1098 status = acr_read_buffer(afp, buffer, (long) ACR_SIZEOF_LONG, NULL);
1099 if (status != ACR_OK) return ACR_ABNORMAL_END_OF_INPUT;
1100 acr_get_long(byte_order, 1, &buffer[0], &datalen);
1101 }
1102
1103 /* Check for undefined length */
1104 if (datalen == ACR_UNDEFINED_ELEMENT_LENGTH) {
1105 *data_length = ACR_VARIABLE_LENGTH;
1106 *data_pointer = NULL;
1107 return ACR_OK;
1108 }
1109 *data_length = (long)datalen;
1110
1111 /* Check for sequence VR */
1112 if (is_sequence_vr(vr_name)) {
1113 *data_pointer = NULL;
1114 return ACR_OK;
1115 }
1116
1117 /* Allocate space for the data and null-terminate it */
1118 size_allocated = *data_length + 1;
1119 *data_pointer = MALLOC(size_allocated);
1120 if (*data_pointer == NULL) {
1121 *data_length = 0;
1122 size_allocated = *data_length + 1;
1123 *data_pointer = MALLOC(size_allocated);
1124 }
1125 (*data_pointer)[*data_length] = '\0';
1126
1127 /* Read in the data */
1128 status = acr_read_buffer(afp, (unsigned char *) *data_pointer,
1129 *data_length, NULL);
1130 if (status != ACR_OK) {
1131 FREE(*data_pointer);
1132 return ACR_ABNORMAL_END_OF_INPUT;
1133 }
1134
1135 return ACR_OK;
1136 }
1137
1138 /* ----------------------------- MNI Header -----------------------------------
1139 @NAME : acr_write_one_element
1140 @INPUT : afp - Acr_File pointer from which to read
1141 group_id - ACR-NEMA group id
1142 element_id - ACR-NEMA element id
1143 vr_name - 2 character string giving value representation.
1144 It is an error to pass in two NULs if explicit VR is used
1145 (ACR_NO_VR_SPECIFIED is returned).
1146 data_length - length of data to follow. If set to
1147 ACR_VARIABLE_LENGTH, then the data portion is not written out.
1148 data_pointer - pointer to data. If NULL, then no data is
1149 written.
1150 @OUTPUT : (nothing)
1151 @RETURNS : Status.
1152 @DESCRIPTION: Routine to write out one ACR-NEMA element.
1153 @METHOD :
1154 @GLOBALS :
1155 @CALLS :
1156 @CREATED : November 10, 1993 (Peter Neelin)
1157 @MODIFIED : January 29, 1997 (P.N.)
1158 ---------------------------------------------------------------------------- */
acr_write_one_element(Acr_File * afp,int group_id,int element_id,char vr_name[],long data_length,char * data_pointer)1159 Acr_Status acr_write_one_element(Acr_File *afp,
1160 int group_id, int element_id,
1161 char vr_name[],
1162 long data_length, char *data_pointer)
1163 {
1164 long buflen;
1165 unsigned char buffer[2*ACR_SIZEOF_SHORT+2*ACR_SIZEOF_LONG];
1166 Acr_Short grpid, elid, sval;
1167 Acr_Long datalen;
1168 int offset;
1169 Acr_byte_order byte_order;
1170 Acr_Status status;
1171
1172 buflen = sizeof(buffer)/sizeof(buffer[0]) - ACR_SIZEOF_LONG;
1173
1174 /* Get byte ordering */
1175 byte_order = acr_get_byte_order(afp);
1176
1177 /* Get the group id and element id */
1178 offset = 0;
1179 grpid = (Acr_Short) group_id;
1180 acr_put_short(byte_order, 1, &grpid, &buffer[offset]);
1181 offset += ACR_SIZEOF_SHORT;
1182 elid = (Acr_Short) element_id;
1183 acr_put_short(byte_order, 1, &elid, &buffer[offset]);
1184 offset += ACR_SIZEOF_SHORT;
1185
1186 /* Check data length */
1187 if ((Acr_Long)data_length == ACR_VARIABLE_LENGTH)
1188 datalen = ACR_UNDEFINED_ELEMENT_LENGTH;
1189 else
1190 datalen = (Acr_Long)data_length;
1191
1192 /* Check whether we need VR */
1193 if (acr_get_vr_encoding(afp) == ACR_IMPLICIT_VR) {
1194 acr_put_long(byte_order, 1, &datalen, &buffer[offset]);
1195 offset += ACR_SIZEOF_LONG;
1196 }
1197 else {
1198 if (vr_name[0] == '\0') return ACR_NO_VR_SPECIFIED;
1199 buffer[offset++] = vr_name[0];
1200 buffer[offset++] = vr_name[1];
1201 if (!is_special_vr(vr_name)) {
1202 sval = (Acr_Short) datalen;
1203 acr_put_short(byte_order, 1, &sval, &buffer[offset]);
1204 offset += ACR_SIZEOF_SHORT;
1205 }
1206 else {
1207 sval = 0;
1208 acr_put_short(byte_order, 1, &sval, &buffer[offset]);
1209 offset += ACR_SIZEOF_SHORT;
1210 acr_put_long(byte_order, 1, &datalen, &buffer[offset]);
1211 offset += ACR_SIZEOF_LONG;
1212 buflen += ACR_SIZEOF_LONG;
1213 }
1214 }
1215
1216 /* Write it out */
1217 status = acr_write_buffer(afp, buffer, buflen, NULL);
1218 if (status != ACR_OK) return status;
1219
1220 if ((data_length == ACR_VARIABLE_LENGTH) || (data_pointer == NULL)) {
1221 return ACR_OK;
1222 }
1223
1224 /* Write out the data */
1225 status = acr_write_buffer(afp, (unsigned char *) data_pointer,
1226 data_length, NULL);
1227 if (status != ACR_OK) return status;
1228
1229 return ACR_OK;
1230 }
1231
1232 /* ----------------------------- MNI Header -----------------------------------
1233 @NAME : acr_status_string
1234 @INPUT : status - status code to look up
1235 @OUTPUT : (nothing)
1236 @RETURNS : Pointer to string describing status.
1237 @DESCRIPTION: Routine to get a string that describes a status value.
1238 @METHOD :
1239 @GLOBALS :
1240 @CALLS :
1241 @CREATED : July 10, 1997 (Peter Neelin)
1242 @MODIFIED :
1243 ---------------------------------------------------------------------------- */
acr_status_string(Acr_Status status)1244 char *acr_status_string(Acr_Status status)
1245 {
1246 char *status_string;
1247
1248 switch (status) {
1249 case ACR_OK:
1250 status_string = "No error"; break;
1251 case ACR_END_OF_INPUT:
1252 status_string = "End of input"; break;
1253 case ACR_PROTOCOL_ERROR:
1254 status_string = "Protocol error"; break;
1255 case ACR_OTHER_ERROR:
1256 status_string = "Other error"; break;
1257 case ACR_ABNORMAL_END_OF_INPUT:
1258 status_string = "Abnormal end of input"; break;
1259 case ACR_HIGH_LEVEL_ERROR:
1260 status_string = "High-level error"; break;
1261 case ACR_ABNORMAL_END_OF_OUTPUT:
1262 status_string = "Abnormal end of output"; break;
1263 case ACR_REACHED_WATCHPOINT:
1264 status_string = "Reached watchpoint"; break;
1265 case ACR_IO_ERROR:
1266 status_string = "I/O error"; break;
1267 case ACR_NO_VR_SPECIFIED:
1268 status_string = "VR not specified on output"; break;
1269 case ACR_PDU_UID_TOO_LONG:
1270 status_string = "Input PDU UID too long"; break;
1271 case ACR_CONNECTION_TIMEDOUT:
1272 status_string = "Connection timed out"; break;
1273 default:
1274 status_string = "Unknown status"; break;
1275 }
1276
1277 return status_string;
1278 }
1279
1280