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