1 /* ----------------------------- MNI Header -----------------------------------
2 @NAME       : element.c
3 @DESCRIPTION: Routines for doing acr_nema element operations.
4 @METHOD     :
5 @GLOBALS    :
6 @CREATED    : November 10, 1993 (Peter Neelin)
7 @MODIFIED   :
8  * $Log: element.c,v $
9  * Revision 6.12  2008-08-12 05:00:22  rotor
10  *  * large number of changes from Claude (64 bit and updates)
11  *
12  * Revision 6.11  2006/09/01 16:33:49  jharlap
13  * fixed bug in Acr_nema that caused dump_acr_nema to skip all elements with element number 0x0010 when it should only have skipped 0x7fe0,0x0010.
14  *
15  * Revision 6.10  2006/04/09 15:28:40  bert
16  * Add functions acr_get_element_double_array and acr_create_element_double
17  *
18  * Revision 6.9  2006/03/10 19:22:56  bert
19  * Update to conversion/Acr_nema/element.c for value printing
20  *
21  * Revision 6.8  2005/07/14 15:56:56  bert
22  * Print raw byte data when dumping fields with unknown value representations and sizes other than 2 or 4. (ported from 1.X)
23  *
24  * Revision 6.7.2.2  2005/06/06 20:48:14  bert
25  * Print raw byte data when dumping fields with unknown value representations and sizes other than 2 or 4.
26  *
27  * Revision 6.7.2.1  2005/05/12 21:15:30  bert
28  * Initial checkin
29  *
30  * Revision 6.7  2005/04/18 23:22:29  bert
31  * Initialize newlist in acr_copy_element() to avoid problems with empty lists
32  *
33  * Revision 6.6  2005/03/11 22:05:29  bert
34  * Implement _acr_name_proc to allow printing of field names in dump_acr_nema
35  *
36  * Revision 6.5  2005/03/04 00:25:54  bert
37  * Avoid memory leak by freeing unused elements in a sequence.  Fix order of initialization in acr_create_element() to set variable length property correctly. Don't change VR encoding when parsing a sequence, rely on the new handling of 0xfffe group items by the acr_io functions
38  *
39  * Revision 6.4  2004/10/29 13:08:41  rotor
40  *  * rewrote Makefile with no dependency on a minc distribution
41  *  * removed all references to the abominable minc_def.h
42  *  * I should autoconf this really, but this is old code that
43  *      is now replaced by Jon Harlaps PERL version..
44  *
45  * Revision 6.3  2002/12/07 01:37:24  neelin
46  * Added missing type
47  *
48  * Revision 6.2  2001/12/12 19:00:54  neelin
49  * Corrected error in reading of a sequence element. When making a linked
50  * list of items, previtem was not being updated properly and items were
51  * being dropped. This exhibited itself as protocol error since an incorrect
52  * element length was being computed. (Thanks to Roch Comeau for pointing
53  * this out.)
54  *
55  * Revision 6.1  1999/10/29 17:51:52  neelin
56  * Fixed Log keyword
57  *
58  * Revision 6.0  1997/09/12 13:23:59  neelin
59  * Release of minc version 0.6
60  *
61  * Revision 5.2  1997/09/02  22:52:12  neelin
62  * Fixed padding of of UI strings and got rid of acr_string_pad_char
63  * function.
64  *
65  * Revision 5.1  1997/08/22  15:08:34  neelin
66  * Added routine acr_string_pad_char to set character used for padding
67  * strings to an even number of bytes.
68  *
69  * Revision 5.0  1997/08/21  13:25:00  neelin
70  * Release of minc version 0.5
71  *
72  * Revision 4.1  1997/05/13  22:46:25  neelin
73  * Modified behaviour of acr_create_element_string (and numeric) so that
74  * the VR type is taken from the elid if it is specified there.
75  *
76  * Revision 4.0  1997/05/07  20:01:23  neelin
77  * Release of minc version 0.4
78  *
79  * Revision 3.2  1997/04/21  20:21:09  neelin
80  * Updated the library to handle dicom messages.
81  *
82  * Revision 3.1  1995/11/16  13:13:49  neelin
83  * Added include of math.h to get declaration of strtod under SunOs
84  *
85  * Revision 3.0  1995/05/15  19:32:12  neelin
86  * Release of minc version 0.3
87  *
88  * Revision 2.0  1994/09/28  10:36:10  neelin
89  * Release of minc version 0.2
90  *
91  * Revision 1.8  94/09/28  10:35:44  neelin
92  * Pre-release
93  *
94  * Revision 1.7  93/11/30  12:19:15  neelin
95  * Handle MALLOC returning NULL because of extremely large data element length.
96  *
97  * Revision 1.6  93/11/30  08:57:28  neelin
98  * Added element copy routine.
99  *
100  * Revision 1.5  93/11/26  18:47:36  neelin
101  * Added element copy routine.
102  *
103  * Revision 1.4  93/11/25  10:35:34  neelin
104  * Ensure that strings have an even length (pad with space).
105  *
106  * Revision 1.3  93/11/24  11:25:14  neelin
107  * Changed short to unsigned short.
108  *
109  * Revision 1.2  93/11/22  13:11:34  neelin
110  * Added Acr_Element_Id code.
111  *
112  * Revision 1.1  93/11/19  12:48:12  neelin
113  * Initial revision
114  *
115 @COPYRIGHT  :
116               Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre,
117               Montreal Neurological Institute, McGill University.
118               Permission to use, copy, modify, and distribute this
119               software and its documentation for any purpose and without
120               fee is hereby granted, provided that the above copyright
121               notice appear in all copies.  The author and McGill University
122               make no representations about the suitability of this
123               software for any purpose.  It is provided "as is" without
124               express or implied warranty.
125 ---------------------------------------------------------------------------- */
126 
127 #include <stdlib.h>
128 #include <stdio.h>
129 #include <string.h>
130 #include <ctype.h>
131 #include <math.h>
132 #include <acr_nema.h>
133 
134 /* Private functions */
135 static void delete_element_data(Acr_Element element);
136 static Acr_Element create_element_mem(Acr_Element_Id elid,
137                                       Acr_VR_Type vr_code,
138                                       size_t value_size, void *value);
139 
140 /* Macros */
141 #define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
142 
143 
144 /* ----------------------------- MNI Header -----------------------------------
145 @NAME       : acr_create_element
146 @INPUT      : group_id
147               element_id
148               vr_code - Internal VR code
149               data_length - if < 0, then data is assumed to be a pointer to
150                  a list of elements in the sequence
151               data_pointer - pointer to actual data or to list of elements
152 @OUTPUT     : (none)
153 @RETURNS    : Pointer to element structure
154 @DESCRIPTION: Creates an acr-nema element structure. If data_length is
155               negative, then the element is a sequence and the data_pointer
156               must point to a list of elements. In this case, the element is
157               assumed to have variable length. If the element is an
158               ACR_VR_SQ, then it is possible to change it to have fixed length
159               by calling acr_set_element_variable_length with FALSE.
160 @METHOD     :
161 @GLOBALS    :
162 @CALLS      :
163 @CREATED    : November 10, 1993 (Peter Neelin)
164 @MODIFIED   : February 4, 1997 (P.N.)
165 ---------------------------------------------------------------------------- */
acr_create_element(int group_id,int element_id,Acr_VR_Type vr_code,long data_length,char * data_pointer)166 Acr_Element acr_create_element(int group_id, int element_id,
167                                Acr_VR_Type vr_code,
168                                long data_length, char *data_pointer)
169 {
170    Acr_Element element;
171 
172    /* Allocate the element. We set the data pointer to NULL so that
173       acr_set_element_data does not try to free an unitialized pointer */
174    element = MALLOC(sizeof(*element));
175    element->data_pointer = NULL;
176 
177    /* Assign fields */
178    acr_set_element_id(element, group_id, element_id);
179    acr_set_element_vr(element, vr_code);
180    acr_set_element_vr_encoding(element, ACR_EXPLICIT_VR);
181    acr_set_element_byte_order(element, acr_get_machine_byte_order());
182    acr_set_element_next(element, NULL);
183    acr_set_element_data(element, data_length, data_pointer);
184    acr_set_element_variable_length(element, (data_length < 0));
185 
186    return element;
187 }
188 
189 /* ----------------------------- MNI Header -----------------------------------
190 @NAME       : delete_element_data
191 @INPUT      : element
192 @OUTPUT     : (none)
193 @RETURNS    : (nothing)
194 @DESCRIPTION: Deletes element data, but leaves element in an intermediate
195               state with dangling pointers and incorrect lengths.
196 @METHOD     :
197 @GLOBALS    :
198 @CALLS      :
199 @CREATED    : February 4, 1997 (Peter Neelin)
200 @MODIFIED   :
201 ---------------------------------------------------------------------------- */
delete_element_data(Acr_Element element)202 static void delete_element_data(Acr_Element element)
203 {
204    char *data_pointer;
205 
206    data_pointer = acr_get_element_data(element);
207    if (data_pointer != NULL) {
208       if (acr_element_is_sequence(element)) {
209          acr_delete_element_list((Acr_Element) data_pointer);
210       }
211       else {
212          FREE(data_pointer);
213       }
214    }
215 
216    return;
217 }
218 
219 /* ----------------------------- MNI Header -----------------------------------
220 @NAME       : acr_delete_element
221 @INPUT      : element
222 @OUTPUT     : (none)
223 @RETURNS    : (nothing)
224 @DESCRIPTION: Deletes an acr-nema element structure (freeing the data pointer)
225 @METHOD     :
226 @GLOBALS    :
227 @CALLS      :
228 @CREATED    : November 10, 1993 (Peter Neelin)
229 @MODIFIED   : February 4, 1997 (P.N.)
230 ---------------------------------------------------------------------------- */
acr_delete_element(Acr_Element element)231 void acr_delete_element(Acr_Element element)
232 {
233 
234    if (element == NULL) return;
235    delete_element_data(element);
236    FREE(element);
237 
238    return;
239 }
240 
241 /* ----------------------------- MNI Header -----------------------------------
242 @NAME       : acr_delete_element_list
243 @INPUT      : element_list
244 @OUTPUT     : (none)
245 @RETURNS    : (nothing)
246 @DESCRIPTION: Delete a list of acr-nema elements
247 @METHOD     :
248 @GLOBALS    :
249 @CALLS      :
250 @CREATED    : November 10, 1993 (Peter Neelin)
251 @MODIFIED   :
252 ---------------------------------------------------------------------------- */
acr_delete_element_list(Acr_Element element_list)253 void acr_delete_element_list(Acr_Element element_list)
254 {
255    Acr_Element next, cur;
256 
257    if (element_list == NULL) return;
258 
259    /* Loop through the list, deleting elements */
260    next = element_list;
261    while (next != NULL) {
262       cur = next;
263       next = acr_get_element_next(cur);
264       acr_delete_element(cur);
265    }
266 
267    return;
268 }
269 
270 /* ----------------------------- MNI Header -----------------------------------
271 @NAME       : acr_element_list_add
272 @INPUT      : element_list - pointer to element list or NULL
273               element - element to add to list
274 @OUTPUT     : (none)
275 @RETURNS    : Pointer to new element list
276 @DESCRIPTION: Adds an element to a list of elements. If element_list is NULL,
277               then a new list is created.
278 @METHOD     :
279 @GLOBALS    :
280 @CALLS      :
281 @CREATED    : February 11, 1997 (P.N.)
282 @MODIFIED   :
283 ---------------------------------------------------------------------------- */
acr_element_list_add(Acr_Element element_list,Acr_Element element)284 Acr_Element acr_element_list_add(Acr_Element element_list,
285                                  Acr_Element element)
286 {
287    Acr_Element current;
288 
289    /* Add the element to the list */
290    if (element_list == NULL) {
291       element_list = element;
292    }
293    else {
294       current = element_list;
295       while (acr_get_element_next(current) != NULL) {
296          current = acr_get_element_next(current);
297       }
298       acr_set_element_next(current, element);
299    }
300 
301    return element_list;
302 
303 }
304 
305 /* ----------------------------- MNI Header -----------------------------------
306 @NAME       : acr_set_element_id
307 @INPUT      : element
308               group_id
309               element_id
310 @OUTPUT     : (none)
311 @RETURNS    : (nothing)
312 @DESCRIPTION: Set group and element id of an acr-nema element
313 @METHOD     :
314 @GLOBALS    :
315 @CALLS      :
316 @CREATED    : November 10, 1993 (Peter Neelin)
317 @MODIFIED   :
318 ---------------------------------------------------------------------------- */
acr_set_element_id(Acr_Element element,int group_id,int element_id)319 void acr_set_element_id(Acr_Element element,
320                         int group_id, int element_id)
321 {
322    element->group_id = group_id;
323    element->element_id = element_id;
324    return;
325 }
326 
327 /* ----------------------------- MNI Header -----------------------------------
328 @NAME       : acr_set_element_vr
329 @INPUT      : element
330               group_id
331               vr_code
332 @OUTPUT     : (none)
333 @RETURNS    : (nothing)
334 @DESCRIPTION: Set VR code for an element
335 @METHOD     :
336 @GLOBALS    :
337 @CALLS      :
338 @CREATED    : February 4, 1997 (Peter Neelin)
339 @MODIFIED   :
340 ---------------------------------------------------------------------------- */
acr_set_element_vr(Acr_Element element,Acr_VR_Type vr_code)341 void acr_set_element_vr(Acr_Element element,
342                         Acr_VR_Type vr_code)
343 {
344    element->vr_code = (short) vr_code;
345    return;
346 }
347 
348 /* ----------------------------- MNI Header -----------------------------------
349 @NAME       : acr_set_element_vr_encoding
350 @INPUT      : element
351               group_id
352               vr_encoding - ACR_EXPLICIT_ENCODING or ACR_IMPLICIT_ENCODING
353 @OUTPUT     : (none)
354 @RETURNS    : (nothing)
355 @DESCRIPTION: Set encoding type for element VR
356 @METHOD     :
357 @GLOBALS    :
358 @CALLS      :
359 @CREATED    : February 4, 1997 (Peter Neelin)
360 @MODIFIED   :
361 ---------------------------------------------------------------------------- */
acr_set_element_vr_encoding(Acr_Element element,Acr_VR_encoding_type vr_encoding)362 void acr_set_element_vr_encoding(Acr_Element element,
363                                  Acr_VR_encoding_type vr_encoding)
364 {
365    element->uses_explicit_vr = (vr_encoding == ACR_EXPLICIT_VR);
366    return;
367 }
368 
369 /* ----------------------------- MNI Header -----------------------------------
370 @NAME       : acr_set_element_byte_order
371 @INPUT      : element
372               group_id
373               byte_order - ACR_LITTLE_ENDIAN or ACR_BIG_ENDIAN
374 @OUTPUT     : (none)
375 @RETURNS    : (nothing)
376 @DESCRIPTION: Set byte order for an element
377 @METHOD     :
378 @GLOBALS    :
379 @CALLS      :
380 @CREATED    : February 14, 1997 (Peter Neelin)
381 @MODIFIED   :
382 ---------------------------------------------------------------------------- */
acr_set_element_byte_order(Acr_Element element,Acr_byte_order byte_order)383 void acr_set_element_byte_order(Acr_Element element,
384                                 Acr_byte_order byte_order)
385 {
386    element->has_little_endian_order = (byte_order == ACR_LITTLE_ENDIAN);
387    return;
388 }
389 
390 /* ----------------------------- MNI Header -----------------------------------
391 @NAME       : acr_set_element_variable_length
392 @INPUT      : element
393               group_id
394               has_variable_length
395 @OUTPUT     : (none)
396 @RETURNS    : (nothing)
397 @DESCRIPTION: Set flag indicating whether element has variable length or not.
398               This can only be set if the element contains sequence data.
399 @METHOD     :
400 @GLOBALS    :
401 @CALLS      :
402 @CREATED    : February 4, 1997 (Peter Neelin)
403 @MODIFIED   :
404 ---------------------------------------------------------------------------- */
acr_set_element_variable_length(Acr_Element element,int has_variable_length)405 void acr_set_element_variable_length(Acr_Element element,
406                                      int has_variable_length)
407 {
408    if (acr_element_is_sequence(element)) {
409       element->has_variable_length = (has_variable_length != FALSE);
410    }
411    else {
412       element->has_variable_length = FALSE;
413    }
414    return;
415 }
416 
417 /* ----------------------------- MNI Header -----------------------------------
418 @NAME       : acr_set_element_data
419 @INPUT      : element
420               data_length - if < 0, then data is treated as a list of
421                  elements
422               data_pointer
423 @OUTPUT     : (none)
424 @RETURNS    : (nothing)
425 @DESCRIPTION: Set data length and pointer of an acr-nema element. A negative
426               length means that this element is a sequence and the data
427               pointer points to a list of elements (items).
428 @METHOD     :
429 @GLOBALS    :
430 @CALLS      :
431 @CREATED    : November 10, 1993 (Peter Neelin)
432 @MODIFIED   : February 4, 1997 (P.N.)
433 ---------------------------------------------------------------------------- */
acr_set_element_data(Acr_Element element,long data_length,char * data_pointer)434 void acr_set_element_data(Acr_Element element,
435                           long data_length, char *data_pointer)
436 {
437    Acr_Element item, last, last2;
438    long last_length;
439 
440    /* Free the old data if needed */
441    if (element->data_pointer != NULL) {
442       delete_element_data(element);
443    }
444 
445    /* Set the pointer and check for a sequence */
446    element->data_pointer = data_pointer;
447    element->is_sequence = (data_length < 0);
448 
449    /* If we have a sequence, work out its length and set each item to not
450       use explicit VR */
451    if (element->is_sequence) {
452       data_length = 0;
453       last = last2 = NULL;
454       for (item = (Acr_Element) data_pointer;
455            item != NULL;
456            item=acr_get_element_next(item)) {
457          last_length = acr_get_element_total_length(item, ACR_IMPLICIT_VR);
458          data_length += last_length;
459          acr_set_element_vr_encoding(item, ACR_IMPLICIT_VR);
460          last2 = last;
461          last = item;
462       }
463 
464       /* Check for a last delimiting item - remove it so that we don't
465          have to worry about switching between defined and undefined
466          lengths - it will always be added later */
467       if ((last != NULL) &&
468           (acr_get_element_group(last) == ACR_ITEM_GROUP) &&
469           ((acr_get_element_element(last) == ACR_ITEM_DELIMITER) ||
470            (acr_get_element_element(last) == ACR_SEQ_DELIMITER))) {
471          if (last2 != NULL) {
472             acr_set_element_next(last2, NULL);
473             data_length -= last_length;
474          }
475          else {
476             element->data_pointer = NULL;
477             data_length = 0;
478          }
479          acr_delete_element(last);
480       }
481 
482    }
483 
484    /* Save the length */
485    element->data_length = data_length;
486 
487    return;
488 }
489 
490 /* ----------------------------- MNI Header -----------------------------------
491 @NAME       : acr_set_element_next
492 @INPUT      : element
493               next
494 @OUTPUT     : (none)
495 @RETURNS    : (nothing)
496 @DESCRIPTION: Set pointer to next element for an acr-nema element
497 @METHOD     :
498 @GLOBALS    :
499 @CALLS      :
500 @CREATED    : November 10, 1993 (Peter Neelin)
501 @MODIFIED   :
502 ---------------------------------------------------------------------------- */
acr_set_element_next(Acr_Element element,Acr_Element next)503 void acr_set_element_next(Acr_Element element, Acr_Element next)
504 {
505    element->next = next;
506    return;
507 }
508 
509 /* ----------------------------- MNI Header -----------------------------------
510 @NAME       : acr_get_element_group
511 @INPUT      : element
512 @OUTPUT     : (none)
513 @RETURNS    : group id
514 @DESCRIPTION: Get group id for element
515 @METHOD     :
516 @GLOBALS    :
517 @CALLS      :
518 @CREATED    : November 10, 1993 (Peter Neelin)
519 @MODIFIED   :
520 ---------------------------------------------------------------------------- */
acr_get_element_group(Acr_Element element)521 int acr_get_element_group(Acr_Element element)
522 {
523    return element->group_id;
524 }
525 
526 /* ----------------------------- MNI Header -----------------------------------
527 @NAME       : acr_get_element_element
528 @INPUT      : element
529 @OUTPUT     : (none)
530 @RETURNS    : element id
531 @DESCRIPTION: Get element id for element
532 @METHOD     :
533 @GLOBALS    :
534 @CALLS      :
535 @CREATED    : November 10, 1993 (Peter Neelin)
536 @MODIFIED   :
537 ---------------------------------------------------------------------------- */
acr_get_element_element(Acr_Element element)538 int acr_get_element_element(Acr_Element element)
539 {
540    return element->element_id;
541 }
542 
543 /* ----------------------------- MNI Header -----------------------------------
544 @NAME       : acr_get_element_vr
545 @INPUT      : element
546 @OUTPUT     : (none)
547 @RETURNS    : element VR code
548 @DESCRIPTION: Get VR code for element
549 @METHOD     :
550 @GLOBALS    :
551 @CALLS      :
552 @CREATED    : February 4, 1997 (Peter Neelin)
553 @MODIFIED   :
554 ---------------------------------------------------------------------------- */
acr_get_element_vr(Acr_Element element)555 Acr_VR_Type acr_get_element_vr(Acr_Element element)
556 {
557    return (Acr_VR_Type) element->vr_code;
558 }
559 
560 /* ----------------------------- MNI Header -----------------------------------
561 @NAME       : acr_get_element_vr_encoding
562 @INPUT      : element
563 @OUTPUT     : (none)
564 @RETURNS    : ACR_EXPLICIT_ENCODING or ACR_IMPLICIT_ENCODING
565 @DESCRIPTION: Get VR encoding type for element
566 @METHOD     :
567 @GLOBALS    :
568 @CALLS      :
569 @CREATED    : February 4, 1997 (Peter Neelin)
570 @MODIFIED   :
571 ---------------------------------------------------------------------------- */
acr_get_element_vr_encoding(Acr_Element element)572 Acr_VR_encoding_type acr_get_element_vr_encoding(Acr_Element element)
573 {
574    return (element->uses_explicit_vr ? ACR_EXPLICIT_VR : ACR_IMPLICIT_VR);
575 }
576 
577 /* ----------------------------- MNI Header -----------------------------------
578 @NAME       : acr_element_is_sequence
579 @INPUT      : element
580 @OUTPUT     : (none)
581 @RETURNS    : TRUE if element stores a sequence of items
582 @DESCRIPTION:
583 @METHOD     :
584 @GLOBALS    :
585 @CALLS      :
586 @CREATED    : February 4, 1997 (Peter Neelin)
587 @MODIFIED   :
588 ---------------------------------------------------------------------------- */
acr_element_is_sequence(Acr_Element element)589 int acr_element_is_sequence(Acr_Element element)
590 {
591    return element->is_sequence;
592 }
593 
594 /* ----------------------------- MNI Header -----------------------------------
595 @NAME       : acr_get_element_byte_order
596 @INPUT      : element
597 @OUTPUT     : (none)
598 @RETURNS    : ACR_BIG_ENDIAN or ACR_LITTLE_ENDIAN
599 @DESCRIPTION:
600 @METHOD     :
601 @GLOBALS    :
602 @CALLS      :
603 @CREATED    : February 17, 1997 (Peter Neelin)
604 @MODIFIED   :
605 ---------------------------------------------------------------------------- */
acr_get_element_byte_order(Acr_Element element)606 Acr_byte_order acr_get_element_byte_order(Acr_Element element)
607 {
608    return (element->has_little_endian_order ?
609            ACR_LITTLE_ENDIAN : ACR_BIG_ENDIAN);
610 }
611 
612 /* ----------------------------- MNI Header -----------------------------------
613 @NAME       : acr_element_has_variable_length
614 @INPUT      : element
615 @OUTPUT     : (none)
616 @RETURNS    : TRUE if element has variable length representation
617 @DESCRIPTION:
618 @METHOD     :
619 @GLOBALS    :
620 @CALLS      :
621 @CREATED    : February 4, 1997 (Peter Neelin)
622 @MODIFIED   :
623 ---------------------------------------------------------------------------- */
acr_element_has_variable_length(Acr_Element element)624 int acr_element_has_variable_length(Acr_Element element)
625 {
626    return element->has_variable_length;
627 }
628 
629 /* ----------------------------- MNI Header -----------------------------------
630 @NAME       : acr_get_element_length
631 @INPUT      : element
632 @OUTPUT     : (none)
633 @RETURNS    : data_length
634 @DESCRIPTION: Get data length for element. If we have a variable length
635               sequence, then we add in the length of the sequence delimiter.
636 @METHOD     :
637 @GLOBALS    :
638 @CALLS      :
639 @CREATED    : November 10, 1993 (Peter Neelin)
640 @MODIFIED   :
641 ---------------------------------------------------------------------------- */
acr_get_element_length(Acr_Element element)642 long acr_get_element_length(Acr_Element element)
643 {
644    long data_length;
645 
646    data_length = element->data_length;
647 
648    if (acr_element_has_variable_length(element)) {
649       data_length += 2 * ACR_SIZEOF_SHORT + ACR_SIZEOF_LONG;
650    }
651 
652    return data_length;
653 }
654 
655 /* ----------------------------- MNI Header -----------------------------------
656 @NAME       : acr_get_element_data
657 @INPUT      : element
658 @OUTPUT     : (none)
659 @RETURNS    : data_pointer
660 @DESCRIPTION: Get data pointer for element
661 @METHOD     :
662 @GLOBALS    :
663 @CALLS      :
664 @CREATED    : November 10, 1993 (Peter Neelin)
665 @MODIFIED   :
666 ---------------------------------------------------------------------------- */
acr_get_element_data(Acr_Element element)667 char *acr_get_element_data(Acr_Element element)
668 {
669    return element->data_pointer;
670 }
671 
672 /* ----------------------------- MNI Header -----------------------------------
673 @NAME       : acr_get_element_total_length
674 @INPUT      : element
675               vr_encoding - ACR_IMPLICIT_VR or ACR_EXPLICIT_VR
676 @OUTPUT     : (none)
677 @RETURNS    : total length for element, or zero if error.
678 @DESCRIPTION: Get total length for element in ACR-NEMA representation
679               depending on VR
680 @METHOD     :
681 @GLOBALS    :
682 @CALLS      :
683 @CREATED    : November 10, 1993 (Peter Neelin)
684 @MODIFIED   :
685 ---------------------------------------------------------------------------- */
acr_get_element_total_length(Acr_Element element,Acr_VR_encoding_type vr_encoding)686 long acr_get_element_total_length(Acr_Element element,
687                                   Acr_VR_encoding_type vr_encoding)
688 {
689    /* bert- verify that the VR name is non-null. This protects against
690     * core dumps when reading improperly-formatted files.
691     */
692    char *vr_name = acr_get_vr_name(acr_get_element_vr(element));
693    if (vr_name == NULL) {
694       return (0);
695    }
696 
697    return acr_get_element_length(element) +
698       acr_get_element_header_size(vr_name, vr_encoding);
699 }
700 
701 /* ----------------------------- MNI Header -----------------------------------
702 @NAME       : acr_get_element_next
703 @INPUT      : element
704 @OUTPUT     : (none)
705 @RETURNS    : next element
706 @DESCRIPTION: Get next element for element
707 @METHOD     :
708 @GLOBALS    :
709 @CALLS      :
710 @CREATED    : November 10, 1993 (Peter Neelin)
711 @MODIFIED   :
712 ---------------------------------------------------------------------------- */
acr_get_element_next(Acr_Element element)713 Acr_Element acr_get_element_next(Acr_Element element)
714 {
715    return element->next;
716 }
717 
718 /* ----------------------------- MNI Header -----------------------------------
719 @NAME       : acr_copy_element
720 @INPUT      : element
721 @OUTPUT     : (none)
722 @RETURNS    : (nothing)
723 @DESCRIPTION: Copies an acr-nema element structure
724 @METHOD     :
725 @GLOBALS    :
726 @CALLS      :
727 @CREATED    : November 26, 1993 (Peter Neelin)
728 @MODIFIED   : February 4, 1997 (P.N.)
729 ---------------------------------------------------------------------------- */
acr_copy_element(Acr_Element element)730 Acr_Element acr_copy_element(Acr_Element element)
731 {
732    Acr_Element copy;
733    long length;
734    unsigned char *data;
735    Acr_Element olditem, newitem, newlist;
736 
737    /* Check for NULL element */
738    if (element == NULL) return NULL;
739 
740    /* Copy a sequence */
741    if (acr_element_is_sequence(element)) {
742       length = -1;
743       olditem = (Acr_Element) acr_get_element_data(element);
744       newitem = NULL;
745       newlist = NULL;           /* bert- initialize in case list is empty */
746       while (olditem != NULL) {
747          if (newitem == NULL) {
748             newlist = acr_copy_element(olditem);
749             newitem = newlist;
750          }
751          else {
752             acr_set_element_next(newitem, acr_copy_element(olditem));
753             newitem = acr_get_element_next(newitem);
754          }
755          olditem = olditem->next;
756       }
757       data = (unsigned char *) newlist;
758    }
759 
760    /* Or copy a value */
761    else {
762       length = acr_get_element_length(element);
763       data = MALLOC(length+1);
764       if (data == NULL) {
765          length = 0;
766          data = MALLOC(length+1);
767       }
768       data[length] = '\0';
769       if (length > 0) {
770          (void) memcpy(data, acr_get_element_data(element), length);
771       }
772    }
773 
774    /* Create the new element */
775    copy = acr_create_element(acr_get_element_group(element),
776                              acr_get_element_element(element),
777                              acr_get_element_vr(element),
778                              length, (void *) data);
779    acr_set_element_vr_encoding(copy, acr_get_element_vr_encoding(element));
780    acr_set_element_byte_order(copy, acr_get_element_byte_order(element));
781    acr_set_element_variable_length(copy,
782                                    acr_element_has_variable_length(element));
783 
784 
785    return copy;
786 }
787 
788 /* ----------------------------- MNI Header -----------------------------------
789 @NAME       : acr_input_element
790 @INPUT      : afp - acr file pointer
791 @OUTPUT     : element
792 @RETURNS    : status
793 @DESCRIPTION: Read in an acr-nema element
794 @METHOD     :
795 @GLOBALS    :
796 @CALLS      :
797 @CREATED    : November 10, 1993 (Peter Neelin)
798 @MODIFIED   :
799 ---------------------------------------------------------------------------- */
acr_input_element(Acr_File * afp,Acr_Element * element)800 Acr_Status acr_input_element(Acr_File *afp, Acr_Element *element)
801 {
802    int group_id, element_id, item_gid, item_elid;
803    long data_length;
804    char vr_name[2];
805    char *data_pointer;
806    Acr_Status status;
807    int is_sequence, more_to_read, found_delimiter, has_variable_length;
808    Acr_Element item, itemlist, previtem;
809    Acr_VR_Type vr_code;
810    Acr_VR_encoding_type vr_encoding;
811 
812    /* Set element in case of error */
813    *element = NULL;
814 
815    vr_encoding = acr_get_vr_encoding(afp);
816 
817    /* Read in the value */
818    status = acr_read_one_element(afp, &group_id, &element_id, vr_name,
819                                  &data_length, &data_pointer);
820 
821    if (status != ACR_OK) {
822       return status;
823    }
824 
825    /* Get VR code */
826    vr_code = acr_lookup_vr_name(vr_name);
827 
828    /* Check for sequence */
829    is_sequence = (data_length < 0);
830    if ((data_length > 0)  && (data_pointer == NULL)) {
831       is_sequence = TRUE;
832    }
833 
834    has_variable_length = (data_length < 0);
835 
836    /* If we have a sequence, read in all the items and store them as a
837       list of elements. */
838    if (is_sequence) {
839 
840       more_to_read = TRUE;
841       itemlist = NULL;
842 
843       while (more_to_read) {
844 
845          /* Read in an item */
846          status = acr_input_element(afp, &item);
847          if (item == NULL) break;
848 
849          /* If we know the length of the whole sequence, check it */
850          if ((status == ACR_OK) && (data_length > 0)) {
851             data_length -= acr_get_element_total_length(item, vr_encoding);
852             if (data_length < 0) status = ACR_PROTOCOL_ERROR;
853          }
854 
855          /* Look for delimiter */
856          item_gid = acr_get_element_group(item);
857          item_elid = acr_get_element_element(item);
858          found_delimiter =
859             ((item_gid == ACR_ITEM_GROUP) &&
860              ((item_elid == ACR_ITEM_DELIMITER) ||
861               (item_elid == ACR_SEQ_DELIMITER)));
862 
863          /* Add the item to the list if it is not a delimiter */
864          if (!found_delimiter) {
865             if (itemlist == NULL) {
866                itemlist = item;
867             }
868             else {
869                acr_set_element_next(previtem, item);
870             }
871             previtem = item;
872          }
873          else {
874              free(item);        /* Avoid leaking memory */
875          }
876 
877          /* Check for end of items */
878          if ((data_length == 0) || found_delimiter || (status != ACR_OK)) {
879             more_to_read = FALSE;
880          }
881       }        /* End of loop over items */
882 
883       /* Save the item list as the data */
884       data_pointer = (char *) itemlist;
885    }
886 
887    /* Create the element */
888    *element = acr_create_element(group_id, element_id, vr_code,
889                                  (is_sequence ? -1 : data_length),
890                                  data_pointer);
891    acr_set_element_vr_encoding(*element, acr_get_vr_encoding(afp));
892    acr_set_element_byte_order(*element, acr_get_byte_order(afp));
893    if (is_sequence && !has_variable_length) {
894       acr_set_element_variable_length(*element, FALSE);
895    }
896 
897    return status;
898 }
899 
900 /* ----------------------------- MNI Header -----------------------------------
901 @NAME       : acr_output_element
902 @INPUT      : afp - acr file pointer
903               element
904 @OUTPUT     : (none)
905 @RETURNS    : status
906 @DESCRIPTION: Write out an acr-nema element. The byte ordering of the element
907               data is changed to match that of the output stream
908 @METHOD     :
909 @GLOBALS    :
910 @CALLS      :
911 @CREATED    : November 10, 1993 (Peter Neelin)
912 @MODIFIED   :
913 ---------------------------------------------------------------------------- */
acr_output_element(Acr_File * afp,Acr_Element element)914 Acr_Status acr_output_element(Acr_File *afp, Acr_Element element)
915 {
916    char *vr_name;
917    Acr_VR_Type vr_code;
918    Acr_Status status;
919    long data_length;
920    int is_sequence, has_variable_length;
921    char *data_pointer;
922    int item_id;
923    Acr_Element item;
924    Acr_VR_encoding_type old_vr_encoding;
925 
926    /* Get info from element */
927    vr_code = acr_get_element_vr(element);
928    vr_name = acr_get_vr_name(vr_code);
929    is_sequence = acr_element_is_sequence(element);
930    has_variable_length = acr_element_has_variable_length(element);
931    if (is_sequence && has_variable_length) {
932       data_length = ACR_VARIABLE_LENGTH;
933    }
934    else {
935       data_length = acr_get_element_length(element);
936    }
937 
938    /* Get the data. */
939    if (is_sequence) {
940       data_pointer = NULL;
941    }
942    else {
943       data_pointer = acr_get_element_data(element);
944    }
945 
946    /* Convert the element byte order */
947    acr_convert_element_byte_order(element, acr_get_byte_order(afp));
948 
949    /* Write out the element */
950    status = acr_write_one_element(afp,
951                                   acr_get_element_group(element),
952                                   acr_get_element_element(element),
953                                   vr_name, data_length, data_pointer);
954    if (status != ACR_OK) return status;
955 
956    /* Write out items if we have a sequence */
957    if (is_sequence) {
958 
959       /* Set the encoding to implicit for items */
960       old_vr_encoding = acr_get_vr_encoding(afp);
961       acr_set_vr_encoding(afp, ACR_IMPLICIT_VR);
962 
963       /* Loop over items */
964       item = (Acr_Element) acr_get_element_data(element);
965       while (item != NULL) {
966          status = acr_output_element(afp, item);
967          if (status != ACR_OK) return status;
968          item = acr_get_element_next(item);
969       }
970 
971       /* Write out the delimiter if needed */
972       if (has_variable_length) {
973          if (acr_get_element_group(element) == ACR_ITEM_GROUP) {
974             item_id = ACR_ITEM_DELIMITER;
975          }
976          else {
977             item_id = ACR_SEQ_DELIMITER;
978          }
979          status = acr_write_one_element(afp, ACR_ITEM_GROUP, item_id,
980                                         ACR_VR_UNKNOWN, 0L, NULL);
981          if (status != ACR_OK) return status;
982       }
983 
984       /* Restore the VR encoding */
985       acr_set_vr_encoding(afp, old_vr_encoding);
986 
987    }
988 
989    return status;
990 }
991 
992 /* ----------------------------- MNI Header -----------------------------------
993 @NAME       : acr_convert_element_byte_order
994 @INPUT      : element
995               byte_order - ACR_BIG_ENDIAN or ACR_LITTLE_ENDIAN
996 @OUTPUT     : (none)
997 @RETURNS    : status
998 @DESCRIPTION: Converts the data within an element to a specified byte_order.
999 @METHOD     :
1000 @GLOBALS    :
1001 @CALLS      :
1002 @CREATED    : November 10, 1993 (Peter Neelin)
1003 @MODIFIED   :
1004 ---------------------------------------------------------------------------- */
acr_convert_element_byte_order(Acr_Element element,Acr_byte_order byte_order)1005 void acr_convert_element_byte_order(Acr_Element element,
1006                                     Acr_byte_order byte_order)
1007 {
1008    Acr_byte_order element_byte_order;
1009    long nvalues;
1010    size_t value_size;
1011 
1012    /* Get the element and stream byte orders and change the element
1013       byte order to match that of the stream */
1014    element_byte_order = acr_get_element_byte_order(element);
1015    acr_set_element_byte_order(element, byte_order);
1016 
1017    /* Change byte order of data in place */
1018    if (!acr_element_is_sequence(element)) {
1019 
1020       /* Look for types that might need byte swapping */
1021       switch (acr_get_element_vr(element)) {
1022       case ACR_VR_SS:
1023       case ACR_VR_US:
1024       case ACR_VR_OW:
1025          value_size = ACR_SIZEOF_SHORT; break;
1026       case ACR_VR_SL:
1027       case ACR_VR_UL:
1028          value_size = ACR_SIZEOF_LONG; break;
1029       case ACR_VR_FL:
1030          value_size = ACR_SIZEOF_FLOAT; break;
1031       case ACR_VR_FD:
1032          value_size = ACR_SIZEOF_DOUBLE; break;
1033       default:
1034          value_size = 1; break;
1035       }
1036 
1037       /* Reverse byte order */
1038       if (value_size > 1) {
1039          if (element_byte_order != byte_order) {
1040             nvalues = acr_get_element_length(element) / value_size;
1041             acr_reverse_byte_order(nvalues, value_size,
1042                                    acr_get_element_data(element), NULL);
1043          }
1044       }
1045    }
1046 
1047 }
1048 
1049 /* ----------------------------- MNI Header -----------------------------------
1050 @NAME       : acr_match_element_id
1051 @INPUT      : elid - element id to check
1052               element - element to check
1053 @OUTPUT     : (none)
1054 @RETURNS    : TRUE if the ids match, FALSE otherwise
1055 @DESCRIPTION: Compares the group and element id of an element id structure to
1056               that of an element. Returns TRUE if they are the same.
1057 @METHOD     :
1058 @GLOBALS    :
1059 @CALLS      :
1060 @CREATED    : February 12, 1997 (Peter Neelin)
1061 @MODIFIED   :
1062 ---------------------------------------------------------------------------- */
acr_match_element_id(Acr_Element_Id elid,Acr_Element element)1063 int acr_match_element_id(Acr_Element_Id elid,
1064                          Acr_Element element)
1065 {
1066    return ((elid->group_id == acr_get_element_group(element)) &&
1067            (elid->element_id == acr_get_element_element(element)));
1068 }
1069 
1070 /* ----------------------------- MNI Header -----------------------------------
1071 @NAME       : acr_find_element_id
1072 @INPUT      : elid - element id to check
1073               element_list - element list to search
1074 @OUTPUT     : (none)
1075 @RETURNS    : Pointer to element found or NULL
1076 @DESCRIPTION: Searches an element list for an element id. As a side effect,
1077               the VR type of the element is set if it is previously unknown
1078               and it is defined in the element id structure.
1079 @METHOD     :
1080 @GLOBALS    :
1081 @CALLS      :
1082 @CREATED    : February 12, 1997 (Peter Neelin)
1083 @MODIFIED   :
1084 ---------------------------------------------------------------------------- */
acr_find_element_id(Acr_Element element_list,Acr_Element_Id elid)1085 Acr_Element acr_find_element_id(Acr_Element element_list,
1086                                 Acr_Element_Id elid)
1087 {
1088    Acr_Element element;
1089 
1090    /* Look for the element */
1091    element = element_list;
1092    while ((element != NULL) && !acr_match_element_id(elid, element)) {
1093       element = acr_get_element_next(element);
1094    }
1095 
1096    /* Set the VR type if it is unknown */
1097    if ((element != NULL) &&
1098        (acr_get_element_vr(element) == ACR_VR_UNKNOWN) &&
1099        (elid->vr_code != ACR_VR_UNKNOWN)) {
1100       acr_set_element_vr(element, elid->vr_code);
1101    }
1102 
1103    return element;
1104 }
1105 
1106 /* ----------------------------- MNI Header -----------------------------------
1107 @NAME       : acr_memdup
1108 @INPUT      : value_size - number of bytes to copy
1109               value - value to copy
1110 @OUTPUT     : (none)
1111 @RETURNS    : Pointer to copy of data
1112 @DESCRIPTION: Allocates memory and makes a copy of some memory
1113 @METHOD     :
1114 @GLOBALS    :
1115 @CALLS      :
1116 @CREATED    : February 14, 1997 (Peter Neelin)
1117 @MODIFIED   :
1118 ---------------------------------------------------------------------------- */
acr_memdup(size_t value_size,void * value)1119 void *acr_memdup(size_t value_size, void *value)
1120 {
1121    char *copy, *original;
1122    size_t i;
1123 
1124    original = (char *) value;
1125    copy = (char *) MALLOC(value_size);
1126    for (i=0; i<value_size; i++) {
1127       copy[i] = original[i];
1128    }
1129    return (void *) copy;
1130 }
1131 
1132 /* ----------------------------- MNI Header -----------------------------------
1133 @NAME       : create_element_mem
1134 @INPUT      : elid
1135               vr_code - internal VR code for element
1136               value_size
1137               value
1138 @OUTPUT     : (none)
1139 @RETURNS    : Pointer to element structure
1140 @DESCRIPTION: Creates an acr-nema element structure containing data of the
1141               specified size. The data is copied into a new memory location.
1142 @METHOD     :
1143 @GLOBALS    :
1144 @CALLS      :
1145 @CREATED    : February 14, 1997 (Peter Neelin)
1146 @MODIFIED   :
1147 ---------------------------------------------------------------------------- */
create_element_mem(Acr_Element_Id elid,Acr_VR_Type vr_code,size_t value_size,void * value)1148 static Acr_Element create_element_mem(Acr_Element_Id elid,
1149                                       Acr_VR_Type vr_code,
1150                                       size_t value_size, void *value)
1151 {
1152    return acr_create_element(elid->group_id, elid->element_id, vr_code,
1153                              value_size, acr_memdup(value_size, value));
1154 }
1155 
1156 /* ----------------------------- MNI Header -----------------------------------
1157 @NAME       : acr_create_element_short
1158 @INPUT      : elid
1159               value
1160 @OUTPUT     : (none)
1161 @RETURNS    : Pointer to element structure
1162 @DESCRIPTION: Creates an acr-nema element structure containing one short.
1163 @METHOD     :
1164 @GLOBALS    :
1165 @CALLS      :
1166 @CREATED    : November 17, 1993 (Peter Neelin)
1167 @MODIFIED   :
1168 ---------------------------------------------------------------------------- */
acr_create_element_short(Acr_Element_Id elid,Acr_Short value)1169 Acr_Element acr_create_element_short(Acr_Element_Id elid,
1170                                      Acr_Short value)
1171 {
1172    return create_element_mem(elid, ACR_VR_US, sizeof(value), (void *) &value);
1173 }
1174 
1175 /* ----------------------------- MNI Header -----------------------------------
1176 @NAME       : acr_create_element_long
1177 @INPUT      : elid
1178               value
1179 @OUTPUT     : (none)
1180 @RETURNS    : Pointer to element structure
1181 @DESCRIPTION: Creates an acr-nema element structure containing one long.
1182 @METHOD     :
1183 @GLOBALS    :
1184 @CALLS      :
1185 @CREATED    : November 17, 1993 (Peter Neelin)
1186 @MODIFIED   :
1187 ---------------------------------------------------------------------------- */
acr_create_element_long(Acr_Element_Id elid,Acr_Long value)1188 Acr_Element acr_create_element_long(Acr_Element_Id elid,
1189                                     Acr_Long value)
1190 {
1191    return create_element_mem(elid, ACR_VR_UL, sizeof(value), (void *) &value);
1192 }
1193 
1194 /* ----------------------------- MNI Header -----------------------------------
1195 @NAME       : acr_create_element_double
1196 @INPUT      : elid
1197               nvalues
1198               values
1199 @OUTPUT     : (none)
1200 @RETURNS    : Pointer to element structure
1201 @DESCRIPTION: Creates an acr-nema element structure containing an array of
1202               doubles.
1203 @METHOD     :
1204 @GLOBALS    :
1205 @CALLS      :
1206 @CREATED    : April 8, 2006 (Bert Vincent)
1207 @MODIFIED   :
1208 ---------------------------------------------------------------------------- */
acr_create_element_double(Acr_Element_Id elid,int nvalues,Acr_Double * values)1209 Acr_Element acr_create_element_double(Acr_Element_Id elid,
1210                                       int nvalues,
1211                                       Acr_Double *values)
1212 {
1213    return create_element_mem(elid, ACR_VR_FD, (ACR_SIZEOF_DOUBLE * nvalues),
1214                              values);
1215 }
1216 
1217 /* ----------------------------- MNI Header -----------------------------------
1218 @NAME       : acr_create_element_numeric
1219 @INPUT      : elid
1220               value
1221 @OUTPUT     : (none)
1222 @RETURNS    : Pointer to element structure
1223 @DESCRIPTION: Creates an acr-nema element structure containing one ascii
1224               numeric.
1225               Note that the VR type is taken from the elid structure unless
1226               it is not specified there (ACR_VR_UNKNOWN).
1227 @METHOD     :
1228 @GLOBALS    :
1229 @CALLS      :
1230 @CREATED    : November 17, 1993 (Peter Neelin)
1231 @MODIFIED   :
1232 ---------------------------------------------------------------------------- */
acr_create_element_numeric(Acr_Element_Id elid,double value)1233 Acr_Element acr_create_element_numeric(Acr_Element_Id elid,
1234                                        double value)
1235 {
1236    char string[256];
1237    Acr_Element element;
1238 
1239    if (elid->vr_code == ACR_VR_FD) {
1240        element = create_element_mem(elid, ACR_VR_FD, sizeof(value),
1241                                     (void *) &value);
1242    }
1243    else {
1244        (void) sprintf(string, "%.15g", value);
1245        element = acr_create_element_string(elid, string);
1246        if (elid->vr_code == ACR_VR_UNKNOWN)
1247            acr_set_element_vr(element, ACR_VR_DS);
1248    }
1249    return element;
1250 }
1251 
1252 /* ----------------------------- MNI Header -----------------------------------
1253 @NAME       : acr_create_element_string
1254 @INPUT      : elid
1255               value
1256 @OUTPUT     : (none)
1257 @RETURNS    : Pointer to element structure
1258 @DESCRIPTION: Creates an acr-nema element structure containing an ascii string.
1259               Note that the string is duplicated for the element structure.
1260               Note also that the VR type is taken from the elid structure
1261               unless it is not specified there (ACR_VR_UNKNOWN).
1262 @METHOD     :
1263 @GLOBALS    :
1264 @CALLS      :
1265 @CREATED    : November 17, 1993 (Peter Neelin)
1266 @MODIFIED   :
1267 ---------------------------------------------------------------------------- */
acr_create_element_string(Acr_Element_Id elid,Acr_String value)1268 Acr_Element acr_create_element_string(Acr_Element_Id elid,
1269                                       Acr_String value)
1270 {
1271    long data_length;
1272    long alloc_length;
1273    char *data;
1274    int pad;
1275    Acr_VR_Type vr_code;
1276 
1277    /* Get the appropriate vr code */
1278    vr_code = ((elid->vr_code == ACR_VR_UNKNOWN) ? ACR_VR_ST : elid->vr_code);
1279 
1280    /* Get string length and check for an odd length */
1281    data_length = strlen(value);
1282    if ((data_length % 2) == 0)
1283       pad = FALSE;
1284    else {
1285       pad = TRUE;
1286       data_length++;
1287    }
1288 
1289    /* Allocate the string and copy it */
1290    alloc_length = data_length + 1;
1291    data = (char *) MALLOC(alloc_length);
1292    (void) strcpy(data, value);
1293 
1294    /* Pad the end with a blank or NUL if needed */
1295    if (pad) {
1296       data[data_length - 1] = ((vr_code == ACR_VR_UI) ? '\0' : ' ');
1297       data[data_length] = '\0';
1298    }
1299 
1300    /* Create the element and return it */
1301    return acr_create_element(elid->group_id, elid->element_id,
1302                              vr_code, data_length, data);
1303 }
1304 
1305 /* ----------------------------- MNI Header -----------------------------------
1306 @NAME       : acr_create_element_sequence
1307 @INPUT      : elid
1308               value
1309 @OUTPUT     : (none)
1310 @RETURNS    : Pointer to element structure
1311 @DESCRIPTION: Creates an acr-nema element structure containing a sequence of
1312               items.
1313 @METHOD     :
1314 @GLOBALS    :
1315 @CALLS      :
1316 @CREATED    : February 12, 1997 (Peter Neelin)
1317 @MODIFIED   :
1318 ---------------------------------------------------------------------------- */
acr_create_element_sequence(Acr_Element_Id elid,Acr_Element itemlist)1319 Acr_Element acr_create_element_sequence(Acr_Element_Id elid,
1320                                         Acr_Element itemlist)
1321 {
1322    return acr_create_element(elid->group_id, elid->element_id,
1323                              ACR_VR_SQ, -1L, (char *) itemlist);
1324 }
1325 
1326 /* ----------------------------- MNI Header -----------------------------------
1327 @NAME       : acr_get_element_short
1328 @INPUT      : element
1329 @OUTPUT     : (none)
1330 @RETURNS    : Value from element structure
1331 @DESCRIPTION: Gets a single short from an element structure. Returns zero
1332               if an error occurs.
1333 @METHOD     :
1334 @GLOBALS    :
1335 @CALLS      :
1336 @CREATED    : November 17, 1993 (Peter Neelin)
1337 @MODIFIED   :
1338 ---------------------------------------------------------------------------- */
acr_get_element_short(Acr_Element element)1339 Acr_Short acr_get_element_short(Acr_Element element)
1340 {
1341    Acr_Short value;
1342 
1343    value = (Acr_Short)acr_get_numeric_vr(acr_get_element_vr(element),
1344                                          acr_get_element_byte_order(element),
1345                                          acr_get_element_data(element),
1346                                          acr_get_element_length(element));
1347 
1348    return value;
1349 }
1350 
1351 /* ----------------------------- MNI Header -----------------------------------
1352 @NAME       : acr_get_element_long
1353 @INPUT      : element
1354 @OUTPUT     : (none)
1355 @RETURNS    : Value from element structure
1356 @DESCRIPTION: Gets a single long from an element structure. Returns zero
1357               if an error occurs.
1358 @METHOD     :
1359 @GLOBALS    :
1360 @CALLS      :
1361 @CREATED    : November 17, 1993 (Peter Neelin)
1362 @MODIFIED   :
1363 ---------------------------------------------------------------------------- */
acr_get_element_long(Acr_Element element)1364 Acr_Long acr_get_element_long(Acr_Element element)
1365 {
1366    Acr_Long value;
1367 
1368    value = (Acr_Long)acr_get_numeric_vr(acr_get_element_vr(element),
1369                                         acr_get_element_byte_order(element),
1370                                         acr_get_element_data(element),
1371                                         acr_get_element_length(element));
1372 
1373    return value;
1374 }
1375 
1376 /* ----------------------------- MNI Header -----------------------------------
1377 @NAME       : acr_get_element_numeric
1378 @INPUT      : element
1379 @OUTPUT     : (none)
1380 @RETURNS    : Value from element structure
1381 @DESCRIPTION: Gets a single ascii numeric from an element structure.
1382               Returns zero if an error occurs.
1383 @METHOD     :
1384 @GLOBALS    :
1385 @CALLS      :
1386 @CREATED    : November 17, 1993 (Peter Neelin)
1387 @MODIFIED   :
1388 ---------------------------------------------------------------------------- */
acr_get_element_numeric(Acr_Element element)1389 double acr_get_element_numeric(Acr_Element element)
1390 {
1391    double value;
1392 
1393    value = acr_get_numeric_vr(acr_get_element_vr(element),
1394                               acr_get_element_byte_order(element),
1395                               acr_get_element_data(element),
1396                               acr_get_element_length(element));
1397 
1398    return value;
1399 }
1400 
1401 /* ----------------------------- MNI Header -----------------------------------
1402 @NAME       : acr_get_element_string
1403 @INPUT      : element
1404 @OUTPUT     : (none)
1405 @RETURNS    : Value from element structure
1406 @DESCRIPTION: Gets an string from an element structure.
1407 @METHOD     :
1408 @GLOBALS    :
1409 @CALLS      :
1410 @CREATED    : November 17, 1993 (Peter Neelin)
1411 @MODIFIED   :
1412 ---------------------------------------------------------------------------- */
acr_get_element_string(Acr_Element element)1413 Acr_String acr_get_element_string(Acr_Element element)
1414 {
1415 
1416    return acr_get_string_vr(acr_get_element_vr(element),
1417                             acr_get_element_byte_order(element),
1418                             acr_get_element_data(element),
1419                             acr_get_element_length(element));
1420 
1421 }
1422 
1423 /* ----------------------------- MNI Header -----------------------------------
1424 @NAME       : acr_get_element_short_array
1425 @INPUT      : element
1426               max_values - maximum number of values to return
1427 @OUTPUT     : values - array of values found
1428 @RETURNS    : Number of values found
1429 @DESCRIPTION: Gets an array of shorts from an element structure. If the
1430               number of values in the element is greater than max_values,
1431               then only max_values values are extracted, but the total
1432               number of values in the element is returned.
1433 @METHOD     :
1434 @GLOBALS    :
1435 @CALLS      :
1436 @CREATED    : February 17, 1997 (Peter Neelin)
1437 @MODIFIED   :
1438 ---------------------------------------------------------------------------- */
acr_get_element_short_array(Acr_Element element,long max_values,Acr_Short values[])1439 long acr_get_element_short_array(Acr_Element element, long max_values,
1440                                  Acr_Short values[])
1441 {
1442    long nvalues;
1443 
1444    /* Check VR of element */
1445    switch (acr_get_element_vr(element)) {
1446    case ACR_VR_SS:
1447    case ACR_VR_US:
1448    case ACR_VR_OW:
1449    case ACR_VR_UNKNOWN:
1450       break;
1451    default:
1452       return (long) 0;
1453    }
1454 
1455    /* Get number of values in element */
1456    nvalues = acr_get_element_length(element) / ACR_SIZEOF_SHORT;
1457 
1458    /* Check the maximum number of values */
1459    if (max_values > nvalues) max_values = nvalues;
1460 
1461    /* Get the data */
1462    acr_get_short(acr_get_element_byte_order(element),
1463                  max_values, acr_get_element_data(element), values);
1464 
1465    /* Return the number of values in the structure */
1466    return nvalues;
1467 }
1468 
1469 /* ----------------------------- MNI Header -----------------------------------
1470 @NAME       : acr_get_element_double_array
1471 @INPUT      : element
1472               max_values - maximum number of values to return
1473 @OUTPUT     : values - array of values found
1474 @RETURNS    : Number of values found
1475 @DESCRIPTION: Gets an array of doubles from an element structure. If the
1476               number of values in the element is greater than max_values,
1477               then only max_values values are extracted, but the total
1478               number of values in the element is returned.
1479 @METHOD     :
1480 @GLOBALS    :
1481 @CALLS      :
1482 @CREATED    : April 8, 2006 (Bert Vincent)
1483 @MODIFIED   :
1484 ---------------------------------------------------------------------------- */
acr_get_element_double_array(Acr_Element element,long max_values,Acr_Double values[])1485 long acr_get_element_double_array(Acr_Element element, long max_values,
1486                                   Acr_Double values[])
1487 {
1488    long nvalues;
1489 
1490    /* Check VR of element */
1491    switch (acr_get_element_vr(element)) {
1492    case ACR_VR_FD:
1493    case ACR_VR_UNKNOWN:
1494       break;
1495    default:
1496       return (long) 0;
1497    }
1498 
1499    /* Get number of values in element */
1500    nvalues = acr_get_element_length(element) / ACR_SIZEOF_DOUBLE;
1501 
1502    /* Check the maximum number of values */
1503    if (max_values > nvalues) max_values = nvalues;
1504 
1505    /* Get the data */
1506    acr_get_double(acr_get_element_byte_order(element),
1507                   max_values, acr_get_element_data(element), values);
1508 
1509    /* Return the number of values in the structure */
1510    return nvalues;
1511 }
1512 
1513 /* ----------------------------- MNI Header -----------------------------------
1514 @NAME       : acr_element_numeric_array_separator
1515 @INPUT      : character - character to add to list or EOF if not adding
1516                  anything
1517 @OUTPUT     : (none)
1518 @RETURNS    : Pointer to array of separators, ending with an EOF
1519 @DESCRIPTION: Adds to the list of separators for a numeric array, or
1520               returns a pointer to the array which is terminated with an EOF.
1521 @METHOD     :
1522 @GLOBALS    :
1523 @CALLS      :
1524 @CREATED    : February 27, 1997 (Peter Neelin)
1525 @MODIFIED   :
1526 ---------------------------------------------------------------------------- */
acr_element_numeric_array_separator(int character)1527 int *acr_element_numeric_array_separator(int character)
1528 {
1529    static int *separator_list = NULL;
1530    static int nseparators = 0;
1531    static int default_list[] = {',', '\\', '/'};
1532    int isep;
1533 
1534    /* Create the default list */
1535    if (separator_list == NULL) {
1536       nseparators = SIZEOF_ARRAY(default_list);
1537       separator_list =
1538          MALLOC((size_t) (nseparators + 1) * sizeof(*separator_list));
1539       for (isep = 0; isep < nseparators; isep++) {
1540          separator_list[isep] = default_list[isep];
1541       }
1542       separator_list[nseparators] = EOF;
1543    }
1544 
1545    /* Add the character to the list if it is not already there */
1546    if (character != EOF) {
1547       for (isep=0; isep < nseparators; isep++) {
1548          if (character == separator_list[isep]) break;
1549       }
1550       if (character != separator_list[isep]) {
1551          nseparators++;
1552          separator_list =
1553             REALLOC(separator_list,
1554                     (size_t) (nseparators + 1) * sizeof(*separator_list));
1555          separator_list[nseparators - 1] = character;
1556          separator_list[nseparators] = EOF;
1557       }
1558    }
1559 
1560    /* Return the list */
1561    return separator_list;
1562 }
1563 
1564 /* ----------------------------- MNI Header -----------------------------------
1565 @NAME       : acr_get_element_numeric_array
1566 @INPUT      : element
1567               max_values - maximum number of values to return
1568 @OUTPUT     : values - array of values found
1569 @RETURNS    : Number of values found
1570 @DESCRIPTION: Gets an array of ascii numbers from an element structure.
1571 @METHOD     :
1572 @GLOBALS    :
1573 @CALLS      :
1574 @CREATED    : November 17, 1993 (Peter Neelin)
1575 @MODIFIED   :
1576 ---------------------------------------------------------------------------- */
acr_get_element_numeric_array(Acr_Element element,int max_values,double values[])1577 int acr_get_element_numeric_array(Acr_Element element,
1578                                   int max_values, double values[])
1579 {
1580    char *start, *end, *cur, *prev;
1581    int *separator_list;
1582    int nvalues, isep;
1583 
1584    /* Get separator list */
1585    separator_list = acr_element_numeric_array_separator(EOF);
1586 
1587    /* Set up pointers to end of string and first non-space character */
1588    start = (char *) acr_get_element_data(element);
1589    end = start + acr_get_element_length(element);
1590    cur = start;
1591    while (isspace((int) *cur)) cur++;
1592    nvalues = 0;
1593 
1594    /* Loop through string looking for numbers */
1595    while (cur<end) {
1596 
1597       /* Get number */
1598       prev = cur;
1599       if (nvalues < max_values) {
1600          values[nvalues] = strtod(prev, &cur);
1601       }
1602       else {
1603          (void) strtod(prev, &cur);
1604       }
1605       if (cur == prev) {
1606          return nvalues;
1607       }
1608       nvalues++;
1609 
1610       /* Skip any spaces */
1611       while (isspace(*cur)) cur++;
1612 
1613       /* Skip an optional separator */
1614       for (isep=0; separator_list[isep] != EOF; isep++) {
1615          if (*cur == separator_list[isep]) {
1616             cur++;
1617             break;
1618          }
1619       }
1620 
1621    }
1622 
1623    return nvalues;
1624 }
1625 
1626 static void
maybe_print_as_string(FILE * file_pointer,Acr_Element cur_element,int element_length,int done_already)1627 maybe_print_as_string(FILE *file_pointer, Acr_Element cur_element,
1628                       int element_length, int done_already)
1629 {
1630     char *string;
1631     char *copy;
1632     int string_length;
1633     int printable = 0;
1634     int i;
1635     int j;
1636 
1637     string = acr_get_element_string(cur_element);
1638     string_length = element_length;
1639     while ((string_length > 0) && (string[string_length-1] == '\0')) {
1640         string_length--;
1641     }
1642 
1643     /* Print string if short enough and is printable */
1644     if (element_length > 0 &&
1645 		  !(acr_get_element_group(cur_element) == 0x7fe0 &&
1646         acr_get_element_element(cur_element) == 0x0010)) {
1647         copy = malloc(string_length + 1);
1648         printable = (string_length > 0);
1649         for (i=0; i < string_length; i++) {
1650             if (! isprint((int) string[i])) {
1651                 printable = FALSE;
1652                 copy[i] = ' ';
1653             }
1654             else if ((string[i] == '\n') ||
1655                      (string[i] == '\r') ||
1656                      (string[i] == '\f'))
1657                 copy[i] = ' ';
1658             else
1659                 copy[i] = string[i];
1660         }
1661         copy[i] = '\0';
1662 
1663         if (printable) {
1664             (void) fprintf(file_pointer, " string = \"%s\"", copy);
1665         }
1666         else if (!done_already) {
1667             /* If unknown length print as a series of bytes.
1668              */
1669             string = acr_get_element_data(cur_element);
1670             fprintf(file_pointer, " byte = ");
1671             if (element_length < 1000) {
1672                 for (i = 0; i < element_length; i++) {
1673                     fprintf(file_pointer, "%#x",
1674                             (unsigned char)string[i]);
1675                     if (i != element_length - 1) {
1676                         fprintf(file_pointer, ", ");
1677                     }
1678                 }
1679             }
1680             else {
1681                 fprintf(file_pointer, "\n");
1682                 for (i = 0; i < element_length; i += 16) {
1683                     for (j = 0; j < 16; j++) {
1684                             if (i + j < element_length) {
1685                                 fprintf(file_pointer, "%02x ",
1686                                         (unsigned char)string[i+j]);
1687                             }
1688                             else {
1689                                 fprintf(file_pointer, "   ");
1690                             }
1691                         }
1692                         fprintf(file_pointer, "| ");
1693                         for (j = 0; j < 16; j++) {
1694                             if (i + j < element_length) {
1695                                 int c = (unsigned char)string[i+j];
1696                                 fprintf(file_pointer, "%c",
1697                                         isprint(c) ? c : '.');
1698                             }
1699                         }
1700                         fprintf(file_pointer, "\n");
1701                     }
1702             }
1703         }
1704         free(copy);
1705     }
1706 }
1707 
1708 /* ----------------------------- MNI Header -----------------------------------
1709 @NAME       : acr_dump_element_list
1710 @INPUT      : file_pointer - where output should go
1711               element_list
1712 @OUTPUT     : (none)
1713 @RETURNS    : (nothing)
1714 @DESCRIPTION: Dump information from an acr-nema element list
1715 @METHOD     :
1716 @GLOBALS    :
1717 @CALLS      :
1718 @CREATED    : February 12, 1997 (Peter Neelin)
1719 @MODIFIED   :
1720 ---------------------------------------------------------------------------- */
acr_dump_element_list(FILE * file_pointer,Acr_Element element_list)1721 void acr_dump_element_list(FILE *file_pointer,
1722                            Acr_Element element_list)
1723 {
1724 #define INDENT_AMOUNT 3
1725    Acr_Element cur_element;
1726    long element_length;
1727    int i;
1728    static int current_indent_level = 0;
1729    Acr_VR_Type vr_code;
1730 
1731    /* Check that we have something to print */
1732    if (element_list == NULL) return;
1733 
1734    /* Increment indent level */
1735    current_indent_level += INDENT_AMOUNT;
1736 
1737    /* Loop over elements */
1738    cur_element = element_list;
1739    while (cur_element != NULL) {
1740 
1741       /* Indent the line */
1742       for (i=0; i < current_indent_level; i++) {
1743          (void) putc((int) ' ', file_pointer);
1744       }
1745 
1746       element_length = acr_get_element_length(cur_element);
1747 
1748       /* Print the element id */
1749       (void) fprintf(file_pointer,
1750                      "0x%04x  0x%04x  length = %d ",
1751                      acr_get_element_group(cur_element),
1752                      acr_get_element_element(cur_element),
1753                      (int) element_length);
1754 
1755       if (_acr_name_proc != NULL) {
1756           char *name_ptr;
1757 
1758           name_ptr = (*_acr_name_proc)(acr_get_element_group(cur_element),
1759                                        acr_get_element_element(cur_element));
1760 
1761           if (name_ptr != NULL) {
1762               fprintf(file_pointer, "(%s)", name_ptr);
1763           }
1764       }
1765       fprintf(file_pointer, ":");
1766 
1767       /* Print value if needed */
1768       vr_code = acr_get_element_vr(cur_element);
1769       if (acr_element_is_sequence(cur_element)) {
1770          (void) fprintf(file_pointer, " VR=%s",
1771                         acr_get_vr_name(vr_code));
1772          if (acr_get_element_data(cur_element) == NULL) {
1773             (void) fprintf(file_pointer, " (empty sequence)");
1774          }
1775          else {
1776             (void) fprintf(file_pointer, " (sequence)");
1777          }
1778          (void) putc((int) '\n', file_pointer);
1779          acr_dump_element_list(file_pointer,
1780             (Acr_Element) acr_get_element_data(cur_element));
1781       }
1782       else if (vr_code != ACR_VR_UNKNOWN) {
1783          (void) fprintf(file_pointer, " VR=%s, ",
1784                         acr_get_vr_name(vr_code));
1785          switch (vr_code) {
1786          case ACR_VR_SS:
1787          case ACR_VR_US:
1788             (void) fprintf(file_pointer, "short = %d (0x%04x)",
1789                            (int) acr_get_element_short(cur_element),
1790                            (int) acr_get_element_short(cur_element));
1791             break;
1792          case ACR_VR_AT:
1793          case ACR_VR_SL:
1794          case ACR_VR_UL:
1795             (void) fprintf(file_pointer, "long = %d (0x%08x)",
1796                            (int) acr_get_element_long(cur_element),
1797                            (int) acr_get_element_long(cur_element));
1798             break;
1799          case ACR_VR_OB:
1800          case ACR_VR_OW:
1801             maybe_print_as_string(file_pointer, cur_element,
1802                                   element_length, 0);
1803             break;
1804          default:
1805             (void) fprintf(file_pointer, "value = \"%s\"",
1806                            acr_get_element_string(cur_element));
1807             break;
1808          }
1809          (void) putc((int) '\n', file_pointer);
1810       }
1811       else {
1812          int done_already = 0;
1813 
1814          switch (element_length) {
1815          case ACR_SIZEOF_SHORT:
1816             (void) fprintf(file_pointer, " short = %d (0x%04x)",
1817                            (int) acr_get_element_short(cur_element),
1818                            (int) acr_get_element_short(cur_element));
1819             done_already = 1;
1820             break;
1821          case ACR_SIZEOF_LONG:
1822             (void) fprintf(file_pointer, " long = %d (0x%08x)",
1823                            (int) acr_get_element_long(cur_element),
1824                            (int) acr_get_element_long(cur_element));
1825             done_already = 1;
1826             break;
1827          }
1828 
1829          maybe_print_as_string(file_pointer, cur_element, element_length,
1830                                done_already);
1831 
1832          /* End line */
1833          (void) fprintf(file_pointer, "\n");
1834 
1835       }         /* if is_sequence ... else  */
1836 
1837       cur_element = acr_get_element_next(cur_element);
1838    }
1839 
1840    /* Decrement indent level */
1841    current_indent_level -= INDENT_AMOUNT;
1842 
1843 }
1844