1 /* ----------------------------- MNI Header -----------------------------------
2 @NAME       : group.c
3 @DESCRIPTION: Routines for doing acr_nema group operations.
4 @METHOD     :
5 @GLOBALS    :
6 @CREATED    : November 10, 1993 (Peter Neelin)
7 @MODIFIED   :
8  * $Log: group.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/04/09 15:29:43  bert
13  * Add acr_insert_double()
14  *
15  * Revision 6.10  2005/05/09 15:34:46  bert
16  * For acr_find_{short,int,long,double}, treat a zero-length element as if it were absent, and return the default value.
17  *
18  * Revision 6.9  2005/03/11 22:05:29  bert
19  * Implement _acr_name_proc to allow printing of field names in dump_acr_nema
20  *
21  * Revision 6.8  2005/03/04 17:09:11  bert
22  * Change several functions to return Acr_Status instead of void; lose public and private; Make insert_element() check the return value of acr_get_element_total_length()
23  *
24  * Revision 6.7  2004/10/29 13:08:42  rotor
25  *  * rewrote Makefile with no dependency on a minc distribution
26  *  * removed all references to the abominable minc_def.h
27  *  * I should autoconf this really, but this is old code that
28  *      is now replaced by Jon Harlaps PERL version..
29  *
30  * Revision 6.6  2002/12/08 22:31:34  neelin
31  * When a last fragment is received, the dicom watchpoint is only updated when the next read happens, so the peek ahead will fail after the watchpoint test in acr_input_group_with_max.
32  *
33  * Revision 6.5  2001/11/08 14:17:05  neelin
34  * Added acr_test_dicom_file to allow reading of DICOM part 10 format
35  * files. This function also calls acr_test_byte_order to set up the stream
36  * properly and can be used as a direct replacement for that function.
37  * This set of changes does NOT include the ability to write part 10 files.
38  *
39  * Revision 6.4  2000/05/01 17:18:07  neelin
40  * Modifications tohandle end-of-input properly, both on first group
41  * read, and when ignoring protocol errors.
42  *
43  * Revision 6.3  2000/04/28 15:03:11  neelin
44  * Added support for ignoring non-fatal protocol errors (cases where redundant
45  * information is inconsistent). In particular, it is possible to ignore
46  * differences between the group length element and the true group length.
47  *
48  * Revision 6.2  1999/10/29 17:51:53  neelin
49  * Fixed Log keyword
50  *
51  * Revision 6.1  1998/11/06 19:41:06  neelin
52  * Added functions acr_group_steal_element and acr_find_group.
53  *
54  * Revision 6.0  1997/09/12  13:23:59  neelin
55  * Release of minc version 0.6
56  *
57  * Revision 5.0  1997/08/21  13:25:00  neelin
58  * Release of minc version 0.5
59  *
60  * Revision 4.2  1997/08/21  13:24:55  neelin
61  * Pre-release
62  *
63  * Revision 4.1  1997/06/17  23:49:08  neelin
64  * Added routines for inserting elements into a group list.
65  *
66  * Revision 4.0  1997/05/07  20:01:23  neelin
67  * Release of minc version 0.4
68  *
69  * Revision 3.1  1997/04/21  20:21:09  neelin
70  * Updated the library to handle dicom messages.
71  *
72  * Revision 3.0  1995/05/15  19:32:12  neelin
73  * Release of minc version 0.3
74  *
75  * Revision 2.2  1995/02/08  21:16:06  neelin
76  * Changes to make irix 5 lint happy.
77  *
78  * Revision 2.1  1995/01/04  08:10:16  neelin
79  * Improved string printing in dump function (longer strings and replace
80  * carriage returns, linefeeds and formfeeds by spaces).
81  *
82  * Revision 2.0  94/09/28  10:36:16  neelin
83  * Release of minc version 0.2
84  *
85  * Revision 1.11  94/09/28  10:35:45  neelin
86  * Pre-release
87  *
88  * Revision 1.10  94/04/07  10:05:04  neelin
89  * Added status ACR_ABNORMAL_END_OF_INPUT and changed some ACR_PROTOCOL_ERRORs
90  * to that or ACR_OTHER_ERROR.
91  * Added #ifdef lint to DEFINE_ELEMENT.
92  *
93  * Revision 1.9  93/12/10  09:20:32  neelin
94  * Added acr_find_<type> routines.
95  *
96  * Revision 1.8  93/12/08  09:04:59  neelin
97  * Fixed memory leak in acr_input_group_with_max.
98  * Fixed acr_input_group_list (didn't stop reading when reached max group).
99  *
100  * Revision 1.7  93/11/30  08:57:42  neelin
101  * Added group and group list copy routines.
102  *
103  * Revision 1.6  93/11/26  18:47:51  neelin
104  * Added group and group list copy routines.
105  *
106  * Revision 1.5  93/11/25  10:36:57  neelin
107  * Fixed input_group_list (wasn't checking max properly).
108  *
109  * Revision 1.4  93/11/24  12:05:12  neelin
110  * Changed format of dump.
111  *
112  * Revision 1.3  93/11/24  11:25:38  neelin
113  * Added some group list stuff (dump, input_group_list).
114  *
115  * Revision 1.2  93/11/22  13:11:58  neelin
116  * Changed to use new Acr_Element_Id stuff
117  *
118  * Revision 1.1  93/11/19  12:48:52  neelin
119  * Initial revision
120  *
121 @COPYRIGHT  :
122               Copyright 1993 Peter Neelin, McConnell Brain Imaging Centre,
123               Montreal Neurological Institute, McGill University.
124               Permission to use, copy, modify, and distribute this
125               software and its documentation for any purpose and without
126               fee is hereby granted, provided that the above copyright
127               notice appear in all copies.  The author and McGill University
128               make no representations about the suitability of this
129               software for any purpose.  It is provided "as is" without
130               express or implied warranty.
131 ---------------------------------------------------------------------------- */
132 
133 #include <stdlib.h>
134 #include <stdio.h>
135 #include <ctype.h>
136 #include <string.h>
137 #include <acr_nema.h>
138 
139 /* Private functions */
140 static void steal_element(Acr_Group group, Acr_Element element,
141                           Acr_Element previous);
142 static void remove_element(Acr_Group group, Acr_Element element,
143                            Acr_Element previous);
144 static Acr_Status insert_element(Acr_Group group, Acr_Element element,
145                                  Acr_Element previous);
146 static void update_group_length_element(Acr_Group group,
147                                         Acr_VR_encoding_type vr_encoding);
148 static Acr_Status acr_input_group_with_max(Acr_File *afp, Acr_Group *group,
149                                            int max_group_id);
150 
151 acr_name_proc_t _acr_name_proc = NULL;
152 
153 
154 /* ----------------------------- MNI Header -----------------------------------
155 @NAME       : acr_create_group
156 @INPUT      : group_id
157 @OUTPUT     : (none)
158 @RETURNS    : Pointer to group structure
159 @DESCRIPTION: Creates an acr-nema group structure
160 @METHOD     :
161 @GLOBALS    :
162 @CALLS      :
163 @CREATED    : November 10, 1993 (Peter Neelin)
164 @MODIFIED   : February 4, 1997 (P.N.)
165 ---------------------------------------------------------------------------- */
acr_create_group(int group_id)166 Acr_Group acr_create_group(int group_id)
167 {
168    Acr_Group group;
169    Acr_Element length_element;
170    long group_length = 0;
171 
172    /* Allocate the group */
173    group = MALLOC(sizeof(*group));
174 
175    /* Create a length element */
176    group_length = 0;
177    length_element =
178       acr_create_element(group_id, ACR_EID_GRPLEN, ACR_VR_UL,
179                          (long) ACR_SIZEOF_LONG,
180                          acr_memdup((size_t) ACR_SIZEOF_LONG, &group_length));
181 
182    /* Assign fields */
183    group->group_id = group_id;
184    group->nelements = 1;
185    group->implicit_total_length =
186       acr_get_element_total_length(length_element, ACR_IMPLICIT_VR);
187    group->explicit_total_length =
188       acr_get_element_total_length(length_element, ACR_EXPLICIT_VR);
189    group->list_head = length_element;
190    group->list_tail = length_element;
191    group->next = NULL;
192 
193    return group;
194 }
195 
196 /* ----------------------------- MNI Header -----------------------------------
197 @NAME       : acr_delete_group
198 @INPUT      : group
199 @OUTPUT     : (none)
200 @RETURNS    : (nothing)
201 @DESCRIPTION: Deletes an acr-nema group structure (freeing the element list)
202 @METHOD     :
203 @GLOBALS    :
204 @CALLS      :
205 @CREATED    : November 10, 1993 (Peter Neelin)
206 @MODIFIED   :
207 ---------------------------------------------------------------------------- */
acr_delete_group(Acr_Group group)208 void acr_delete_group(Acr_Group group)
209 {
210    acr_delete_element_list(group->list_head);
211 
212    FREE(group);
213 
214    return;
215 }
216 
217 /* ----------------------------- MNI Header -----------------------------------
218 @NAME       : acr_delete_group_list
219 @INPUT      : group_list
220 @OUTPUT     : (none)
221 @RETURNS    : (nothing)
222 @DESCRIPTION: Delete a list of acr-nema group
223 @METHOD     :
224 @GLOBALS    :
225 @CALLS      :
226 @CREATED    : November 10, 1993 (Peter Neelin)
227 @MODIFIED   :
228 ---------------------------------------------------------------------------- */
acr_delete_group_list(Acr_Group group_list)229 void acr_delete_group_list(Acr_Group group_list)
230 {
231    Acr_Group next, cur;
232 
233    /* Check for null group */
234    if (group_list == NULL) return;
235 
236    /* Loop through the list, deleting groups */
237    next = group_list;
238    do {
239       cur = next;
240       next = cur->next;
241       acr_delete_group(cur);
242    } while (next != NULL);
243 
244    return;
245 }
246 
247 /* ----------------------------- MNI Header -----------------------------------
248 @NAME       : acr_copy_group
249 @INPUT      : group
250 @OUTPUT     : (none)
251 @RETURNS    : (nothing)
252 @DESCRIPTION: Makes a copy of an acr-nema group structure
253 @METHOD     :
254 @GLOBALS    :
255 @CALLS      :
256 @CREATED    : November 26, 1993 (Peter Neelin)
257 @MODIFIED   :
258 ---------------------------------------------------------------------------- */
acr_copy_group(Acr_Group group)259 Acr_Group acr_copy_group(Acr_Group group)
260 {
261    Acr_Group copy;
262    Acr_Element cur;
263 
264    /* Create the group */
265    copy = acr_create_group(acr_get_group_group(group));
266 
267    /* Get the second element (first element is always there) */
268    cur = acr_get_element_next(group->list_head);
269    while (cur != NULL) {
270       acr_group_add_element(copy, acr_copy_element(cur));
271       cur = acr_get_element_next(cur);
272    }
273 
274    return copy;
275 }
276 
277 /* ----------------------------- MNI Header -----------------------------------
278 @NAME       : acr_copy_group_list
279 @INPUT      : group_list
280 @OUTPUT     : (none)
281 @RETURNS    : (nothing)
282 @DESCRIPTION: Make a copy of a group list
283 @METHOD     :
284 @GLOBALS    :
285 @CALLS      :
286 @CREATED    : November 26, 1993 (Peter Neelin)
287 @MODIFIED   :
288 ---------------------------------------------------------------------------- */
acr_copy_group_list(Acr_Group group_list)289 Acr_Group acr_copy_group_list(Acr_Group group_list)
290 {
291    Acr_Group copy_list;
292    Acr_Group copy_group;
293    Acr_Group cur;
294 
295    /* Create first group */
296    copy_list = copy_group = acr_copy_group(group_list);
297 
298    /* Loop through groups */
299    cur = acr_get_group_next(group_list);
300    while (cur != NULL) {
301       acr_set_group_next(copy_group, acr_copy_group(cur));
302       copy_group = acr_get_group_next(copy_group);
303       cur = acr_get_group_next(cur);
304    }
305 
306    return copy_list;
307 
308 }
309 
310 /* ----------------------------- MNI Header -----------------------------------
311 @NAME       : steal_element
312 @INPUT      : group
313               element - element to remove
314               previous - pointer to previous element or NULL if beginning
315                  of group element list
316 @OUTPUT     : (none)
317 @RETURNS    : (nothing)
318 @DESCRIPTION: Steal an element from a group (remove it without deleting it).
319               The caller must free the element themselves.
320 @METHOD     :
321 @GLOBALS    :
322 @CALLS      :
323 @CREATED    : November 6, 1998 (Peter Neelin)
324 @MODIFIED   :
325 ---------------------------------------------------------------------------- */
steal_element(Acr_Group group,Acr_Element element,Acr_Element previous)326 static void steal_element(Acr_Group group, Acr_Element element,
327                           Acr_Element previous)
328 {
329    Acr_Element next;
330 
331    /* Get pointer to next element */
332    next = acr_get_element_next(element);
333 
334    /* Update the previous element or list head */
335    if (previous != NULL)
336       acr_set_element_next(previous, next);
337    else
338       group->list_head = next;
339 
340    /* Check for an element at the tail */
341    if (next == NULL)
342       group->list_tail = previous;
343 
344    /* Update the group fields */
345    group->nelements--;
346    group->implicit_total_length -=
347       acr_get_element_total_length(element, ACR_IMPLICIT_VR);
348    group->explicit_total_length -=
349       acr_get_element_total_length(element, ACR_EXPLICIT_VR);
350 
351    /* Update the group length element */
352    update_group_length_element(group,
353                                acr_get_element_vr_encoding(group->list_head));
354 
355 }
356 
357 /* ----------------------------- MNI Header -----------------------------------
358 @NAME       : remove_element
359 @INPUT      : group
360               element - element to remove
361               previous - pointer to previous element or NULL if beginning
362                  of group element list
363 @OUTPUT     : (none)
364 @RETURNS    : (nothing)
365 @DESCRIPTION: Remove an element from a group.
366 @METHOD     :
367 @GLOBALS    :
368 @CALLS      :
369 @CREATED    : June 17, 1997 (Peter Neelin)
370 @MODIFIED   :
371 ---------------------------------------------------------------------------- */
remove_element(Acr_Group group,Acr_Element element,Acr_Element previous)372 static void remove_element(Acr_Group group, Acr_Element element,
373                            Acr_Element previous)
374 {
375 
376    /* Get rid of the old element from the group */
377    steal_element(group, element, previous);
378 
379    /* Delete the old element */
380    acr_delete_element(element);
381 
382 }
383 
384 /* ----------------------------- MNI Header -----------------------------------
385 @NAME       : insert_element
386 @INPUT      : group
387               element - element to insert
388               previous - pointer to previous element or NULL if beginning
389                  of group element list
390 @OUTPUT     : (none)
391 @RETURNS    : Acr_Status
392 @DESCRIPTION: Insert an element into a group.
393 @METHOD     :
394 @GLOBALS    :
395 @CALLS      :
396 @CREATED    : June 17, 1997 (Peter Neelin)
397 @MODIFIED   :
398 ---------------------------------------------------------------------------- */
insert_element(Acr_Group group,Acr_Element element,Acr_Element previous)399 static Acr_Status insert_element(Acr_Group group, Acr_Element element,
400                                  Acr_Element previous)
401 {
402    Acr_Element next;
403    long length;
404 
405    /* Update the pointers */
406    if (previous != NULL) {        /* Middle or tail of list */
407       next = acr_get_element_next(previous);
408       acr_set_element_next(previous, element);
409    }
410    else {                         /* Head of list */
411       next = group->list_head;
412       group->list_head = element;
413    }
414    acr_set_element_next(element, next);
415 
416    /* Check for the tail */
417    if (next == NULL) {
418       group->list_tail = element;
419    }
420 
421    /* Update the group fields */
422    group->nelements++;
423    length = acr_get_element_total_length(element, ACR_IMPLICIT_VR);
424    if (length <= 0) {
425       return (ACR_OTHER_ERROR);
426    }
427    group->implicit_total_length += length;
428 
429    length = acr_get_element_total_length(element, ACR_EXPLICIT_VR);
430    if (length <= 0) {
431       return (ACR_OTHER_ERROR);
432    }
433    group->explicit_total_length += length;
434 
435 
436    /* Update the length element */
437    update_group_length_element(group,
438                                acr_get_element_vr_encoding(group->list_head));
439    return (ACR_OK);
440 }
441 
442 /* ----------------------------- MNI Header -----------------------------------
443 @NAME       : acr_group_insert_element
444 @INPUT      : group
445               element
446 @OUTPUT     : (none)
447 @RETURNS    : Acr_Status
448 @DESCRIPTION: Insert an element into a group. If an element of the same
449               id already exists in the list, it is removed and deleted.
450 @METHOD     :
451 @GLOBALS    :
452 @CALLS      :
453 @CREATED    : June 17, 1997 (Peter Neelin)
454 @MODIFIED   :
455 ---------------------------------------------------------------------------- */
acr_group_insert_element(Acr_Group group,Acr_Element element)456 Acr_Status acr_group_insert_element(Acr_Group group,
457                                     Acr_Element element)
458 {
459    Acr_Element next_element, prev_element, cur_element;
460    int element_id;
461 
462    /* Check that the element belongs in this group */
463    if (group->group_id != acr_get_element_group(element)) {
464       (void) fprintf(stderr,
465           "ACR error: Cannot add element %d (group %d) to group %d\n",
466                      acr_get_element_element(element),
467                      acr_get_element_group(element),
468                      group->group_id);
469       exit(EXIT_FAILURE);
470    }
471 
472    /* Get element id */
473    element_id = acr_get_element_element(element);
474 
475    /* Check that new element has id > group length element id */
476    if (element_id < ACR_EID_GRPLEN) {
477       (void) fprintf(stderr,
478       "ACR error: Cannot add element id %d <= length id (%d) to group %d\n",
479                      element_id, ACR_EID_GRPLEN, group->group_id);
480       exit(EXIT_FAILURE);
481    }
482 
483    /* Check whether the the element should be added after the last element */
484    if (acr_get_element_element(group->list_tail) < element_id) {
485       prev_element = group->list_tail;
486       next_element = NULL;
487    }
488 
489    /* Otherwise, search for the appropriate location */
490    else {
491       prev_element = NULL;
492       next_element = group->list_head;
493       while ((next_element != NULL) &&
494              (acr_get_element_element(next_element) < element_id)) {
495          prev_element = next_element;
496          next_element = acr_get_element_next(next_element);
497       }
498    }
499 
500    /* Check for an existing element and get rid of it */
501    if ((next_element != NULL) &&
502        (acr_get_element_element(next_element) == element_id)) {
503 
504       /* Set pointers and get rid of the old element */
505       cur_element = next_element;
506       next_element = acr_get_element_next(cur_element);
507       remove_element(group, cur_element, prev_element);
508 
509    }
510 
511    /* Insert the new element */
512    return insert_element(group, element, prev_element);
513 
514 }
515 
516 /* ----------------------------- MNI Header -----------------------------------
517 @NAME       : acr_group_add_element
518 @INPUT      : group
519               element
520 @OUTPUT     : (none)
521 @RETURNS    : Acr_Status
522 @DESCRIPTION: Add an element to an acr-nema group
523 @METHOD     :
524 @GLOBALS    :
525 @CALLS      :
526 @CREATED    : November 10, 1993 (Peter Neelin)
527 @MODIFIED   :
528 ---------------------------------------------------------------------------- */
acr_group_add_element(Acr_Group group,Acr_Element element)529 Acr_Status acr_group_add_element(Acr_Group group, Acr_Element element)
530 {
531    /* Check that the element belongs in this group */
532    if (group->group_id != acr_get_element_group(element)) {
533       (void) fprintf(stderr,
534           "ACR error: Cannot add element %d (group %d) to group %d\n",
535                      acr_get_element_element(element),
536                      acr_get_element_group(element),
537                      group->group_id);
538       exit(EXIT_FAILURE);
539    }
540 
541    /* Insert the element at the tail */
542    return insert_element(group, element, group->list_tail);
543 }
544 
545 /* ----------------------------- MNI Header -----------------------------------
546 @NAME       : acr_group_remove_element
547 @INPUT      : group
548               element_id
549 @OUTPUT     : (none)
550 @RETURNS    : (nothing)
551 @DESCRIPTION: Remove an element from a group.
552 @METHOD     :
553 @GLOBALS    :
554 @CALLS      :
555 @CREATED    : June 17, 1997 (Peter Neelin)
556 @MODIFIED   :
557 ---------------------------------------------------------------------------- */
acr_group_remove_element(Acr_Group group,int element_id)558 void acr_group_remove_element(Acr_Group group, int element_id)
559 {
560    Acr_Element next_element, prev_element;
561 
562    /* Search for the appropriate location */
563    prev_element = NULL;
564    next_element = group->list_head;
565    while ((next_element != NULL) &&
566           (acr_get_element_element(next_element) != element_id)) {
567       prev_element = next_element;
568       next_element = acr_get_element_next(next_element);
569    }
570 
571    /* Check for an existing element and get rid of it */
572    if ((next_element != NULL) &&
573        (acr_get_element_element(next_element) == element_id)) {
574 
575       /* Set pointers and get rid of the old element */
576       remove_element(group, next_element, prev_element);
577 
578    }
579 
580 }
581 
582 /* ----------------------------- MNI Header -----------------------------------
583 @NAME       : acr_group_steal_element
584 @INPUT      : group
585               element - the caller must pass an element so that we
586                  know that they have a handle to it.
587 @OUTPUT     : (none)
588 @RETURNS    : (nothing)
589 @DESCRIPTION: Remove an element from a group without deleting it.
590 @METHOD     :
591 @GLOBALS    :
592 @CALLS      :
593 @CREATED    : November 6, 1998 (Peter Neelin)
594 @MODIFIED   :
595 ---------------------------------------------------------------------------- */
acr_group_steal_element(Acr_Group group,Acr_Element element)596 void acr_group_steal_element(Acr_Group group, Acr_Element element)
597 {
598    int element_id;
599    Acr_Element next_element, prev_element;
600 
601    /* Get element id from element */
602    element_id = acr_get_element_element(element);
603 
604    /* Search for the appropriate location */
605    prev_element = NULL;
606    next_element = group->list_head;
607    while ((next_element != NULL) &&
608           (acr_get_element_element(next_element) != element_id)) {
609       prev_element = next_element;
610       next_element = acr_get_element_next(next_element);
611    }
612 
613    /* Check for an existing element and get rid of it */
614    if ((next_element != NULL) &&
615        (acr_get_element_element(next_element) == element_id)) {
616 
617       /* Set pointers and get rid of the old element */
618       steal_element(group, next_element, prev_element);
619 
620    }
621 
622 }
623 
624 /* ----------------------------- MNI Header -----------------------------------
625 @NAME       : update_group_length_element
626 @INPUT      : group
627               vr_encoding - ACR_IMPLICIT_VR or ACR_EXPLICIT_VR
628 @OUTPUT     : (none)
629 @RETURNS    : (nothing)
630 @DESCRIPTION: Update the length element of the group according to the VR type
631 @METHOD     :
632 @GLOBALS    :
633 @CALLS      :
634 @CREATED    : February 14, 1997 (Peter Neelin)
635 @MODIFIED   :
636 ---------------------------------------------------------------------------- */
update_group_length_element(Acr_Group group,Acr_VR_encoding_type vr_encoding)637 static void update_group_length_element(Acr_Group group,
638                                         Acr_VR_encoding_type vr_encoding)
639 {
640    Acr_Long group_length;
641    Acr_Element length_element;
642    void *group_length_data;
643 
644    /* Get the element */
645    length_element = group->list_head;
646    if (length_element == NULL) return;
647    if (acr_get_element_element(length_element) != ACR_EID_GRPLEN) return;
648 
649    /* Calculate the appropriate length */
650    if (vr_encoding == ACR_IMPLICIT_VR) {
651       group_length = group->implicit_total_length -
652          acr_get_element_total_length(length_element, ACR_IMPLICIT_VR);
653    }
654    else {
655       group_length = group->explicit_total_length -
656          acr_get_element_total_length(length_element, ACR_EXPLICIT_VR);
657    }
658 
659    /* Update the element */
660    group_length_data = acr_get_element_data(length_element);
661    acr_put_long(acr_get_element_byte_order(length_element),
662                 1, &group_length, group_length_data);
663 
664 }
665 
666 /* ----------------------------- MNI Header -----------------------------------
667 @NAME       : acr_set_group_next
668 @INPUT      : group
669               next
670 @OUTPUT     : (none)
671 @RETURNS    : (nothing)
672 @DESCRIPTION: Set pointer to next group for an acr-nema group
673 @METHOD     :
674 @GLOBALS    :
675 @CALLS      :
676 @CREATED    : November 10, 1993 (Peter Neelin)
677 @MODIFIED   :
678 ---------------------------------------------------------------------------- */
acr_set_group_next(Acr_Group group,Acr_Group next)679 void acr_set_group_next(Acr_Group group, Acr_Group next)
680 {
681    group->next = next;
682    return;
683 }
684 
685 /* ----------------------------- MNI Header -----------------------------------
686 @NAME       : acr_get_group_group
687 @INPUT      : group
688 @OUTPUT     : (none)
689 @RETURNS    : group id
690 @DESCRIPTION: Get group id for group
691 @METHOD     :
692 @GLOBALS    :
693 @CALLS      :
694 @CREATED    : November 10, 1993 (Peter Neelin)
695 @MODIFIED   :
696 ---------------------------------------------------------------------------- */
acr_get_group_group(Acr_Group group)697 int acr_get_group_group(Acr_Group group)
698 {
699    return group->group_id;
700 }
701 
702 /* ----------------------------- MNI Header -----------------------------------
703 @NAME       : acr_get_group_element_list
704 @INPUT      : group
705 @OUTPUT     : (none)
706 @RETURNS    : element list
707 @DESCRIPTION: Get element list for group
708 @METHOD     :
709 @GLOBALS    :
710 @CALLS      :
711 @CREATED    : November 10, 1993 (Peter Neelin)
712 @MODIFIED   :
713 ---------------------------------------------------------------------------- */
acr_get_group_element_list(Acr_Group group)714 Acr_Element acr_get_group_element_list(Acr_Group group)
715 {
716    return group->list_head;
717 }
718 
719 /* ----------------------------- MNI Header -----------------------------------
720 @NAME       : acr_get_group_total_length
721 @INPUT      : group
722               vr_encoding - ACR_EXPLICIT_VR or ACR_IMPLICIT_VR
723 @OUTPUT     : (none)
724 @RETURNS    : total length of group
725 @DESCRIPTION: Get total length of group
726 @METHOD     :
727 @GLOBALS    :
728 @CALLS      :
729 @CREATED    : November 10, 1993 (Peter Neelin)
730 @MODIFIED   :
731 ---------------------------------------------------------------------------- */
acr_get_group_total_length(Acr_Group group,Acr_VR_encoding_type vr_encoding)732 long acr_get_group_total_length(Acr_Group group,
733                                 Acr_VR_encoding_type vr_encoding)
734 {
735    if (vr_encoding == ACR_IMPLICIT_VR)
736       return group->implicit_total_length;
737    else
738       return group->explicit_total_length;
739 }
740 
741 /* ----------------------------- MNI Header -----------------------------------
742 @NAME       : acr_get_group_nelements
743 @INPUT      : group
744 @OUTPUT     : (none)
745 @RETURNS    : number of elements in group
746 @DESCRIPTION: Get number of elements in group
747 @METHOD     :
748 @GLOBALS    :
749 @CALLS      :
750 @CREATED    : November 10, 1993 (Peter Neelin)
751 @MODIFIED   :
752 ---------------------------------------------------------------------------- */
acr_get_group_nelements(Acr_Group group)753 int acr_get_group_nelements(Acr_Group group)
754 {
755    return group->nelements;
756 }
757 
758 /* ----------------------------- MNI Header -----------------------------------
759 @NAME       : acr_get_group_next
760 @INPUT      : group
761 @OUTPUT     : (none)
762 @RETURNS    : next group
763 @DESCRIPTION: Get next group for group
764 @METHOD     :
765 @GLOBALS    :
766 @CALLS      :
767 @CREATED    : November 10, 1993 (Peter Neelin)
768 @MODIFIED   :
769 ---------------------------------------------------------------------------- */
acr_get_group_next(Acr_Group group)770 Acr_Group acr_get_group_next(Acr_Group group)
771 {
772    return group->next;
773 }
774 
775 /* ----------------------------- MNI Header -----------------------------------
776 @NAME       : acr_input_group_with_max
777 @INPUT      : afp - acr file pointer
778               max_group_id - maximum group id to read in. If <= 0 then any
779                  group is read in.
780 @OUTPUT     : group
781 @RETURNS    : status
782 @DESCRIPTION: Read in an acr-nema group with an optional maximum group id.
783               If group id exceeds max, then *group is set to NULL. If an
784               error occurs, then a group may still be returned. This routine
785               will stop reading when it reaches a watchpoint.
786 @METHOD     :
787 @GLOBALS    :
788 @CALLS      :
789 @CREATED    : November 10, 1993 (Peter Neelin)
790 @MODIFIED   :
791 ---------------------------------------------------------------------------- */
acr_input_group_with_max(Acr_File * afp,Acr_Group * group,int max_group_id)792 static Acr_Status acr_input_group_with_max(Acr_File *afp, Acr_Group *group,
793                                            int max_group_id)
794 {
795    int group_id, element_id, next_group_id;
796    long group_length;
797    Acr_Status status;
798    Acr_Element element;
799    int have_length_element;
800    int get_more_elements;
801    Acr_VR_encoding_type vr_encoding;
802 
803    /* Initialize the group pointer */
804    *group = NULL;
805 
806    /* Look ahead at the next element */
807    status = acr_peek_at_next_element_id(afp, &group_id, &element_id);
808    if (status != ACR_OK) return status;
809 
810    /* Check for a group past the limit */
811    if ((max_group_id > 0) && (group_id > max_group_id)) {
812       return status;
813    }
814 
815    /* Check for a length element */
816    have_length_element = (element_id == ACR_EID_GRPLEN);
817 
818    /* Read the length element and check it */
819    if (have_length_element) {
820       status = acr_input_element(afp, &element);
821       if (status != ACR_OK) {
822          acr_delete_element(element);
823          return status;
824       }
825       if ((acr_get_element_element(element) != ACR_EID_GRPLEN) ||
826            (acr_get_element_length(element) != ACR_SIZEOF_LONG)) {
827          if (acr_ignore_protocol_errors(afp)) {
828             group_length = 0;
829          }
830          else {
831             acr_delete_element(element);
832             status = ACR_PROTOCOL_ERROR;
833             return status;
834          }
835       }
836       else {
837          group_length = acr_get_element_long(element);
838       }
839       acr_delete_element(element);
840    }
841 
842    /* Create the group */
843    *group = acr_create_group(group_id);
844 
845    /* Set the VR encoding and the byte ordering for the length element
846       according to the input stream. If the vr_encoding is implicit, then
847       make the VR unknown. Note that the group will always have a length
848       element even if the input stream does not. */
849    element = acr_get_group_element_list(*group);
850    vr_encoding = acr_get_vr_encoding(afp);
851    acr_set_element_vr_encoding(element, vr_encoding);
852    acr_set_element_byte_order(element, acr_get_byte_order(afp));
853    if (vr_encoding == ACR_IMPLICIT_VR) {
854       acr_set_element_vr(element, ACR_VR_UNKNOWN);
855    }
856 
857    /* Loop through elements, adding them to the list */
858    get_more_elements = (have_length_element ? (group_length > 0) : TRUE);
859    while (get_more_elements) {
860 
861       /* Check for a watchpoint */
862       if (acr_get_io_watchpoint(afp) <= 0) {
863          get_more_elements = FALSE;
864          break;
865       }
866 
867       /* Look ahead at next element */
868       status = acr_peek_at_next_element_id(afp, &next_group_id, &element_id);
869       if ((status != ACR_OK) || (next_group_id != group_id)) {
870          if ( status == ACR_REACHED_WATCHPOINT )
871             status = ACR_OK;
872          get_more_elements = FALSE;
873          break;
874       }
875 
876       /* Read in the next element */
877       status = acr_input_element(afp, &element);
878       if (status != ACR_OK) {
879          get_more_elements = FALSE;
880       }
881 
882       /* Add it to the group */
883       if (element != NULL) {
884          acr_group_add_element(*group, element);
885          if (have_length_element) {
886             group_length -=
887                acr_get_element_total_length(element, acr_get_vr_encoding(afp));
888          }
889       }
890 
891       /* Check group length */
892       if (have_length_element && !acr_ignore_protocol_errors(afp)) {
893          get_more_elements = (group_length > 0);
894       }
895 
896    }
897 
898    /* Check that we got a full group */
899    if (have_length_element && (group_length != 0) &&
900        !acr_ignore_protocol_errors(afp)) {
901       switch (status) {
902       case ACR_OK:
903          status = ACR_PROTOCOL_ERROR;
904          break;
905       case ACR_END_OF_INPUT:
906          status = ACR_ABNORMAL_END_OF_INPUT;
907          break;
908       }
909    }
910 
911    return status;
912 }
913 
914 /* ----------------------------- MNI Header -----------------------------------
915 @NAME       : acr_input_group
916 @INPUT      : afp - acr file pointer
917 @OUTPUT     : group
918 @RETURNS    : status
919 @DESCRIPTION: Read in an acr-nema group
920 @METHOD     :
921 @GLOBALS    :
922 @CALLS      :
923 @CREATED    : November 10, 1993 (Peter Neelin)
924 @MODIFIED   :
925 ---------------------------------------------------------------------------- */
acr_input_group(Acr_File * afp,Acr_Group * group)926 Acr_Status acr_input_group(Acr_File *afp, Acr_Group *group)
927 {
928 
929    return acr_input_group_with_max(afp, group, 0);
930 
931 }
932 
933 /* ----------------------------- MNI Header -----------------------------------
934 @NAME       : acr_output_group
935 @INPUT      : afp - acr file pointer
936               group
937 @OUTPUT     : (none)
938 @RETURNS    : status
939 @DESCRIPTION: Write out an acr-nema group
940 @METHOD     :
941 @GLOBALS    :
942 @CALLS      :
943 @CREATED    : November 10, 1993 (Peter Neelin)
944 @MODIFIED   :
945 ---------------------------------------------------------------------------- */
acr_output_group(Acr_File * afp,Acr_Group group)946 Acr_Status acr_output_group(Acr_File *afp, Acr_Group group)
947 {
948    long ielement, nelements;
949    Acr_Element cur, next;
950    Acr_Status status;
951 
952    /* Update the length element */
953    update_group_length_element(group, acr_get_vr_encoding(afp));
954 
955    /* Loop through the elements of the group, writing them out */
956    nelements = acr_get_group_nelements(group);
957    next = acr_get_group_element_list(group);
958    for (ielement=0; ielement < nelements && next != NULL; ielement++) {
959       cur = next;
960       next = cur->next;
961       status = acr_output_element(afp, cur);
962       if (status != ACR_OK) {
963          return status;
964       }
965    }
966 
967    /* Check for a bogus group (the true number of elements is different from
968       nelements) */
969    if ((ielement < nelements) || (next != NULL)) {
970       status = ACR_OTHER_ERROR;
971       return status;
972    }
973 
974    return status;
975 
976 }
977 
978 /* ----------------------------- MNI Header -----------------------------------
979 @NAME       : acr_input_group_list
980 @INPUT      : afp - acr file pointer
981               max_group_id - maximum group id to read in. If <= 0 then all
982                  groups are read in. If max_group_id is not a group id in the
983                  input stream, then the input stream is left with the first
984                  element of the next group missing (it gets read here and
985                  is not put back), so no more groups can be read in.
986 @OUTPUT     : group_list
987 @RETURNS    : status
988 @DESCRIPTION: Read in a list of acr-nema groups. If a watchpoint is set
989               on the input handle, then group reading will stop when it is
990               reached, although at least one group will be read in.
991 @METHOD     :
992 @GLOBALS    :
993 @CALLS      :
994 @CREATED    : November 24, 1993 (Peter Neelin)
995 @MODIFIED   :
996 ---------------------------------------------------------------------------- */
acr_input_group_list(Acr_File * afp,Acr_Group * group_list,int max_group_id)997 Acr_Status acr_input_group_list(Acr_File *afp, Acr_Group *group_list,
998                                 int max_group_id)
999 {
1000    Acr_Group cur_group, next_group;
1001    Acr_Status status;
1002 
1003    /* Initialize the group list */
1004    *group_list = NULL;
1005 
1006    /* Read in the first group */
1007    status = acr_input_group_with_max(afp, &next_group, max_group_id);
1008 
1009    /* Set up pointers */
1010    *group_list = cur_group = next_group;
1011 
1012    /* Loop, reading groups */
1013    while ((status == ACR_OK) && (cur_group != NULL) &&
1014           ((max_group_id <= 0) ||
1015            (acr_get_group_group(cur_group) < max_group_id))) {
1016 
1017       /* Check for a watchpoint */
1018       if (acr_get_io_watchpoint(afp) <= 0) {
1019          break;
1020       }
1021 
1022       /* Read in the next group */
1023       status = acr_input_group_with_max(afp, &next_group, max_group_id);
1024 
1025       /* Add it to the list */
1026       acr_set_group_next(cur_group, next_group);
1027       cur_group = next_group;
1028 
1029    }
1030 
1031    return status;
1032 
1033 }
1034 
1035 /* ----------------------------- MNI Header -----------------------------------
1036 @NAME       : acr_find_group
1037 @INPUT      : group_list
1038               group_id
1039 @OUTPUT     : (none)
1040 @RETURNS    : gropu pointer
1041 @DESCRIPTION: Find a group in a group list
1042 @METHOD     :
1043 @GLOBALS    :
1044 @CALLS      :
1045 @CREATED    : November 6, 1998 (Peter Neelin)
1046 @MODIFIED   :
1047 ---------------------------------------------------------------------------- */
acr_find_group(Acr_Group group_list,int group_id)1048 Acr_Group acr_find_group(Acr_Group group_list, int group_id)
1049 {
1050    Acr_Group group;
1051    int next_id;
1052 
1053    /* Search through groups for group id */
1054    group = group_list;
1055    if (group != NULL)
1056       next_id = acr_get_group_group(group);
1057    else
1058       next_id = 0;
1059    while ((next_id != group_id) && (group != NULL)) {
1060       group = acr_get_group_next(group);
1061       if (group != NULL)
1062          next_id = acr_get_group_group(group);
1063    }
1064 
1065    return group;
1066 
1067 }
1068 
1069 /* ----------------------------- MNI Header -----------------------------------
1070 @NAME       : acr_find_group_element
1071 @INPUT      : group_list
1072               elid
1073 @OUTPUT     : (none)
1074 @RETURNS    : element pointer
1075 @DESCRIPTION: Find an element in a group list
1076 @METHOD     :
1077 @GLOBALS    :
1078 @CALLS      :
1079 @CREATED    : November 10, 1993 (Peter Neelin)
1080 @MODIFIED   :
1081 ---------------------------------------------------------------------------- */
acr_find_group_element(Acr_Group group_list,Acr_Element_Id elid)1082 Acr_Element acr_find_group_element(Acr_Group group_list,
1083                                    Acr_Element_Id elid)
1084 {
1085    Acr_Group group;
1086 
1087    /* Find the group */
1088    group = acr_find_group(group_list, elid->group_id);
1089 
1090    /* If not found return NULL */
1091    if (group == NULL) return NULL;
1092 
1093    /* Search through element list for element */
1094    return acr_find_element_id(acr_get_group_element_list(group), elid);
1095 
1096 }
1097 
1098 /* ----------------------------- MNI Header -----------------------------------
1099 @NAME       : acr_dump_group_list
1100 @INPUT      : file_pointer - where output should go
1101               group_list
1102 @OUTPUT     : (none)
1103 @RETURNS    : (nothing)
1104 @DESCRIPTION: Dump information from an acr-nema group list
1105 @METHOD     :
1106 @GLOBALS    :
1107 @CALLS      :
1108 @CREATED    : November 24, 1993 (Peter Neelin)
1109 @MODIFIED   :
1110 ---------------------------------------------------------------------------- */
acr_dump_group_list(FILE * file_pointer,Acr_Group group_list)1111 void acr_dump_group_list(FILE *file_pointer, Acr_Group group_list)
1112 {
1113    Acr_Group cur_group;
1114 
1115    /* Check for empty list */
1116    cur_group = group_list;
1117    if (cur_group == NULL) {
1118       (void) fprintf(file_pointer,"\nEmpty group list\n\n");
1119       return;
1120    }
1121 
1122    /* Loop over groups */
1123    while (cur_group != NULL) {
1124 
1125       /* Print the group id */
1126       (void) fprintf(file_pointer, "\nGroup 0x%04x :\n\n",
1127                      acr_get_group_group(cur_group));
1128 
1129       /* Print the elements */
1130       acr_dump_element_list(file_pointer,
1131                             acr_get_group_element_list(cur_group));
1132 
1133       /* Go to the next group */
1134       cur_group = acr_get_group_next(cur_group);
1135    }
1136 
1137    /* Print a blank line after dump */
1138    (void) fprintf(file_pointer, "\n");
1139 
1140    /* Flush the buffer */
1141    (void) fflush(file_pointer);
1142 
1143    return;
1144 
1145 }
1146 
1147 /* ----------------------------- MNI Header -----------------------------------
1148 @NAME       : acr_find_short
1149 @INPUT      : group_list
1150               elid
1151               default_value
1152 @OUTPUT     : (none)
1153 @RETURNS    : Element value or default_value if element not found
1154 @DESCRIPTION: Find an element in a group list and return its value (assuming
1155               that it is stored as a binary short).
1156 @METHOD     :
1157 @GLOBALS    :
1158 @CALLS      :
1159 @CREATED    : December 10, 1993 (Peter Neelin)
1160 @MODIFIED   :
1161 ---------------------------------------------------------------------------- */
acr_find_short(Acr_Group group_list,Acr_Element_Id elid,Acr_Short default_value)1162 Acr_Short acr_find_short(Acr_Group group_list, Acr_Element_Id elid,
1163                          Acr_Short default_value)
1164 {
1165    Acr_Element element;
1166 
1167    element = acr_find_group_element(group_list, elid);
1168    if (element != NULL && acr_get_element_length(element) > 0)
1169       return acr_get_element_short(element);
1170    else
1171       return default_value;
1172 }
1173 
1174 /* ----------------------------- MNI Header -----------------------------------
1175 @NAME       : acr_find_long
1176 @INPUT      : group_list
1177               elid
1178               default_value
1179 @OUTPUT     : (none)
1180 @RETURNS    : Element value or default_value if element not found
1181 @DESCRIPTION: Find an element in a group list and return its value (assuming
1182               that it is stored as a binary long).
1183 @METHOD     :
1184 @GLOBALS    :
1185 @CALLS      :
1186 @CREATED    : December 10, 1993 (Peter Neelin)
1187 @MODIFIED   :
1188 ---------------------------------------------------------------------------- */
acr_find_long(Acr_Group group_list,Acr_Element_Id elid,Acr_Long default_value)1189 Acr_Long acr_find_long(Acr_Group group_list, Acr_Element_Id elid,
1190                        Acr_Long default_value)
1191 {
1192    Acr_Element element;
1193 
1194    element = acr_find_group_element(group_list, elid);
1195    if (element != NULL && acr_get_element_length(element) > 0)
1196       return acr_get_element_long(element);
1197    else
1198       return default_value;
1199 }
1200 
1201 /* ----------------------------- MNI Header -----------------------------------
1202 @NAME       : acr_find_int
1203 @INPUT      : group_list
1204               elid
1205               default_value
1206 @OUTPUT     : (none)
1207 @RETURNS    : Element value or default_value if element not found
1208 @DESCRIPTION: Find an element in a group list and return its value (assuming
1209               that it is stored as an ascii integer).
1210 @METHOD     :
1211 @GLOBALS    :
1212 @CALLS      :
1213 @CREATED    : December 10, 1993 (Peter Neelin)
1214 @MODIFIED   :
1215 ---------------------------------------------------------------------------- */
acr_find_int(Acr_Group group_list,Acr_Element_Id elid,int default_value)1216 int acr_find_int(Acr_Group group_list, Acr_Element_Id elid,
1217                  int default_value)
1218 {
1219    Acr_Element element;
1220 
1221    element = acr_find_group_element(group_list, elid);
1222    if (element != NULL && acr_get_element_length(element) > 0)
1223       return (int) acr_get_element_numeric(element);
1224    else
1225       return default_value;
1226 }
1227 
1228 /* ----------------------------- MNI Header -----------------------------------
1229 @NAME       : acr_find_double
1230 @INPUT      : group_list
1231               elid
1232               default_value
1233 @OUTPUT     : (none)
1234 @RETURNS    : Element value or default_value if element not found
1235 @DESCRIPTION: Find an element in a group list and return its value (assuming
1236               that it is stored as an ascii double).
1237 @METHOD     :
1238 @GLOBALS    :
1239 @CALLS      :
1240 @CREATED    : December 10, 1993 (Peter Neelin)
1241 @MODIFIED   :
1242 ---------------------------------------------------------------------------- */
acr_find_double(Acr_Group group_list,Acr_Element_Id elid,Acr_Double default_value)1243 Acr_Double acr_find_double(Acr_Group group_list, Acr_Element_Id elid,
1244                            Acr_Double default_value)
1245 {
1246    Acr_Element element;
1247 
1248    element = acr_find_group_element(group_list, elid);
1249    if (element != NULL && acr_get_element_length(element) > 0)
1250       return (Acr_Double)acr_get_element_numeric(element);
1251    else
1252       return default_value;
1253 }
1254 
1255 /* ----------------------------- MNI Header -----------------------------------
1256 @NAME       : acr_find_string
1257 @INPUT      : group_list
1258               elid
1259               default_value
1260 @OUTPUT     : (none)
1261 @RETURNS    : Element value or default_value if element not found
1262 @DESCRIPTION: Find an element in a group list and return its value (assuming
1263               that it is stored as an ascii string).
1264 @METHOD     :
1265 @GLOBALS    :
1266 @CALLS      :
1267 @CREATED    : December 10, 1993 (Peter Neelin)
1268 @MODIFIED   :
1269 ---------------------------------------------------------------------------- */
acr_find_string(Acr_Group group_list,Acr_Element_Id elid,Acr_String default_value)1270 Acr_String acr_find_string(Acr_Group group_list, Acr_Element_Id elid,
1271                            Acr_String default_value)
1272 {
1273    Acr_Element element;
1274 
1275    element = acr_find_group_element(group_list, elid);
1276    if (element != NULL)         /* Allow zero-length strings */
1277       return acr_get_element_string(element);
1278    else
1279       return default_value;
1280 }
1281 
1282 /* ----------------------------- MNI Header -----------------------------------
1283 @NAME       : acr_insert_element_into_group_list
1284 @INPUT      : group_list - list in which element should be inserted
1285                  (can be NULL)
1286               element - element to insert
1287 @OUTPUT     : group_list - modified group list
1288 @RETURNS    : Acr_Status
1289 @DESCRIPTION: Insert an element into a group list. If the group_list is NULL,
1290               then it is created. Note that the element is not copied, it is
1291               just inserted into the list, so it should not be modified after
1292               insertion into the list. If an element of the same id already
1293               exists in the list, it is removed and deleted.
1294 @METHOD     :
1295 @GLOBALS    :
1296 @CALLS      :
1297 @CREATED    : June 17, 1997 (Peter Neelin)
1298 @MODIFIED   :
1299 ---------------------------------------------------------------------------- */
acr_insert_element_into_group_list(Acr_Group * group_list,Acr_Element element)1300 Acr_Status acr_insert_element_into_group_list(Acr_Group *group_list,
1301                                               Acr_Element element)
1302 {
1303    Acr_Group group, next_group, prev_group;
1304    int group_id;
1305 
1306    /* Get group and element id */
1307    group_id = acr_get_element_group(element);
1308 
1309    /* Search for the appropriate group */
1310    prev_group = NULL;
1311    next_group = *group_list;
1312    while ((next_group != NULL) &&
1313           (acr_get_group_group(next_group) < group_id)) {
1314       prev_group = next_group;
1315       next_group = acr_get_group_next(next_group);
1316    }
1317 
1318    /* Check if we have the right group */
1319    if ((next_group != NULL) &&
1320        (acr_get_group_group(next_group) == group_id)) {
1321       group = next_group;
1322    }
1323 
1324    /* If not, create a new group and insert it in the list */
1325    else {
1326 
1327       /* Create a group */
1328       group = acr_create_group(group_id);
1329 
1330       /* Insert it in the list */
1331       acr_set_group_next(group, next_group);
1332       if (prev_group != NULL) {
1333          acr_set_group_next(prev_group, group);
1334       }
1335       else {
1336          *group_list = group;
1337       }
1338 
1339    }
1340 
1341    /* Insert the element into the appropriate group */
1342    return acr_group_insert_element(group, element);
1343 
1344 }
1345 
1346 /* ----------------------------- MNI Header -----------------------------------
1347 @NAME       : acr_insert_short
1348 @INPUT      : group_list - may be NULL if list empty
1349               elid
1350               value
1351 @OUTPUT     : group_list - modified group list
1352 @RETURNS    : Acr_Status
1353 @DESCRIPTION: Creates and inserts an element into a group list.
1354 @METHOD     :
1355 @GLOBALS    :
1356 @CALLS      :
1357 @CREATED    : June 17, 1997 (Peter Neelin)
1358 @MODIFIED   :
1359 ---------------------------------------------------------------------------- */
acr_insert_short(Acr_Group * group_list,Acr_Element_Id elid,Acr_Short value)1360 Acr_Status acr_insert_short(Acr_Group *group_list, Acr_Element_Id elid,
1361                             Acr_Short value)
1362 {
1363    Acr_Element element;
1364 
1365    element = acr_create_element_short(elid, value);
1366    return acr_insert_element_into_group_list(group_list, element);
1367 
1368 }
1369 
1370 /* ----------------------------- MNI Header -----------------------------------
1371 @NAME       : acr_insert_long
1372 @INPUT      : group_list - may be NULL if list empty
1373               elid
1374               value
1375 @OUTPUT     : group_list - modified group list
1376 @RETURNS    : Acr_Status
1377 @DESCRIPTION: Creates and inserts an element into a group list.
1378 @METHOD     :
1379 @GLOBALS    :
1380 @CALLS      :
1381 @CREATED    : June 17, 1997 (Peter Neelin)
1382 @MODIFIED   :
1383 ---------------------------------------------------------------------------- */
acr_insert_long(Acr_Group * group_list,Acr_Element_Id elid,Acr_Long value)1384 Acr_Status acr_insert_long(Acr_Group *group_list, Acr_Element_Id elid,
1385                            Acr_Long value)
1386 {
1387    Acr_Element element;
1388 
1389    element = acr_create_element_long(elid, value);
1390    return acr_insert_element_into_group_list(group_list, element);
1391 
1392 }
1393 
1394 /* ----------------------------- MNI Header -----------------------------------
1395 @NAME       : acr_insert_double
1396 @INPUT      : group_list - may be NULL if list empty
1397               elid
1398               nvalues
1399               values
1400 @OUTPUT     : group_list - modified group list
1401 @RETURNS    : Acr_Status
1402 @DESCRIPTION: Creates and inserts an element into a group list.
1403 @METHOD     :
1404 @GLOBALS    :
1405 @CALLS      :
1406 @CREATED    : April 8, 2006 (Bert Vincent)
1407 @MODIFIED   :
1408 ---------------------------------------------------------------------------- */
acr_insert_double(Acr_Group * group_list,Acr_Element_Id elid,int nvalues,Acr_Double * values)1409 Acr_Status acr_insert_double(Acr_Group *group_list, Acr_Element_Id elid,
1410                              int nvalues, Acr_Double *values)
1411 {
1412     Acr_Element element;
1413     element = acr_create_element_double(elid, nvalues, values);
1414     return acr_insert_element_into_group_list(group_list, element);
1415 }
1416 
1417 /* ----------------------------- MNI Header -----------------------------------
1418 @NAME       : acr_insert_numeric
1419 @INPUT      : group_list - may be NULL if list empty
1420               elid
1421               value
1422 @OUTPUT     : group_list - modified group list
1423 @RETURNS    : Acr_Status
1424 @DESCRIPTION: Creates and inserts an element into a group list.
1425 @METHOD     :
1426 @GLOBALS    :
1427 @CALLS      :
1428 @CREATED    : June 17, 1997 (Peter Neelin)
1429 @MODIFIED   :
1430 ---------------------------------------------------------------------------- */
acr_insert_numeric(Acr_Group * group_list,Acr_Element_Id elid,double value)1431 Acr_Status acr_insert_numeric(Acr_Group *group_list,
1432                               Acr_Element_Id elid,
1433                               double value)
1434 {
1435    Acr_Element element;
1436 
1437    element = acr_create_element_numeric(elid, value);
1438    return acr_insert_element_into_group_list(group_list, element);
1439 
1440 }
1441 
1442 /* ----------------------------- MNI Header -----------------------------------
1443 @NAME       : acr_insert_string
1444 @INPUT      : group_list - may be NULL if list empty
1445               elid
1446               value
1447 @OUTPUT     : group_list - modified group list
1448 @RETURNS    : Acr_Status
1449 @DESCRIPTION: Creates and inserts an element into a group list.
1450 @METHOD     :
1451 @GLOBALS    :
1452 @CALLS      :
1453 @CREATED    : June 17, 1997 (Peter Neelin)
1454 @MODIFIED   :
1455 ---------------------------------------------------------------------------- */
acr_insert_string(Acr_Group * group_list,Acr_Element_Id elid,Acr_String value)1456 Acr_Status acr_insert_string(Acr_Group *group_list,
1457                              Acr_Element_Id elid,
1458                              Acr_String value)
1459 {
1460    Acr_Element element;
1461 
1462    element = acr_create_element_string(elid, value);
1463    return acr_insert_element_into_group_list(group_list, element);
1464 
1465 }
1466 
1467 /* ----------------------------- MNI Header -----------------------------------
1468 @NAME       : acr_insert_sequence
1469 @INPUT      : group_list - may be NULL if list empty
1470               elid
1471               itemlist
1472 @OUTPUT     : group_list - modified group list
1473 @RETURNS    : Acr_Status
1474 @DESCRIPTION: Creates and inserts an element into a group list.
1475 @METHOD     :
1476 @GLOBALS    :
1477 @CALLS      :
1478 @CREATED    : June 17, 1997 (Peter Neelin)
1479 @MODIFIED   :
1480 ---------------------------------------------------------------------------- */
acr_insert_sequence(Acr_Group * group_list,Acr_Element_Id elid,Acr_Element itemlist)1481 Acr_Status acr_insert_sequence(Acr_Group *group_list,
1482                                Acr_Element_Id elid,
1483                                Acr_Element itemlist)
1484 {
1485    Acr_Element element;
1486 
1487    element = acr_create_element_sequence(elid, itemlist);
1488    return acr_insert_element_into_group_list(group_list, element);
1489 
1490 }
1491 
1492 /* ----------------------------- MNI Header -----------------------------------
1493 @NAME       : acr_test_dicom_file
1494 @INPUT      : afp
1495 @OUTPUT     : (none)
1496 @RETURNS    : status
1497 @DESCRIPTION: Tests for a dicom file input, as well as setting the byte
1498               order and VR encoding.
1499 @METHOD     : Check the byte order and t
1500               This function is in this file because it does not really have
1501               a better place to live: It depends on the group reading code
1502               (and so should not live in acr_io.c) and is independent of
1503               the other dicom code (and so should not live there).
1504 @GLOBALS    :
1505 @CALLS      : acr_test_byte_order, acr_input_group_list
1506 @CREATED    : November 8, 2001 (Peter Neelin)
1507 @MODIFIED   :
1508 ---------------------------------------------------------------------------- */
acr_test_dicom_file(Acr_File * afp)1509 Acr_Status acr_test_dicom_file(Acr_File *afp)
1510 {
1511 #define DICOM_FILE_MAGIC_OFFSET 128
1512 #define DICOM_MAGIC_STRING "DICM"
1513 #define DICOM_MAGIC_LEN 4
1514 #define DICOM_FILE_GROUP 0x2
1515 
1516    unsigned char buffer[DICOM_FILE_MAGIC_OFFSET+DICOM_MAGIC_LEN];
1517    Acr_Status status;
1518    long buflen;
1519    Acr_Group group_list;
1520 
1521    /* Read in up to magic */
1522    status = acr_read_buffer(afp, buffer, sizeof(buffer), &buflen);
1523    if (status != ACR_OK) return status;
1524 
1525    /* Check for the magic. If it is not there, put the data back and
1526       then test the byte order. */
1527    if (strncmp((char *) &buffer[DICOM_FILE_MAGIC_OFFSET], DICOM_MAGIC_STRING,
1528                DICOM_MAGIC_LEN) != 0) {
1529       status = acr_unget_buffer(afp, buffer, buflen);
1530       if (status != ACR_OK) return status;
1531       return acr_test_byte_order(afp);
1532    }
1533 
1534    /* Read in group 2.
1535       We could get the transfer syntax in the group at this point,
1536       or just use the test heuristic from acr_test_byte_order. It seems
1537       safer to trust the heuristic than the file writer, so we will ignore
1538       the contents of the group. */
1539    status = acr_test_byte_order(afp);
1540    if (status != ACR_OK) return status;
1541    status = acr_input_group_list(afp, &group_list, DICOM_FILE_GROUP);
1542    acr_delete_group_list(group_list);
1543    if (status != ACR_OK) return status;
1544 
1545    /* Test the byte order for the remainder of the file */
1546    status = acr_test_byte_order(afp);
1547    if (status != ACR_OK) return status;
1548 
1549    return status;
1550 }
1551 
1552