~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Tina4/src/file/dicom.old/CTN/dcm.c

Version: ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2           Copyright (C) 1993, 1994, RSNA and Washington University
  3 
  4           The software and supporting documentation for the Radiological
  5           Society of North America (RSNA) 1993, 1994 Digital Imaging and
  6           Communications in Medicine (DICOM) Demonstration were developed
  7           at the
  8                   Electronic Radiology Laboratory
  9                   Mallinckrodt Institute of Radiology
 10                   Washington University School of Medicine
 11                   510 S. Kingshighway Blvd.
 12                   St. Louis, MO 63110
 13           as part of the 1993, 1994 DICOM Central Test Node project for, and
 14           under contract with, the Radiological Society of North America.
 15 
 16           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
 17           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
 18           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
 19           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
 20           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
 21           THE SOFTWARE IS WITH THE USER.
 22 
 23           Copyright of the software and supporting documentation is
 24           jointly owned by RSNA and Washington University, and free access
 25           is hereby granted as a license to use this software, copy this
 26           software and prepare derivative works based upon this software.
 27           However, any distribution of this software source code or
 28           supporting documentation or derivative works (source code and
 29           supporting documentation) must include the three paragraphs of
 30           the copyright notice.
 31 */
 32 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
 33 
 34 /*
 35 **                              DICOM 93
 36 **                   Electronic Radiology Laboratory
 37 **                 Mallinckrodt Institute of Radiology
 38 **              Washington University School of Medicine
 39 **
 40 ** Module Name(s):      DCM_OpenFile
 41 **                      DCM_CreateObject
 42 **                      DCM_CloseObject
 43 **                      DCM_AddElement
 44 **                      DCM_AddSequenceElement
 45 **                      DCM_RemoveElement
 46 **                      DCM_GetElementValue
 47 **                      DCM_GetElementSize
 48 **                      DCM_ScanParseObject
 49 **                      DCM_ImportStream
 50 **                      DCM_ExportStream
 51 **                      DCM_GetObjectSize
 52 **                      DCM_DumpElements
 53 **                      DCM_Debug
 54 **                      DCM_WriteFile
 55 **                      DCM_ModifyElements
 56 **                      DCM_ParseObject
 57 **                      DCM_RemoveGroup
 58 **                      DCM_GetSequenceList
 59 **                      DCM_ComputeExportSize
 60 **      private functions
 61 **                      newElementItem
 62 **                      findCreateGroup
 63 **                      insertNewElement
 64 **                      updateObjectType
 65 **                      updateSpecialElements
 66 **                      exportFixedFields
 67 **                      exportData
 68 **                      fileSize
 69 **                      swapInPlace
 70 **                      checkObject
 71 **                      writeFile
 72 **                      countBytes
 73 **                      exportStream
 74 **                      verifyFormat
 75 **                      readFile
 76 ** Author, Date:        Stephen M. Moore, 26-Apr-93
 77 ** Intent:
 78 **      This file contains the routines which implement a facility for
 79 **      manipulating DICOM V3 information objects.  These routines parse
 80 **      and construct NEMA objects (or streams).  Users are able to
 81 **      read/write/examine individual attributes.  The package uses those
 82 **      individual elements to construct an internal memory representation of
 83 **      an object.  This representation is a linked list of the individual
 84 **      attributes.  The user of the package can add attributes to an object,
 85 **      remove an element from an object, query the object about an attribute,
 86 **      and convert the object to and from its "stream" representation.
 87 **      In addition, the package can parse a file which contains a stream
 88 **      and create its internal object.
 89 ** Last Update:         $Author: smm $, $Date: 1999/02/06 16:30:20 $
 90 ** Source File:         $RCSfile: dcm.c,v $
 91 ** Revision:            $Revision: 1.136 $
 92 ** Status:              $State: Exp $
 93 */
 94 
 95 static char rcsid[] = "$Revision: 1.136 $ $RCSfile: dcm.c,v $";
 96 
 97 #include <stdio.h>
 98 #include <errno.h>
 99 #include <string.h>
100 #include <ctype.h>
101 #ifndef MACOS
102 #include <stdlib.h>
103 #endif
104 #ifdef MALLOC_DEBUG
105 #include "malloc.h"
106 #endif
107 #ifdef GCCSUNOS
108 #include <unistd.h>
109 #endif
110 
111 #ifdef MACOS
112 #include <files.h>
113 #elif defined _MSC_VER
114 #include <io.h>
115 #include <fcntl.h>
116 #else
117 #include <sys/file.h>
118 #endif
119 
120 #ifdef MACOS
121 #include <fcntl.h>
122 #elif defined _MSC_VER
123 #include <fcntl.h>
124 #elif defined SOLARIS
125 #include <sys/fcntl.h>
126 #endif
127 
128 #include <sys/types.h>
129 #ifdef MACOS
130 #include <stat.h>
131 #else
132 #include <sys/stat.h>
133 #endif
134 #include "dicom.h"
135 #include "condition.h"
136 #include "lst.h"
137 #include "dicom_uids.h"
138 #include "dicom_objects.h"
139 #include "dcmprivate.h"
140 
141 #define BYTEORDER_SAME                  1
142 #define BYTEORDER_REVERSE               2
143 #define NATIVE_ORDER                    BYTEORDER_SAME
144 
145 #ifdef BIG_ENDIAN_ARCHITECTURE
146 #define LITTLE_ORDER    BYTEORDER_REVERSE
147 #define BIG_ORDER       BYTEORDER_SAME
148 #endif
149 
150 #ifdef LITTLE_ENDIAN_ARCHITECTURE
151 #define LITTLE_ORDER    BYTEORDER_SAME
152 #define BIG_ORDER       BYTEORDER_REVERSE
153 #endif
154 
155 static CTNBOOLEAN debug = FALSE;/* Flag for debugging messages to stdout */
156 
157 /* Prototypes for internal functions
158 */
159 static CONDITION
160 newElementItem(DCM_ELEMENT * src, CTNBOOLEAN allocateData,
161                PRV_ELEMENT_ITEM ** dst);
162 static CONDITION
163 findCreateGroup(PRIVATE_OBJECT ** object, unsigned short group,
164                 PRV_GROUP_ITEM ** groupPtr);
165 static CONDITION
166 insertNewElement(PRIVATE_OBJECT ** object,
167                  DCM_ELEMENT * element);
168 static CONDITION
169 updateObjectType(PRIVATE_OBJECT ** object,
170                  DCM_ELEMENT * element);
171 static CONDITION
172 updateSpecialElements(PRIVATE_OBJECT ** object,
173                       PRV_ELEMENT_ITEM * item);
174 static void
175 exportFixedFields(DCM_ELEMENT * element,
176                   unsigned char *b, U32 length, int byteOrder,
177                   CTNBOOLEAN explicitVR, U32 * rtnLength);
178 static CONDITION
179 exportData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
180            unsigned char *src,
181            unsigned char *dst, U32 length, int byteOrder,
182            U32 * rtnLength);
183 #ifdef MACOS
184 static long fileSize(int fd);
185 #else
186 static int fileSize(int fd);
187 #endif
188 static void swapInPlace(PRIVATE_OBJECT ** object, DCM_ELEMENT * e);
189 static CONDITION checkObject(PRIVATE_OBJECT ** object, char *caller);
190 static CONDITION
191     writeFile(void *buffer, U32 length, int flag, void /* int */ *fd);
192 static CONDITION
193 countBytes(void *buffer, U32 length, int flag,
194            void /* unsigned long */ *sizePtr);
195 static CONDITION
196 exportStream(DCM_OBJECT ** callerObject, unsigned long opt,
197              void *buffer, U32 bufferlength, CONDITION(*callback) (),
198              void *ctx, int sequenceLevel);
199 
200 static CONDITION
201     verifyFormat(PRV_ELEMENT_ITEM * item);
202 static CONDITION
203 readFile(char *name, unsigned char *callerBuf, int fd, long size,
204          off_t fileOffset, int recursionLevel,
205          unsigned long opt, DCM_OBJECT ** callerObject,
206          U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
207          void *ctx,
208          CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
209          CONDITION(*sk) (void *ctx, int offset, int flag));
210 static CONDITION
211 readFile1(const char *name, unsigned char *callerBuf, int fd, U32 size,
212           off_t * fileOffset, int recursionLevel,
213           unsigned long opt, PRIVATE_OBJECT ** parentObject,
214           DCM_OBJECT ** callerObject,
215           U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
216           void *ctx,
217           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
218           CONDITION(*sk) (void *ctx, int offset, int flag));
219 
220 static PRV_ELEMENT_ITEM *locateElement(PRIVATE_OBJECT ** obj, DCM_TAG tag);
221 static void computeVM(PRIVATE_OBJECT ** object, DCM_ELEMENT * element);
222 static void ctxSensitiveLookup(PRIVATE_OBJECT ** object, DCM_ELEMENT * element);
223 static CONDITION
224 copyData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
225          DCM_ELEMENT * to, U32 * rtnLength);
226 static CONDITION
227 readLengthToEnd(int fd, const char *fileName,
228                 unsigned long opt, U32 * lengthToEnd);
229 #ifdef LITTLE_ENDIAN_ARCHITECTURE
230 static void swapATGroupElement(DCM_ELEMENT * e);
231 #endif
232 static void
233 dumpBinaryData(void *d, DCM_VALUEREPRESENTATION vr,
234                long vm, long vmLimit);
235 static void
236 compareGroup(PRV_GROUP_ITEM * g1, PRV_GROUP_ITEM * g2,
237              void (*callback) (const DCM_ELEMENT * e1,
238                                const DCM_ELEMENT * e2,
239                                void *ctx),
240              void *ctx);
241 static void remapFileName(const char *name, char *mapName);
242 
243 
244 /* DCM_OpenFile
245 **
246 ** Purpose:
247 **  This function opens a file that conforms to the DICOM V3 standard.
248 **  The file is parsed and an internal representation of the data is created.
249 **  A handle is returned to the caller to allow access to the data.
250 **
251 ** Parameter Dictionary:
252 **   name       ASCIZ string giving path name to file to be opened.
253 **   opt        BITMASK giving options used when opening file and
254 **              interpreting data.  Current options have to do with the
255 **              byte order of the data in the file.  Legal masks for
256 **              this field are:
257 **                      DCM_ORDERNATIVE
258 **                      DCM_ORDERLITTLEENDIAN
259 **                      DCM_ORDERBIGENDIAN
260 **   object     Pointer to handle to return to caller  giving caller
261 **              future access to the data in the object.
262 **
263 ** Return Values:
264 **
265 **      DCM_ELEMENTCREATEFAILED
266 **      DCM_ELEMENTLENGTHERROR
267 **      DCM_ELEMENTOUTOFORDER
268 **      DCM_FILEACCESSERROR
269 **      DCM_FILEOPENFAILED
270 **      DCM_ILLEGALOPTION
271 **      DCM_ILLEGALSTREAMLENGTH
272 **      DCM_LISTFAILURE
273 **      DCM_NORMAL
274 **      DCM_OBJECTCREATEFAILED
275 **      DCM_UNEVENELEMENTLENGTH
276 **
277 ** Algorithm:
278 **      Determine file byte order (per caller's options)
279 **      Create new ACR object
280 **      Open file read only.
281 **      Determine size of file
282 **      While you have not reached end of file
283 **          Read next (group, element, length) triple
284 **          Lookup data element in dictionary
285 **          Read data value according to byte order and (group,element)
286 **          Check to see that data element is in numerical order
287 **          Add data element to linked list
288 **      End while
289 */
290 
291 CONDITION
292 DCM_OpenFile(const char *name, unsigned long opt, DCM_OBJECT ** callerObject)
293 {
294     CONDITION cond;
295     int fd;
296     off_t fileOffset = 0;
297     U32 lengthToEnd;
298     U32 size;
299     CTNBOOLEAN
300         remainFileOpen = FALSE; /* Leave file open after parse ? */
301 
302     if ((opt & (DCM_ORDERMASK | DCM_FILEFORMATMASK)) == 0)
303         return COND_PushCondition(DCM_ILLEGALOPTION,
304                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
305                                   "DCM_OpenFile");
306 
307 #ifdef _MSC_VER
308     fd = open(name, O_RDONLY | O_BINARY);
309 #else
310     fd = open(name, O_RDONLY);
311 #endif
312     if ((fd < 0) && ((opt & DCM_FILENAMEMASK) == DCM_TRYFILENAMECHANGE)) {
313         char mapName[1024];
314         remapFileName(name, mapName);
315 #ifdef _MSC_VER
316         fd = open(mapName, O_RDONLY | O_BINARY);
317 #else
318         fd = open(mapName, O_RDONLY);
319         if (fd < 0) {
320             strcat(mapName, ".");
321             fd = open(mapName, O_RDONLY);
322         }
323 #endif
324     }
325     if (fd < 0) {
326         return COND_PushCondition(DCM_FILEOPENFAILED,
327                                   DCM_Message(DCM_FILEOPENFAILED), name,
328                                   "DCM_OpenFile");
329     }
330     size = fileSize(fd);
331     if (size <= 0)
332         return DCM_FILEACCESSERROR;
333 
334     if ((opt & DCM_LENGTHTOENDMASK) == DCM_USELENGTHTOEND) {
335         cond = readLengthToEnd(fd, name,
336                                opt & (~DCM_LENGTHTOENDMASK), &lengthToEnd);
337         if (cond != DCM_NORMAL) {
338             (void) close(fd);
339             return COND_PushCondition(DCM_FILEOPENFAILED,
340                      DCM_Message(DCM_FILEOPENFAILED), name, "DCM_OpenFile");
341         }
342         size = lengthToEnd;
343         fileOffset = 24;
344         (void) lseek(fd, 24, SEEK_SET);
345     }
346 #ifdef OLDSMM
347     cond = readFile(name, NULL, fd, size, 0, 0, opt, callerObject, NULL,
348                     &remainFileOpen, NULL, NULL, NULL);
349 #endif
350     cond = readFile1(name, NULL, fd, size, &fileOffset, 0, opt, NULL,
351                      callerObject, NULL, &remainFileOpen, NULL, NULL, NULL);
352     if ((cond != DCM_NORMAL) || !remainFileOpen)
353         (void) close(fd);
354     if (cond != DCM_NORMAL) {
355         if (debug)
356             DCM_DumpElements(callerObject, 1);
357         return COND_PushCondition(DCM_FILEOPENFAILED,
358                      DCM_Message(DCM_FILEOPENFAILED), name, "DCM_OpenFile");
359     } else
360         return DCM_NORMAL;
361 }
362 
363 CONDITION
364 DCM_ReadStream(DCM_OBJECT ** callerObject, unsigned long opt, long size,
365                void *ctx,
366           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
367                CONDITION(*sk) (void *ctx, int offset, int flag))
368 {
369     CONDITION cond;
370     int fd = -1;
371     CTNBOOLEAN
372         remainFileOpen = FALSE; /* Leave file open after parse ? */
373     off_t fileOffset = 0;
374 
375     if ((opt & (DCM_ORDERMASK | DCM_FILEFORMATMASK)) == 0)
376         return COND_PushCondition(DCM_ILLEGALOPTION,
377                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
378                                   "DCM_ReadStream");
379 
380     cond = readFile1("", NULL, fd, size, &fileOffset, 0, opt, NULL,
381                      callerObject, NULL, &remainFileOpen, ctx, rd, sk);
382     if (cond != DCM_NORMAL)
383         return COND_PushCondition(DCM_READSTREAMFAILED,
384                        DCM_Message(DCM_READSTREAMFAILED), "DCM_ReadStream");
385     else
386         return DCM_NORMAL;
387 }
388 
389 /* DCM_CreateObject
390 **
391 ** Purpose:
392 **      This function creates a new object and initializes some
393 **      of the fields in the object
394 **
395 ** Parameter Dictionary:
396 **      object          Pointer to caller's handle for object to be created.
397 **      opt             Flag with options used when creating object.
398 **                      The only option that we use now is DCM_NOGROUPLENGTH.
399 **
400 ** Return Values:
401 **      DCM_NORMAL
402 **      DCM_OBJECTCREATEFAILED
403 **      DCM_LISTFAILURE
404 **
405 ** Algorithm:
406 **      Description of the algorithm (optional) and any other notes.
407 */
408 
409 CONDITION
410 DCM_CreateObject(DCM_OBJECT ** object, unsigned long opt)
411 {
412     PRIVATE_OBJECT
413         * obj;
414 
415     if (object == NULL) {
416         (void) COND_PushCondition(DCM_NULLADDRESS,
417                           DCM_Message(DCM_NULLADDRESS), "DCM_CreateObject");
418         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
419                    DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CreateObject");
420     }
421     obj = (PRIVATE_OBJECT *) CTN_MALLOC(sizeof(PRIVATE_OBJECT));
422     if (obj == NULL) {
423         (void) COND_PushCondition(DCM_MALLOCFAILURE,
424                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
425                                   "DCM_CreateObject");
426         *object = NULL;
427         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
428                    DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CreateObject");
429     }
430     (void) memset(obj, 0, sizeof(PRIVATE_OBJECT));
431     (void) strcpy(obj->keyType, KEY_DCM_OBJECT);
432 
433 
434     obj->objectType = DCM_OBJECTUNKNOWN;
435     obj->accessMethod = DCM_MEMORY_ACCESS;
436     obj->deleteFlag = FALSE;
437     if ((opt & DCM_GROUPLENGTHMASK) == DCM_NOGROUPLENGTH)
438         obj->groupLengthFlag = FALSE;
439     else
440         obj->groupLengthFlag = TRUE;
441     obj->objectSize = 0;
442     obj->offset = 0;
443     obj->pixelSize = 0;
444     obj->pixelOffset = 0;
445     obj->pixelBitsAllocated = 0;
446     obj->pixelRepresentation = 0xffff;
447     obj->groupCtx = NULL;
448     obj->elementCtx = NULL;
449     obj->fd = -1;
450     obj->fileName[0] = '\0';
451     obj->preambleFlag = FALSE;
452     obj->preamble[0] = '\0';
453     obj->dataOptions = 0;
454     obj->metaHeaderLength = 0xffffffff;
455     obj->longVRAttributes = 0;
456     obj->waveformDataVR[0] = '\0';
457 
458     obj->groupList = LST_Create();
459     if (obj->groupList == NULL) {
460         CTN_FREE(obj);
461         *object = NULL;
462         return COND_PushCondition(DCM_LISTFAILURE,
463                                   DCM_Message(DCM_LISTFAILURE),
464                                   "DCM_CreateObject");
465     }
466     *object = (DCM_OBJECT *) obj;
467     return DCM_NORMAL;
468 }
469 
470 
471 /* DCM_CloseObject
472 **
473 ** Purpose:
474 **      Close an information object by freeing memory allocated to it and
475 **      destroying caller's reference to it.
476 **
477 ** Parameter Dictionary:
478 **      callerObject    Address of caller's pointer to a DCM_OBJECT.
479 **
480 ** Return Values:
481 **
482 **      DCM_FILEDELETEFAILED
483 **      DCM_ILLEGALOBJECT
484 **      DCM_LISTFAILURE
485 **      DCM_NORMAL
486 **      DCM_NULLOBJECT
487 **
488 ** Algorithm:
489 */
490 
491 CONDITION
492 DCM_CloseObject(DCM_OBJECT ** callerObject)
493 {
494     CONDITION
495         cond;
496     PRV_GROUP_ITEM
497         * group;
498     PRV_ELEMENT_ITEM
499         * element;
500     PRIVATE_OBJECT
501         ** object;
502     DCM_SEQUENCE_ITEM
503         * sequenceItem;
504 
505     if (debug)
506         fprintf(stderr, "Starting DCM_CloseObject\n");
507 
508     object = (PRIVATE_OBJECT **) callerObject;
509     cond = checkObject(object, "DCM_CloseObject");
510     if (cond != DCM_NORMAL)
511         return cond;
512 
513     if ((*object)->fd > 0)
514         (void) close((*object)->fd);
515 
516     if (debug)
517         fprintf(stderr, "DCM_CloseObject: Legal object and file closed\n");
518 
519     while ((group = LST_Pop(&(*object)->groupList)) != NULL) {
520         if (debug)
521             fprintf(stderr, "DCM_CloseObject: group %04x\n", group->group);
522 
523         while ((element = LST_Pop(&group->elementList)) != NULL) {
524             if (debug)
525                 fprintf(stderr, "DCM_CloseObject: Element %08x\n",
526                         element->element.tag);
527             if (element->element.representation == DCM_SQ) {
528                 if (debug)
529                     fprintf(stderr, "Sequence List Address: %x\n",
530                             element->element.d.sq);
531                 if (element->element.d.sq != NULL) {
532                     while ((sequenceItem = LST_Pop(&element->element.d.sq)) != NULL) {
533                         (void) DCM_CloseObject(&sequenceItem->object);
534                         CTN_FREE(sequenceItem);
535                     }
536                     (void) LST_Destroy(&element->element.d.sq);
537                 }
538             }
539             if (debug)
540                 fprintf(stderr, "DCM_CloseObject: free %8x\n", element);
541 
542             CTN_FREE(element);
543         }
544         cond = LST_Destroy(&group->elementList);
545         if (cond != LST_NORMAL)
546             return COND_PushCondition(DCM_LISTFAILURE,
547                            DCM_Message(DCM_LISTFAILURE), "DCM_CloseObject");
548         CTN_FREE(group);
549     }
550     cond = LST_Destroy(&(*object)->groupList);
551     if (cond != LST_NORMAL)
552         return COND_PushCondition(DCM_LISTFAILURE,
553                            DCM_Message(DCM_LISTFAILURE), "DCM_CloseObject");
554 
555     cond = DCM_NORMAL;
556     if ((*object)->deleteFlag) {
557         if (unlink((*object)->fileName) != 0) {
558 /****    (void) COND_PushCondition(DCM_FILEDELETEFAILED, strerror(errno));****/
559             cond = COND_PushCondition(DCM_FILEDELETEFAILED,
560                                       DCM_Message(DCM_FILEDELETEFAILED), (*object)->fileName, strerror(errno),
561                                       "DCM_CloseObject");
562 
563         }
564     }
565     CTN_FREE(*object);
566     *object = NULL;
567     return cond;
568 }
569 
570 /* DCM_AddElement
571 **
572 ** Purpose:
573 **      Add an element to an existing DCM object
574 **
575 ** Parameter Dictionary:
576 **      object          Pointer to caller's existing DCM object.
577 **      element         Pointer to DCM element to be added to object
578 **
579 ** Return Values:
580 **
581 **      DCM_ILLEGALOBJECT
582 **      DCM_ILLEGALREPRESENTATION
583 **      DCM_INSERTFAILED
584 **      DCM_NORMAL
585 **      DCM_NULLOBJECT
586 **
587 ** Algorithm:
588 **      Check caller's object to make certain it is a legal object
589 **      Check element to see that caller is not trying to add
590 **          group length or length to end data elements.
591 **      Lookup element in the dictionary
592 **      If element is not in the dictionary, use caller's definition
593 **      If element is in the dictionary, make certain caller used
594 **          proper definitions or left things undefined.
595 **      Call findCreateGroup to
596 **          - create new group if this group does not exist
597 **          - create length to end element if necessary
598 **          - update object size for this object
599 **          - set CURRENT pointer in linked list to head of this group
600 **      Call insertNewElement to
601 **          - create a copy of the caller's element
602 **          - insert copy into linked list
603 **      Call updateObjectType to
604 **          - update this object as type COMMAND, DATASET, MESSAGE
605 */
606 
607 CONDITION
608 DCM_AddElement(DCM_OBJECT ** callerObject, DCM_ELEMENT * element)
609 {
610     CONDITION
611         cond;
612     DCM_ELEMENT
613         localElement;
614     PRIVATE_OBJECT
615         ** object;
616     PRV_GROUP_ITEM
617         * groupItem;
618 
619     object = (PRIVATE_OBJECT **) callerObject;
620 
621     cond = checkObject(object, "DCM_AddElement");
622     if (cond != DCM_NORMAL)
623         return cond;
624 
625     if ((DCM_TAG_ELEMENT(element->tag) == 0x0000))
626         return COND_PushCondition(DCM_ILLEGALADD,
627                    DCM_Message(DCM_ILLEGALADD), DCM_TAG_GROUP(element->tag),
628                            DCM_TAG_ELEMENT(element->tag), "DCM_AddElement");
629 
630 
631     localElement = *element;
632 
633     cond = DCM_LookupElement(&localElement);
634     if (cond != DCM_NORMAL) {
635         (void) COND_PopCondition(0);
636         localElement = *element;
637     } else {
638         if (localElement.representation == DCM_OT ||
639             localElement.representation == DCM_CTX)
640             localElement.representation = element->representation;
641         if (element->representation != DCM_UNKNOWN &&
642             element->representation != localElement.representation) {
643             return COND_PushCondition(DCM_ILLEGALREPRESENTATION,
644                                       DCM_Message(DCM_ILLEGALREPRESENTATION),
645                                       DCM_TAG_GROUP(element->tag),
646                                       DCM_TAG_ELEMENT(element->tag),
647                                       "DCM_AddElement");
648         }
649     }
650 
651     cond = findCreateGroup(object, DCM_TAG_GROUP(localElement.tag), &groupItem);
652     if (cond != DCM_NORMAL)
653         return COND_PushCondition(DCM_INSERTFAILED,
654                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
655                                   DCM_TAG_ELEMENT(element->tag),
656                                   "DCM_AddElement");
657 
658     cond = insertNewElement(object, &localElement);
659     if (cond != DCM_NORMAL)
660         return COND_PushCondition(DCM_INSERTFAILED,
661                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
662                                   DCM_TAG_ELEMENT(element->tag),
663                                   "DCM_AddElement");
664 
665     cond = updateObjectType(object, &localElement);
666     if (cond != DCM_NORMAL)
667         return COND_PushCondition(DCM_INSERTFAILED,
668                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
669                                   DCM_TAG_ELEMENT(element->tag),
670                                   "DCM_AddElement");
671 
672     return DCM_NORMAL;
673 }
674 
675 /* DCM_AddSequenceElement
676 **
677 ** Purpose:
678 **      Add a sequence element to an existing DCM object.  This
679 **      function takes ownership of the caller's sequence list
680 **      when it adds the element to the object.  The caller's
681 **      copy of the sequence list is removed.
682 **
683 ** Parameter Dictionary:
684 **      object          Pointer to caller's existing DCM object.
685 **      element         Pointer to DCM element to be added to object
686 **
687 ** Return Values:
688 **
689 **      DCM_ILLEGALOBJECT
690 **      DCM_ILLEGALREPRESENTATION
691 **      DCM_INSERTFAILED
692 **      DCM_NORMAL
693 **      DCM_NULLOBJECT
694 **
695 ** Algorithm:
696 */
697 
698 CONDITION
699 DCM_AddSequenceElement(DCM_OBJECT ** callerObject, DCM_ELEMENT * element)
700 {
701     CONDITION cond;
702     DCM_ELEMENT localElement;
703     PRIVATE_OBJECT **object;
704     PRV_GROUP_ITEM *groupItem;
705 
706     object = (PRIVATE_OBJECT **) callerObject;
707 
708     cond = checkObject(object, "DCM_AddSequenceElement");
709     if (cond != DCM_NORMAL)
710         return cond;
711 
712     if ((DCM_TAG_ELEMENT(element->tag) == 0x0000))
713         return COND_PushCondition(DCM_ILLEGALADD,
714                    DCM_Message(DCM_ILLEGALADD), DCM_TAG_GROUP(element->tag),
715                            DCM_TAG_ELEMENT(element->tag), "DCM_AddElement");
716 
717 
718     localElement = *element;
719 
720     cond = DCM_LookupElement(&localElement);
721     if (cond != DCM_NORMAL) {
722         (void) COND_PopCondition(0);
723         localElement = *element;
724     } else {
725         localElement.representation = element->representation;
726     }
727     if (localElement.representation != DCM_SQ) {
728         return COND_PushCondition(DCM_NOTASEQUENCE,
729                                   DCM_Message(DCM_NOTASEQUENCE),
730                                   DCM_TAG_GROUP(localElement.tag),
731                                   DCM_TAG_ELEMENT(localElement.tag),
732                                   "DCM_AddSequenceElement");
733     }
734     cond = findCreateGroup(object, DCM_TAG_GROUP(localElement.tag), &groupItem);
735     if (cond != DCM_NORMAL)
736         return COND_PushCondition(DCM_INSERTFAILED,
737                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
738                                   DCM_TAG_ELEMENT(element->tag),
739                                   "DCM_AddSequenceElement");
740 
741     cond = insertNewElement(object, &localElement);
742     if (cond != DCM_NORMAL)
743         return COND_PushCondition(DCM_INSERTFAILED,
744                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
745                                   DCM_TAG_ELEMENT(element->tag),
746                                   "DCM_AddElement");
747 
748     cond = updateObjectType(object, &localElement);
749     if (cond != DCM_NORMAL)
750         return COND_PushCondition(DCM_INSERTFAILED,
751                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
752                                   DCM_TAG_ELEMENT(element->tag),
753                                   "DCM_AddSequenceElement");
754 
755     /*
756      * We have taken ownership of the sequence list, so zero out caller's
757      * copy
758      */
759     element->d.sq = NULL;
760 
761     return DCM_NORMAL;
762 }
763 
764 /* DCM_RemoveElement
765 **
766 ** Purpose:
767 **      This function removes a single element from an information object.
768 **
769 ** Parameter Dictionary:
770 **      callerObject            Handle to the object
771 **      tag                     The tag of the element to be removed
772 **
773 ** Return Values:
774 **
775 **      DCM_ELEMENTNOTFOUND
776 **      DCM_ILLEGALOBJECT
777 **      DCM_NORMAL
778 **      DCM_NULLOBJECT
779 **
780 ** Algorithm:
781 **      Description of the algorithm (optional) and any other notes.
782 */
783 
784 CONDITION
785 DCM_RemoveElement(DCM_OBJECT ** callerObject, DCM_TAG tag)
786 {
787     PRIVATE_OBJECT
788         ** object;
789     PRV_GROUP_ITEM
790         * groupItem;
791     PRV_ELEMENT_ITEM
792         * elementItem,
793         *groupLengthItem;
794     CONDITION
795         cond;
796     CTNBOOLEAN
797         flag;
798     unsigned short
799         group,
800         element;
801 
802     object = (PRIVATE_OBJECT **) callerObject;
803     cond = checkObject(object, "DCM_RemoveElement");
804     if (cond != DCM_NORMAL)
805         return cond;
806 
807     group = DCM_TAG_GROUP(tag);
808     element = DCM_TAG_ELEMENT(tag);
809 
810     groupItem = LST_Head(&((*object)->groupList));
811     if (groupItem == NULL)
812         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
813                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
814                                   "DCM_RemoveElement");
815 
816     (void) LST_Position(&((*object)->groupList), groupItem);
817 
818     flag = FALSE;
819     while ((groupItem != NULL) && (flag == FALSE)) {
820         if (groupItem->group == group)
821             flag = TRUE;
822         else
823             groupItem = LST_Next(&(*object)->groupList);
824     }
825     if (flag == FALSE)
826         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
827                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
828                                   "DCM_RemoveElement");
829 
830     elementItem = LST_Head(&groupItem->elementList);
831     if (elementItem == NULL)
832         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
833                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
834                                   "DCM_RemoveElement");
835 
836     (void) LST_Position(&groupItem->elementList, elementItem);
837 
838     groupLengthItem = elementItem;
839     if (DCM_TAG_ELEMENT(groupLengthItem->element.tag) != 0x0000)
840         groupLengthItem = NULL;
841 
842 
843     flag = FALSE;
844     while ((elementItem != NULL) && (flag == FALSE)) {
845         if (DCM_TAG_ELEMENT(elementItem->element.tag) == element)
846             flag = TRUE;
847         else
848             elementItem = LST_Next(&groupItem->elementList);
849     }
850 
851     if (flag == FALSE)
852         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
853                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
854                                   "DCM_RemoveElement");
855 
856     if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH) {
857         groupItem->baseLength -= elementItem->paddedDataLength + 2 + 2 + 4;
858         if (groupLengthItem != NULL) {
859             *groupLengthItem->element.d.ul = groupItem->baseLength;
860         }
861     }
862     if ((*object)->objectSize != DCM_UNSPECIFIEDLENGTH)
863         (*object)->objectSize -= elementItem->paddedDataLength + 2 + 2 + 4;
864     if (elementItem->element.representation == DCM_OW ||
865         elementItem->element.representation == DCM_OB ||
866         elementItem->element.representation == DCM_SQ) {
867         groupItem->longVRAttributes--;
868         (*object)->longVRAttributes--;
869     }
870     (void) LST_Remove(&(groupItem->elementList), LST_K_AFTER);
871     CTN_FREE(elementItem);
872     return DCM_NORMAL;
873 }
874 
875 /* DCM_GetElementValue
876 **
877 ** Purpose:
878 **      This function retrieves the data from one data element and
879 **      returns it in a buffer allocated by the caller.  In the event
880 **      the data is larger than the caller's buffer, multiple calls
881 **      are used to retrieve the data.
882 **
883 ** Parameter Dictionary:
884 **      object          Pointer to user's object containing desired element
885 **      element         DCM_ELEMENT structure containing (group,element)
886 **                      specification of desired data element
887 **      rtnLength       Pointer to caller variable to hold length of
888 **                      data returned by this call.
889 **      ctx             Pointer to context variable used for multiple
890 **                      calls to this function.  Caller should set the
891 **                      pointer to NULL before the first call and not
892 **                      touch the pointer again.
893 **
894 ** Return Values:
895 **
896 **      DCM_CANNOTGETSEQUENCEVALUE
897 **      DCM_ELEMENTNOTFOUND
898 **      DCM_GETINCOMPLETE
899 **      DCM_ILLEGALCONTEXT
900 **      DCM_ILLEGALOBJECT
901 **      DCM_NORMAL
902 **      DCM_NULLOBJECT
903 **
904 ** Algorithm:
905 **      Check caller's object to make certain it is a legal DCM object.
906 **      Find head of the object linked list.
907 **      Search linked list sequentially until object is found or end
908 **      of list reached.
909 **      If end of list
910 **              return DCM_ELEMENTNOTFOUND
911 **      If CTX pointer containts NULL
912 **          Begin copy from beginning of element
913 **      else
914 **          Begin copy from address in CTX pointer
915 **      Copy data from element data area to user buffer
916 **      If copy is incomplete (remaining data longer than caller's buffer)
917 **          Update CTX pointer to point to next uncopied part of data
918 **          Return DCM_GETINCOMPLETE
919 **      else
920 **          Update CTX pointer to point past data area.
921 **          Return DCM_NORMAL
922 */
923 
924 CONDITION
925 DCM_GetElementValue(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
926                     U32 * rtnLength, void **ctx)
927 {
928     PRIVATE_OBJECT
929         ** object;
930     PRV_GROUP_ITEM
931         * groupItem;
932     PRV_ELEMENT_ITEM
933         * elementItem;
934     int
935         nBytes;
936     CONDITION
937         cond;
938 
939     object = (PRIVATE_OBJECT **) callerObject;
940     cond = checkObject(object, "DCM_GetElementValue");
941     if (cond != DCM_NORMAL)
942         return cond;
943 
944     groupItem = LST_Head(&(*object)->groupList);
945     if (groupItem == NULL)
946         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
947               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
948                                   DCM_TAG_ELEMENT(element->tag),
949                                   "DCM_GetElementValue");
950 
951     (void) LST_Position(&(*object)->groupList, groupItem);
952     while (groupItem != NULL) {
953         if (groupItem->group == DCM_TAG_GROUP(element->tag))
954             break;
955 
956         groupItem = LST_Next(&(*object)->groupList);
957     }
958     if (groupItem == NULL)
959         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
960               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
961                                   DCM_TAG_ELEMENT(element->tag),
962                                   "DCM_GetElementValue");
963 
964     elementItem = LST_Head(&groupItem->elementList);
965     if (elementItem == NULL)
966         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
967               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
968                                   DCM_TAG_GROUP(element->tag),
969                                   "DCM_GetElementValue");
970 
971     (void) LST_Position(&groupItem->elementList, elementItem);
972     while (elementItem != NULL) {
973         if (elementItem->element.tag == element->tag) {
974             unsigned char *p;
975             U32 l;
976 
977             if (element->representation == DCM_SQ)
978                 return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
979                                     DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
980                                        element->tag, "DCM_GetElementValue");
981 
982             p = *ctx;
983             if ((U32) p > elementItem->element.length)
984                 return COND_PushCondition(DCM_ILLEGALCONTEXT,
985                                           DCM_Message(DCM_ILLEGALCONTEXT),
986                                           "DCM_GetElementValue");
987 
988             l = MIN(element->length, (elementItem->element.length - (U32) p));
989 
990             *rtnLength = l;
991             {
992                 if (elementItem->element.d.ot == NULL) {
993                     if ((*object)->fd != -1) {
994                         (void) lseek((*object)->fd,
995                              elementItem->dataOffset + (off_t) p, SEEK_SET);
996                         nBytes = read((*object)->fd, element->d.ot, (int) l);
997                     } else {
998                         (*object)->sk((*object)->userCtx,
999                                       (long) (elementItem->dataOffset + (off_t) p), SEEK_SET);
1000                         cond = (*object)->rd((*object)->userCtx, element->d.ot, l,
1001                                              &nBytes);
1002                     }
1003                     if ((unsigned) nBytes != l) {
1004                         return COND_PushCondition(DCM_FILEACCESSERROR,
1005                                            DCM_Message(DCM_FILEACCESSERROR),
1006                                                   (*object)->fileName,
1007                                                   "DCM_GetElementValue");
1008                     }
1009 #ifdef LITTLE_ENDIAN_ARCHITECTURE
1010                     if (elementItem->element.representation == DCM_AT) {
1011                         DCM_ELEMENT e;
1012                         e = elementItem->element;
1013                         e.length = l;
1014                         e.d.ot = element->d.ot;
1015                         swapATGroupElement(&e);
1016                     }
1017 #endif
1018                     if (elementItem->byteOrder == BYTEORDER_REVERSE) {
1019                         DCM_ELEMENT e;
1020                         e = elementItem->element;
1021                         e.length = l;
1022                         e.d.ot = element->d.ot;
1023                         swapInPlace(object, &e);
1024                     }
1025                 } else {
1026                     unsigned char *q;
1027                     q = (unsigned char *) elementItem->element.d.ot +
1028                         (U32) p;
1029                     (void) memcpy(element->d.ot, q, l);
1030                     if (elementItem->byteOrder == BYTEORDER_REVERSE) {
1031                         DCM_ELEMENT e;
1032                         e = elementItem->element;
1033                         e.length = l;
1034                         e.d.ot = element->d.ot;
1035                         swapInPlace(object, &e);
1036                     }
1037                 }
1038                 p += l;
1039                 *ctx = (void *) p;
1040                 if ((unsigned) p == elementItem->element.length)
1041                     return DCM_NORMAL;
1042                 else
1043                     return DCM_GETINCOMPLETE;
1044             }
1045 
1046         }
1047         elementItem = LST_Next(&groupItem->elementList);
1048     }
1049     return COND_PushCondition(DCM_ELEMENTNOTFOUND,
1050               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
1051                               DCM_TAG_ELEMENT(element->tag),
1052                               "DCM_GetElementValue");
1053 }
1054 
1055 
1056 CONDITION
1057 DCM_GetElementValueOffset(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
1058                           unsigned long offset)
1059 {
1060     PRIVATE_OBJECT **object;
1061     PRV_ELEMENT_ITEM *elementItem;
1062     int nBytes;
1063     CONDITION cond;
1064 
1065     object = (PRIVATE_OBJECT **) callerObject;
1066     cond = checkObject(object, "DCM_GetElementValue");
1067     if (cond != DCM_NORMAL)
1068         return cond;
1069 
1070     elementItem = locateElement(object, element->tag);
1071     if (elementItem == NULL)
1072         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
1073               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
1074                                   DCM_TAG_ELEMENT(element->tag),
1075                                   "DCM_GetElementValueOffset");
1076 
1077 
1078     {
1079         unsigned char *p;
1080         U32 l;
1081 
1082         if (element->representation == DCM_SQ)
1083             return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
1084                                     DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
1085                                  element->tag, "DCM_GetElementValueOffset");
1086 
1087         p = (unsigned char *) offset;;
1088         if ((U32) p > elementItem->element.length)
1089             return COND_PushCondition(DCM_BADOFFSET,
1090                                       DCM_Message(DCM_BADOFFSET),
1091                                       (int) offset,
1092                                       (int) elementItem->element.length,
1093                                       "DCM_GetElementValueLength");
1094 
1095         l = element->length;
1096         if (l + offset > elementItem->element.length) {
1097             return COND_PushCondition(DCM_BADLENGTH,
1098                                       DCM_Message(DCM_BADLENGTH),
1099                                       (int) offset, (int) l,
1100                                       (int) elementItem->element.length,
1101                                       "DCM_GetElementValueLength");
1102         } {
1103             if (elementItem->element.d.ot == NULL) {
1104                 if ((*object)->fd != -1) {
1105                     (void) lseek((*object)->fd,
1106                              elementItem->dataOffset + (off_t) p, SEEK_SET);
1107                     nBytes = read((*object)->fd, element->d.ot, (int) l);
1108                 } else {
1109                     (*object)->sk((*object)->userCtx,
1110                     (long) (elementItem->dataOffset + (off_t) p), SEEK_SET);
1111                     cond = (*object)->rd((*object)->userCtx, element->d.ot, l,
1112                                          &nBytes);
1113                 }
1114                 if ((unsigned) nBytes != l) {
1115                     return COND_PushCondition(DCM_FILEACCESSERROR,
1116                                            DCM_Message(DCM_FILEACCESSERROR),
1117                                               (*object)->fileName,
1118                                               "DCM_GetElementValueValue");
1119                 }
1120 #ifdef LITTLE_ENDIAN_ARCHITECTURE
1121                 if (elementItem->element.representation == DCM_AT) {
1122                     DCM_ELEMENT e;
1123                     e = elementItem->element;
1124                     e.length = l;
1125                     e.d.ot = element->d.ot;
1126                     swapATGroupElement(&e);
1127                 }
1128 #endif
1129                 if (elementItem->byteOrder == BYTEORDER_REVERSE) {
1130                     DCM_ELEMENT e;
1131                     e = elementItem->element;
1132                     e.length = l;
1133                     e.d.ot = element->d.ot;
1134                     swapInPlace(object, &e);
1135                 }
1136             } else {
1137                 unsigned char *q;
1138                 q = (unsigned char *) elementItem->element.d.ot +
1139                     (U32) p;
1140                 (void) memcpy(element->d.ot, q, l);
1141                 if (elementItem->byteOrder == BYTEORDER_REVERSE) {
1142                     DCM_ELEMENT e;
1143                     e = elementItem->element;
1144                     e.length = l;
1145                     e.d.ot = element->d.ot;
1146                     swapInPlace(object, &e);
1147                 }
1148             }
1149             return DCM_NORMAL;
1150         }
1151 
1152     }
1153 }
1154 
1155 
1156 
1157 /* DCM_GetElementSize
1158 **
1159 ** Purpose:
1160 **      Return the size of one data element in an ACR object.
1161 **
1162 ** Parameter Dictionary:
1163 **      object          Pointer to caller's ACR object
1164 **      element         Pointer to ACR element that defines data element
1165 **                      of interest by specifying (group,element) pair
1166 **      rtnLength       Pointer to caller variable to hold returned
1167 **                      length of data element
1168 **
1169 ** Return Values:
1170 **
1171 **      DCM_NORMAL
1172 **      DCM_NULLOBJECT
1173 **      DCM_ILLEGALOBJECT
1174 **      DCM_ELEMENTNOTFOUND
1175 **
1176 ** Algorithm:
1177 **      Description of the algorithm (optional) and any other notes.
1178 */
1179 
1180 CONDITION
1181 DCM_GetElementSize(DCM_OBJECT ** callerObject, DCM_TAG tag,
1182                    U32 * rtnLength)
1183 {
1184     PRIVATE_OBJECT
1185         ** object;
1186     PRV_GROUP_ITEM
1187         * groupItem;
1188     PRV_ELEMENT_ITEM
1189         * elementItem;
1190     CONDITION
1191         cond;
1192     CTNBOOLEAN
1193         flag;
1194     unsigned short
1195         group,
1196         element;
1197 
1198     object = (PRIVATE_OBJECT **) callerObject;
1199     cond = checkObject(object, "DCM_GetElementSize");
1200     if (cond != DCM_NORMAL)
1201         return cond;
1202 
1203     group = DCM_TAG_GROUP(tag);
1204     element = DCM_TAG_ELEMENT(tag);
1205 
1206     groupItem = LST_Head(&((*object)->groupList));
1207     if (groupItem == NULL)
1208         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
1209                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
1210                                   "DCM_GetElementSize");
1211 
1212     (void) LST_Position(&((*object)->groupList), groupItem);
1213 
1214     flag = FALSE;
1215     while ((groupItem != NULL) && (flag == FALSE)) {
1216         if (groupItem->group == group)
1217             flag = TRUE;
1218         else
1219             groupItem = LST_Next(&(*object)->groupList);
1220     }
1221     if (flag == FALSE)
1222         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
1223                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
1224                                   "DCM_GetElementSize");
1225 
1226     elementItem = LST_Head(&groupItem->elementList);
1227     if (elementItem == NULL)
1228         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
1229                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
1230                                   "DCM_GetElementSize");
1231 
1232     (void) LST_Position(&groupItem->elementList, elementItem);
1233 
1234     flag = FALSE;
1235     while ((elementItem != NULL) && (flag == FALSE)) {
1236         if (elementItem->element.tag == tag)
1237             flag = TRUE;
1238         else
1239             elementItem = LST_Next(&groupItem->elementList);
1240     }
1241 
1242     if (flag == FALSE)
1243         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
1244                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
1245                                   "DCM_GetElementSize");
1246 
1247 
1248     *rtnLength = elementItem->element.length;
1249     return DCM_NORMAL;
1250 }
1251 
1252 
1253 /* DCM_ScanParseObject
1254 **
1255 ** Purpose:
1256 **      DCM_ScanParseObject is used to allow a caller to examine every
1257 **      element in a DICOM object and to parse the elements in the object.
1258 **      The caller passes a list of elements to be parsed from the object.
1259 **      This function examines each element in the object in order
1260 **      (ascending group/element).  If the element in the object is found
1261 **      in the caller's parse list, the element is parsed (and a value
1262 **      placed in storage allocated by the caller).  If the element is
1263 **      not found in the caller's list, a callback function is invoked
1264 **      to notify the caller of the element.  When the callback function
1265 **      is invoked, the arguments are:
1266 **              DCM_ELEMENT *e  Pointer to the individual element
1267 **              void *ctx       Caller's context information
1268 **
1269 **      This function is very useful for determining exactly which
1270 **      elements are present in an object without having to ask for
1271 **      each one individually.
1272 **
1273 ** Parameter Dictionary:
1274 **      callerObject    Pointer to caller's DICOM object
1275 **      buf             Unused
1276 **      bufferSizd      Unused
1277 **      vector          A vector of elements which are to be parsed.  An entry
1278 **                      in the vector gives the tag and describes where the
1279 **                      parsed data is to be stored.
1280 **      vectorLength    Number of entries in the vector.
1281 **      callback        Caller function invoked for an element that is in
1282 **                      the object but is not found in caller's list.
1283 **      ctx             Context information that is passed to callback function.
1284 **
1285 ** Return Values:
1286 **
1287 **      DCM_NORMAL
1288 **      DCM_NULLOBJECT
1289 **      DCM_ILLEGALOBJECT
1290 **
1291 ** Algorithm:
1292 */
1293 
1294 CONDITION
1295 DCM_ScanParseObject(DCM_OBJECT ** callerObject, void *buf, size_t bufferSize,
1296                     DCM_FLAGGED_ELEMENT * vector, int vectorLength,
1297                     CONDITION(*callback) (), void *ctx)
1298 {
1299     PRIVATE_OBJECT
1300         ** object;
1301     PRV_GROUP_ITEM
1302         * groupItem;
1303     PRV_ELEMENT_ITEM
1304         * elementItem;
1305     CONDITION
1306         cond;
1307     CTNBOOLEAN
1308         done = FALSE;
1309     DCM_ELEMENT
1310         e;
1311     int
1312         i;
1313     CTNBOOLEAN
1314         found;
1315     U32
1316         l;
1317     char
1318        *p;
1319 
1320     object = (PRIVATE_OBJECT **) callerObject;
1321     cond = checkObject(object, "DCM_ScanParseObject");
1322     if (cond != DCM_NORMAL)
1323         return cond;
1324 
1325     groupItem = LST_Head(&((*object)->groupList));
1326     (void) LST_Position(&((*object)->groupList), groupItem);
1327     while (groupItem != NULL && !done) {
1328         elementItem = LST_Head(&groupItem->elementList);
1329         (void) LST_Position(&groupItem->elementList, elementItem);
1330         while (elementItem != NULL && !done) {
1331             for (found = FALSE, i = 0; !found && i < vectorLength; i++) {
1332                 if (elementItem->element.tag == vector[i].e.tag) {
1333                     found = TRUE;
1334                     (void) copyData(object, elementItem, &vector[i].e, &l);
1335                     *vector[i].flagAddress |= vector[i].flag;
1336 
1337                     if (DCM_IsString(vector[i].e.representation)) {
1338                         vector[i].e.d.string[l] = '\0';
1339                         p = vector[i].e.d.string + l - 1;
1340                         while (p >= vector[i].e.d.string && (*p == ' '))
1341                             *p-- = '\0';
1342                     }
1343                 }
1344             }
1345             if (!found) {
1346                 e = elementItem->element;
1347                 cond = callback(&e, ctx);
1348                 if (cond != DCM_NORMAL)
1349                     done = TRUE;
1350             }
1351             elementItem = LST_Next(&groupItem->elementList);
1352         }
1353         groupItem = LST_Next(&((*object)->groupList));
1354     }
1355     return DCM_NORMAL;
1356 }
1357 
1358 /* DCM_ImportStream
1359 **
1360 ** Purpose:
1361 **      Import data from memory in DCM stream format and create
1362 **      an internal memory representation of the object.
1363 **
1364 ** Parameter Dictionary:
1365 **      buf             Pointer to caller's buffer containing ACR NEMA data
1366 **      length          Length of input data in bytes
1367 **      opt             Bitmask giving options for interpreting data.
1368 **                      Legal values specify the order of the bytes in the data
1369 **                              ACR_ORDERNATIVE
1370 **                              ACR_ORDERLITTLEENDIAN
1371 **                              ACR_ORDERBIGENDIAN
1372 **      object          Pointer to object created and returned by this function
1373 **
1374 ** Return Values:
1375 **
1376 **      DCM_ELEMENTCREATEFAILED
1377 **      DCM_ELEMENTLENGTHERROR
1378 **      DCM_ELEMENTOUTOFORDER
1379 **      DCM_FILEACCESSERROR
1380 **      DCM_ILLEGALOPTION
1381 **      DCM_ILLEGALSTREAMLENGTH
1382 **      DCM_LISTFAILURE
1383 **      DCM_NORMAL
1384 **      DCM_OBJECTCREATEFAILED
1385 **      DCM_UNEVENELEMENTLENGTH
1386 **
1387 ** Algorithm:
1388 **      call private import stream function which handles recursion
1389 **
1390 */
1391 
1392 CONDITION
1393 DCM_ImportStream(unsigned char *buf, unsigned long length,
1394                  unsigned long opt, DCM_OBJECT ** callerObject)
1395 {
1396 #ifdef DEBUG
1397     if (debug)
1398         (void) fprintf(stderr, "DCM_ImportStream, %ld bytes\n", length);
1399 #endif
1400 
1401     if ((opt & DCM_ORDERMASK) == 0)
1402         return COND_PushCondition(DCM_ILLEGALOPTION,
1403                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
1404                                   "DCM_ImportStream");
1405 
1406     return readFile("", buf, -1, length, 0, 0, opt, callerObject, NULL, NULL,
1407                     NULL, NULL, NULL);
1408 }
1409 
1410 /* DCM_ExportStream
1411 **
1412 ** Purpose:
1413 **      Export a DICOM object into the stream format suitable
1414 **      for network transmission or disk storage.
1415 **
1416 ** Parameter Dictionary:
1417 **      object          Pointer to caller's DICOM object
1418 **      opt             Bitmask giving options for exporting data.  Legal
1419 **                      options give the byte order of exported data:
1420 **                              DCM_ORDERNATIVE
1421 **                              DCM_ORDERLITTLEENDIAN
1422 **                              DCM_ORDERBIGENDIAN
1423 **      buffer          Pointer to caller's buffer to hold next slug
1424 **                      of DCM stream data.
1425 **      bufferlength    Length of caller's buffer to hold stream data.
1426 **      returnlength    Pointer to caller's variable into which we write
1427 **                      the amount of data exported.
1428 **      ctx             Pointer to context variable we maintain to keep
1429 **                      track of our location in export process.
1430 **
1431 ** Return Values:
1432 **
1433 **      DCM_FILEACCESSERROR
1434 **      DCM_ILLEGALOBJECT
1435 **      DCM_LISTFAILURE
1436 **      DCM_NORMAL
1437 **      DCM_NULLOBJECT
1438 **
1439 ** Algorithm:
1440 **      Description of the algorithm (optional) and any other notes.
1441 */
1442 
1443 CONDITION
1444 DCM_ExportStream(DCM_OBJECT ** callerObject, unsigned long opt,
1445                  void *buffer, unsigned long bufferlength,
1446 CONDITION(*callback) (void *buf, U32 bytesExported, int lastFlag, void *ctx),
1447                  void *ctx)
1448 {
1449 
1450 
1451     PRIVATE_OBJECT
1452         ** object;
1453     CONDITION
1454         cond;
1455 
1456     object = (PRIVATE_OBJECT **) callerObject;
1457     cond = checkObject(object, "DCM_ExportStream");
1458     if (cond != DCM_NORMAL)
1459         return cond;
1460 
1461     return exportStream(callerObject, opt, buffer, bufferlength, callback,
1462                         ctx, 0);
1463 }
1464 
1465 /* DCM_GetObjectSize
1466 **
1467 ** Purpose:
1468 **      Return the size of a DICOM object when it is represented in
1469 **      stream format.
1470 **
1471 ** Parameter Dictionary:
1472 **      object          Pointer to caller's DICOM object
1473 **      returnlength    Pointer to unsigned long variable to hold length of
1474 **                      object
1475 **
1476 ** Return Values:
1477 **
1478 **      DCM_ILLEGALOBJECT
1479 **      DCM_NORMAL
1480 **      DCM_NULLOBJECT
1481 **
1482 ** Algorithm:
1483 **      Description of the algorithm (optional) and any other notes.
1484 */
1485 
1486 CONDITION
1487 DCM_GetObjectSize(DCM_OBJECT ** callerObject, unsigned long *returnlength)
1488 {
1489     PRIVATE_OBJECT
1490         ** object;
1491     CONDITION
1492         cond;
1493 
1494     object = (PRIVATE_OBJECT **) callerObject;
1495     cond = checkObject(object, "DCM_GetObjectSize");
1496     if (cond != DCM_NORMAL)
1497         return cond;
1498 
1499     *returnlength = (*object)->objectSize;
1500     return DCM_NORMAL;
1501 }
1502 
1503 /* DCM_DumpElements
1504 **
1505 ** Purpose:
1506 **      Dump a short description of each data element in an object to
1507 **      stdout (for use as a debugging tool).
1508 **
1509 ** Parameter Dictionary:
1510 **      object          Pointer to caller's handle for DCM object to be dumped
1511 **      vm              Limit on the value multiplicity for printing
1512 **                      binary data.  Print no more than vm values.
1513 **
1514 ** Return Values:
1515 **
1516 **      DCM_ILLEGALOBJECT
1517 **      DCM_NORMAL
1518 **      DCM_NULLOBJECT
1519 **
1520 ** Algorithm:
1521 **      Check caller's handle to make certain it is a legal DCM object
1522 **      Print object type (COMMAND, DATASET, MESSAGE) and size in bytes
1523 **      For each GROUP in the object linked list
1524 **          For each ELEMENT ITEM in the group linked list
1525 **              print group, element, size, description
1526 **              print some or all of data based on data element representation
1527 **                      (ASCII number, ASCII text, binary)
1528 **          End for
1529 **      End for
1530 */
1531 CONDITION
1532 DCM_DumpElements(DCM_OBJECT ** callerObject, long vm)
1533 {
1534     PRV_GROUP_ITEM
1535         * groupItem;
1536     PRV_ELEMENT_ITEM
1537         * elementItem;
1538     PRIVATE_OBJECT
1539         ** object;
1540     CONDITION
1541         cond;
1542     DCM_SEQUENCE_ITEM
1543         * sq;
1544     char
1545         scratch[128];
1546     int
1547         stringLength;
1548 
1549     object = (PRIVATE_OBJECT **) callerObject;
1550 
1551     cond = checkObject(object, "DCM_DumpElements");
1552     if (cond != DCM_NORMAL)
1553         return cond;
1554 
1555     printf("\nDCM Dump Elements\n");
1556     switch ((*object)->objectType) {
1557     case DCM_OBJECTUNKNOWN:
1558         printf("Object type: UNKNOWN\n");
1559         break;
1560     case DCM_OBJECTCOMMAND:
1561         printf("Object type: COMMAND\n");
1562         break;
1563     case DCM_OBJECTIMAGE:
1564         printf("Object type: IMAGE\n");
1565         break;
1566     case DCM_OBJECTELEMENTLIST:
1567         printf("Object type: ELEMENT LIST\n");
1568         break;
1569     default:
1570         printf("Object type: Unknown (error)\n");
1571         break;
1572     }
1573     printf("Object size: %ld\n", (*object)->objectSize);
1574 
1575     groupItem = LST_Head(&(*object)->groupList);
1576     if (groupItem != NULL)
1577         (void) LST_Position(&(*object)->groupList, groupItem);
1578 
1579     while (groupItem != NULL) {
1580 #ifdef MACOS
1581         printf("Group: %04x, Length: %8ld\n", groupItem->group,
1582                groupItem->baseLength);
1583 #else
1584         printf("Group: %04x, Length: %8d\n", groupItem->group,
1585                groupItem->baseLength);
1586 #endif
1587         elementItem = LST_Head(&groupItem->elementList);
1588         if (elementItem != NULL)
1589             (void) LST_Position(&groupItem->elementList, elementItem);
1590         while (elementItem != NULL) {
1591 #ifdef MACOS
1592             (void) printf("%04x %04x %8ld ",
1593                           DCM_TAG_GROUP(elementItem->element.tag),
1594                           DCM_TAG_ELEMENT(elementItem->element.tag),
1595                           elementItem->element.length);
1596 #else
1597             (void) printf("%04x %04x %8d ",
1598                           DCM_TAG_GROUP(elementItem->element.tag),
1599                           DCM_TAG_ELEMENT(elementItem->element.tag),
1600                           elementItem->element.length);
1601 #endif
1602             (void) printf("//%31s//", elementItem->element.description);
1603             if (elementItem->element.d.ot == NULL)
1604                 (void) printf("Data on disk\n");
1605             else {
1606                 switch (elementItem->element.representation) {
1607                 case DCM_AE:
1608                 case DCM_AS:
1609                 case DCM_CS:
1610                 case DCM_DA:
1611                 case DCM_DT:
1612                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
1613                     strncpy(scratch, elementItem->element.d.string, stringLength);
1614                     scratch[stringLength] = '\0';
1615                     (void) printf("%s\n", scratch);
1616                     break;
1617                 case DCM_DD:
1618                 case DCM_FD:
1619                 case DCM_FL:
1620                     (void) printf("Unimplemented\n");
1621                     break;
1622                 case DCM_DS:
1623                 case DCM_IS:
1624                 case DCM_LO:
1625                 case DCM_LT:
1626                 case DCM_PN:
1627                 case DCM_SH:
1628                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
1629                     strncpy(scratch, elementItem->element.d.string, stringLength);
1630                     scratch[stringLength] = '\0';
1631                     (void) printf("%s\n", scratch);
1632                     break;
1633                 case DCM_SL:
1634 #ifdef MACOS
1635                     (void) printf("%8lx %ld\n", *elementItem->element.d.sl,
1636                                   *elementItem->element.d.sl);
1637 #else
1638                     (void) printf("%8x %d\n", *elementItem->element.d.sl,
1639                                   *elementItem->element.d.sl);
1640                     if (vm > 1)
1641                         dumpBinaryData(elementItem->element.d.ot,
1642                                        elementItem->element.representation,
1643                              elementItem->element.length / sizeof(U32), vm);
1644 #endif
1645                     break;
1646                 case DCM_SS:
1647                     (void) printf("%4x %d\n", *elementItem->element.d.ss,
1648                                   *elementItem->element.d.ss);
1649                     if (vm > 1)
1650                         dumpBinaryData(elementItem->element.d.ot,
1651                                        elementItem->element.representation,
1652                            elementItem->element.length / sizeof(short), vm);
1653                     break;
1654                 case DCM_SQ:
1655                     (void) printf("SEQUENCE\n");
1656                     sq = LST_Head(&elementItem->element.d.sq);
1657                     if (sq != NULL)
1658                         (void) LST_Position(&elementItem->element.d.sq, sq);
1659                     printf("DCM Dump Sequence\n");
1660                     while (sq != NULL) {
1661                         (void) DCM_DumpElements(&sq->object, vm);
1662                         sq = LST_Next(&elementItem->element.d.sq);
1663                     }
1664                     printf("DCM Dump Sequence Complete\n");
1665                     break;
1666                 case DCM_ST:
1667                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
1668                     strncpy(scratch, elementItem->element.d.string, stringLength);
1669                     scratch[stringLength] = '\0';
1670                     (void) printf("%s\n", scratch);
1671                     break;
1672                 case DCM_TM:
1673                 case DCM_UI:
1674                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
1675                     strncpy(scratch, elementItem->element.d.string, stringLength);
1676                     scratch[stringLength] = '\0';
1677                     (void) printf("%s\n", scratch);
1678                     break;
1679                 case DCM_AT:
1680                 case DCM_UL:
1681 #ifdef MACOS
1682                     (void) printf("%8lx %ld\n", *elementItem->element.d.ul,
1683                                   *elementItem->element.d.ul);
1684 #else
1685                     (void) printf("%8x %d\n", *elementItem->element.d.ul,
1686                                   *elementItem->element.d.ul);
1687                     if (vm > 1)
1688                         dumpBinaryData(elementItem->element.d.ot,
1689                                        elementItem->element.representation,
1690                              elementItem->element.length / sizeof(U32), vm);
1691 #endif
1692                     break;
1693                 case DCM_US:
1694                     (void) printf("%4x %d\n", *elementItem->element.d.us,
1695                                   *elementItem->element.d.us);
1696                     if (vm > 1)
1697                         dumpBinaryData(elementItem->element.d.ot,
1698                                        elementItem->element.representation,
1699                                        elementItem->element.length / sizeof(unsigned short), vm);
1700                     break;
1701                 case DCM_OT:
1702                 case DCM_OW:
1703                 case DCM_OB:
1704                 case DCM_UNKNOWN:
1705                 case DCM_RET:
1706                     (void) printf("Unimplemented\n");
1707                     break;
1708                 default:
1709                     (void) printf("Some unimplemented logic if here\n");
1710                     break;
1711                 }
1712             }
1713             elementItem = LST_Next(&groupItem->elementList);
1714         }
1715         groupItem = LST_Next(&(*object)->groupList);
1716     }
1717 
1718     printf("DCM Dump Elements Complete\n\n");
1719     return DCM_NORMAL;
1720 }
1721 
1722 /* DCM_Debug
1723 **
1724 ** Purpose:
1725 **      To enable the debugging facility
1726 **
1727 ** Parameter Dictionary:
1728 **      flag    CTNBOOLEAN variable TRUE if caller wants to turn on debugging
1729 **              info; FALSE otherwise
1730 **
1731 ** Return Values:
1732 **      None
1733 **
1734 ** Algorithm:
1735 **      Description of the algorithm (optional) and any other notes.
1736 */
1737 
1738 void
1739 DCM_Debug(CTNBOOLEAN flag)
1740 {
1741     debug = flag;
1742 }
1743 
1744 /* DCM_WriteFile
1745 **
1746 ** Purpose:
1747 **      Export an object from the internal representation and
1748 **      write the stream representation to a file.
1749 **
1750 ** Parameter Dictionary:
1751 **      object          DCM_OBJECT which is to be written to the file
1752 **      opt             Bitmask giving options for exporting data.  Legal
1753 **                      options give the byte order of exported data:
1754 **                              DCM_ORDERNATIVE
1755 **                              DCM_ORDERLITTLEENDIAN
1756 **                              DCM_ORDERBIGENDIAN
1757 **      file            ASCIIZ name of the file to be created.
1758 **
1759 ** Return Values:
1760 **
1761 **      DCM_FILEACCESSERROR
1762 **      DCM_FILECREATEFAILED
1763 **      DCM_ILLEGALOBJECT
1764 **      DCM_LISTFAILURE
1765 **      DCM_NORMAL
1766 **      DCM_NULLOBJECT
1767 **
1768 ** Algorithm:
1769 **      Description of the algorithm (optional) and any other notes.
1770 */
1771 
1772 CONDITION
1773 DCM_WriteFile(DCM_OBJECT ** callerObject, unsigned long opt, const char *file)
1774 {
1775     PRIVATE_OBJECT
1776         ** object;
1777     int
1778         fd;
1779     unsigned char
1780         buf[2048];
1781     CONDITION
1782         cond;
1783 
1784     object = (PRIVATE_OBJECT **) callerObject;
1785     cond = checkObject(object, "DCM_WriteFile");
1786     if (cond != DCM_NORMAL)
1787         return cond;
1788 #ifdef MACOS
1789     fd = open(file, O_WRONLY | O_CREAT | O_TRUNC);
1790 #elif _MSC_VER
1791     fd = _open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
1792                _S_IREAD | _S_IWRITE);
1793 #else
1794     fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
1795 #endif
1796     if (fd < 0) {
1797         return COND_PushCondition(DCM_FILECREATEFAILED,
1798                    DCM_Message(DCM_FILECREATEFAILED), file, strerror(errno),
1799                                   "DCM_WriteFile");
1800     }
1801     cond = DCM_ExportStream(callerObject, opt, buf,
1802                             (unsigned long) sizeof(buf), writeFile, &fd);
1803     if (cond != DCM_NORMAL)
1804         return cond;
1805 
1806     (void) close(fd);
1807     return DCM_NORMAL;
1808 }
1809 
1810 /* DCM_ModifyElements
1811 **
1812 ** Purpose:
1813 **
1814 ** Parameter Dictionary:
1815 **      callerObject            Handle to user's DICOM object to be modified
1816 **      vector                  Mandatory elements that need to be stored
1817 **                              in the object
1818 **      count                   Number of such mandatory elements
1819 **      flaggedVector           Optional elements
1820 **      flaggedCount            Number of such optional elements
1821 **      updateCount             Total number of elements updated (returned to
1822 **                              caller)
1823 **
1824 ** Return Values:
1825 **
1826 **      DCM_ILLEGALOBJECT
1827 **      DCM_ILLEGALREPRESENTATION
1828 **      DCM_INSERTFAILED
1829 **      DCM_NORMAL
1830 **      DCM_NULLOBJECT
1831 **
1832 ** Algorithm:
1833 **      Check caller's object to make certain it is a legal DCM object.
1834 **      Find head of the object linked list.
1835 **      Search linked list sequentially until object is found or end
1836 **      of list reached.
1837 **      If end of list
1838 **              return DCM_ELEMENTNOTFOUND
1839 **      If CTX pointer containts NULL
1840 **          Begin copy from beginning of element
1841 **      else
1842 **          Begin copy from address in CTX pointer
1843 **      Copy data from element data area to user buffer
1844 **      If copy is incomplete (remaining data longer than caller's buffer)
1845 **          Update CTX pointer to point to next uncopied part of data
1846 **          Return DCM_GETINCOMPLETE
1847 **      else
1848 **          Update CTX pointer to point past data area.
1849 **          Return DCM_NORMAL
1850 */
1851 
1852 CONDITION
1853 DCM_ModifyElements(DCM_OBJECT ** callerObject, DCM_ELEMENT * vector, int count,
1854                    DCM_FLAGGED_ELEMENT * flaggedVector, int flaggedCount,
1855                    int *updateCount)
1856 {
1857     PRIVATE_OBJECT
1858         ** object;
1859     CONDITION
1860         cond;
1861     DCM_ELEMENT
1862         e;
1863     int
1864         c = 0;
1865 
1866     object = (PRIVATE_OBJECT **) callerObject;
1867     cond = checkObject(object, "DCM_ModifyElement");
1868     if (cond != DCM_NORMAL)
1869         return cond;
1870 
1871     while (count-- > 0) {
1872         cond = DCM_RemoveElement(callerObject, vector->tag);
1873         if (cond != DCM_NORMAL)
1874             (void) COND_PopCondition(FALSE);
1875 
1876         e = *vector;
1877         if (DCM_IsString(e.representation))
1878             e.length = strlen(e.d.string);
1879 
1880         cond = DCM_AddElement(callerObject, &e);
1881         if (cond != DCM_NORMAL)
1882             return cond;
1883 
1884         c++;
1885         vector++;
1886     }
1887 
1888     while (flaggedCount-- > 0) {
1889         if ((*(flaggedVector->flagAddress) & flaggedVector->flag) != 0) {
1890             cond = DCM_RemoveElement(callerObject, flaggedVector->e.tag);
1891             if (cond != DCM_NORMAL)
1892                 (void) COND_PopCondition(FALSE);
1893 
1894             e = flaggedVector->e;
1895             if (DCM_IsString(e.representation))
1896                 e.length = strlen(e.d.string);
1897             cond = DCM_AddElement(callerObject, &e);
1898             if (cond != DCM_NORMAL)
1899                 return cond;
1900             c++;
1901         }
1902         flaggedVector++;
1903     }
1904 
1905     if (updateCount != NULL)
1906         *updateCount = c;
1907     return DCM_NORMAL;
1908 }
1909 
1910 
1911 /* DCM_ParseObject
1912 **
1913 ** Purpose:
1914 **      Parse the object and store the mandatory and optional elements in
1915 **      different vectors.
1916 **
1917 ** Parameter Dictionary:
1918 **      callerObject            Handle to user's DICOM object to be modified
1919 **      vector                  Mandatory elements that need to be stored
1920 **                              in the object
1921 **      count                   Number of such mandatory elements
1922 **      flaggedVector           Optional elements
1923 **      flaggedCount            Number of such optional elements
1924 **      parseCount              Total number of elements parsed (returned to
1925 **                              caller)
1926 **
1927 ** Return Values:
1928 **
1929 **      DCM_CANNOTGETSEQUENCEVALUE
1930 **      DCM_ELEMENTNOTFOUND
1931 **      DCM_GETINCOMPLETE
1932 **      DCM_ILLEGALCONTEXT
1933 **      DCM_ILLEGALOBJECT
1934 **      DCM_NORMAL
1935 **      DCM_NULLOBJECT
1936 **
1937 ** Notes:
1938 **
1939 ** Algorithm:
1940 **      Description of the algorithm (optional) and any other notes.
1941 */
1942 CONDITION
1943 DCM_ParseObject(DCM_OBJECT ** callerObject, DCM_ELEMENT * vector,
1944               int count, DCM_FLAGGED_ELEMENT * flaggedVector, int flagCount,
1945                 int *parseCount)
1946 {
1947     PRIVATE_OBJECT
1948         ** object;
1949     CONDITION
1950         cond;
1951     void
1952        *ctx;
1953     U32
1954         l;
1955     int
1956         c = 0;
1957     char
1958        *p;
1959 
1960     object = (PRIVATE_OBJECT **) callerObject;
1961     cond = checkObject(object, "DCM_ParseObject");
1962     if (cond != DCM_NORMAL)
1963         return cond;
1964 
1965     while (count-- > 0) {
1966         ctx = NULL;
1967         cond = DCM_GetElementValue(callerObject, vector, &l, &ctx);
1968         if (cond != DCM_NORMAL)
1969             return cond;
1970         if (DCM_IsString(vector->representation)) {
1971             vector->d.string[l] = '\0';
1972             p = vector->d.string + l - 1;
1973             while (p >= vector->d.string && (*p == ' '))
1974                 *p-- = '\0';
1975         }
1976         c++;
1977         vector++;
1978     }
1979 
1980     while (flagCount-- > 0) {
1981         ctx = NULL;
1982         cond = DCM_GetElementValue(callerObject, &flaggedVector->e, &l, &ctx);
1983         if (cond != DCM_NORMAL) {
1984             (void) COND_PopCondition(FALSE);
1985         } else {
1986             c++;
1987             if (DCM_IsString(flaggedVector->e.representation)) {
1988                 flaggedVector->e.d.string[l] = '\0';
1989                 p = flaggedVector->e.d.string + l - 1;
1990                 while (p >= flaggedVector->e.d.string && (*p == ' '))
1991                     *p-- = '\0';
1992             }
1993             *(flaggedVector->flagAddress) |= flaggedVector->flag;
1994         }
1995         flaggedVector++;
1996     }
1997 
1998     if (parseCount != NULL)
1999         *parseCount = c;
2000     return DCM_NORMAL;
2001 }
2002 
2003 
2004 /* DCM_RemoveGroup
2005 **
2006 ** Purpose:
2007 **      Remove an element with the given group number from the object
2008 **
2009 ** Parameter Dictionary:
2010 **      callerObject            Handle to caller's object
2011 **      group                   Group number of the element to be removed.
2012 **
2013 ** Return Values:
2014 **
2015 **      DCM_GROUPNOTFOUND
2016 **      DCM_ILLEGALOBJECT
2017 **      DCM_LISTFAILURE
2018 **      DCM_NORMAL
2019 **      DCM_NULLOBJECT
2020 **
2021 ** Notes:
2022 **
2023 ** Algorithm:
2024 **      Description of the algorithm (optional) and any other notes.
2025 */
2026 
2027 CONDITION
2028 DCM_RemoveGroup(DCM_OBJECT ** callerObject, unsigned short group)
2029 {
2030     PRIVATE_OBJECT
2031         ** object;
2032     CONDITION
2033         cond;
2034     PRV_GROUP_ITEM
2035         * groupItem;
2036     PRV_ELEMENT_ITEM
2037         * elementItem;
2038     CTNBOOLEAN
2039         found = FALSE;
2040 
2041     object = (PRIVATE_OBJECT **) callerObject;
2042     cond = checkObject(object, "DCM_RemoveGroup");
2043     if (cond != DCM_NORMAL)
2044         return cond;
2045 
2046     groupItem = LST_Head(&(*object)->groupList);
2047     if (groupItem == NULL)
2048         return COND_PushCondition(DCM_GROUPNOTFOUND,
2049             DCM_Message(DCM_GROUPNOTFOUND), (int) group, "DCM_RemoveGroup");
2050 
2051     (void) LST_Position(&(*object)->groupList, groupItem);
2052 
2053     while (!found && (groupItem != NULL)) {
2054         if (groupItem->group == group)
2055             found = TRUE;
2056         else
2057             groupItem = LST_Next(&(*object)->groupList);
2058     }
2059     if (groupItem == NULL)
2060         return COND_PushCondition(DCM_GROUPNOTFOUND,
2061             DCM_Message(DCM_GROUPNOTFOUND), (int) group, "DCM_RemoveGroup");
2062 
2063 
2064     while ((elementItem = LST_Pop(&groupItem->elementList)) != NULL)
2065         CTN_FREE(elementItem);
2066 
2067     groupItem = LST_Remove(&(*object)->groupList, LST_K_AFTER);
2068     cond = LST_Destroy(&groupItem->elementList);
2069     if (cond != LST_NORMAL)
2070         return COND_PushCondition(DCM_LISTFAILURE,
2071                            DCM_Message(DCM_LISTFAILURE), "DCM_RemoveGroup");
2072     CTN_FREE(groupItem);
2073     return DCM_NORMAL;
2074 }
2075 
2076 /* DCM_GetSequenceList
2077 **
2078 ** Purpose:
2079 **      Obtain the sequence list from the DICOM object corresponding to the
2080 **      tag value.
2081 **
2082 ** Parameter Dictionary:
2083 **      object          Handle to the DICOM object
2084 **      tag             Tag number of the sequence list element to be obtained
2085 **                      from the DICOM object
2086 **      list            Holds the sequence list. Returned to the caller.
2087 **
2088 ** Return Values:
2089 **
2090 **      DCM_ELEMENTNOTFOUND
2091 **      DCM_ILLEGALOBJECT
2092 **      DCM_NORMAL
2093 **      DCM_NULLOBJECT
2094 **
2095 ** Notes:
2096 **
2097 ** Algorithm:
2098 **      Description of the algorithm (optional) and any other notes.
2099 */
2100 
2101 CONDITION
2102 DCM_GetSequenceList(DCM_OBJECT ** object, DCM_TAG tag, LST_HEAD ** list)
2103 {
2104     PRIVATE_OBJECT
2105         ** obj;
2106     CONDITION
2107         cond;
2108     PRV_GROUP_ITEM
2109         * groupItem;
2110     PRV_ELEMENT_ITEM
2111         * elementItem;
2112     CTNBOOLEAN
2113         found = FALSE;
2114 
2115     obj = (PRIVATE_OBJECT **) object;
2116     cond = checkObject(obj, "DCM_GetSequenceList");
2117     if (cond != DCM_NORMAL)
2118         return cond;
2119 
2120     groupItem = LST_Head(&(*obj)->groupList);
2121     if (groupItem == NULL)
2122         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2123                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2124                                   DCM_TAG_ELEMENT(tag),
2125                                   "DCM_GetSequenceList");
2126 
2127     (void) LST_Position(&(*obj)->groupList, groupItem);
2128     while (groupItem != NULL) {
2129         if (groupItem->group == DCM_TAG_GROUP(tag))
2130             break;
2131 
2132         groupItem = LST_Next(&(*obj)->groupList);
2133     }
2134     if (groupItem == NULL)
2135         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2136                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2137                                   DCM_TAG_ELEMENT(tag),
2138                                   "DCM_GetSequenceList");
2139 
2140     elementItem = LST_Head(&groupItem->elementList);
2141     if (elementItem == NULL)
2142         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2143                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2144                                   DCM_TAG_GROUP(tag),
2145                                   "DCM_GetSequenceTag");
2146 
2147     (void) LST_Position(&groupItem->elementList, elementItem);
2148     while (!found && (elementItem != NULL)) {
2149         if (elementItem->element.tag == tag) {
2150             *list = elementItem->element.d.sq;
2151             found = TRUE;
2152         }
2153         elementItem = LST_Next(&groupItem->elementList);
2154     }
2155     if (found)
2156         return DCM_NORMAL;
2157     else
2158         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2159                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2160                                   DCM_TAG_ELEMENT(tag),
2161                                   "DCM_GetSequenceList");
2162 }
2163 
2164 CONDITION
2165 DCM_GetSequenceElement(DCM_OBJECT ** object, DCM_TAG top, DCM_ELEMENT * e)
2166 {
2167     PRIVATE_OBJECT **obj;
2168     CONDITION cond;
2169     PRV_GROUP_ITEM *groupItem;
2170     PRV_ELEMENT_ITEM *elementItem;
2171     DCM_SEQUENCE_ITEM *seqItem;
2172 
2173     CTNBOOLEAN found = FALSE;
2174 
2175     obj = (PRIVATE_OBJECT **) object;
2176     cond = checkObject(obj, "DCM_GetSequenceElement");
2177     if (cond != DCM_NORMAL)
2178         return cond;
2179 
2180     elementItem = locateElement(obj, top);
2181     if (elementItem == NULL) {
2182         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2183                                   DCM_Message(DCM_ELEMENTNOTFOUND),
2184                                   DCM_TAG_GROUP(top),
2185                                   DCM_TAG_ELEMENT(top),
2186                                   "DCM_GetElementSequence");
2187     }
2188     if (elementItem->element.representation != DCM_SQ) {
2189         return COND_PushCondition(DCM_UNEXPECTEDREPRESENTATION,
2190                                   DCM_Message(DCM_UNEXPECTEDREPRESENTATION),
2191                                   "DCM_GetSequenceElement", "sequence");
2192     }
2193     seqItem = LST_Head(&elementItem->element.d.sq);
2194     cond = DCM_ParseObject(&seqItem->object, e, 1, NULL, 0, NULL);
2195     return cond;
2196 
2197 #if 0
2198     return DCM_NORMAL;
2199 #endif
2200 }
2201 
2202 /* DCM_GetElementValueList
2203 **
2204 ** Purpose:
2205 **
2206 ** Parameter Dictionary:
2207 **      Define the parameters to the function
2208 **
2209 ** Return Values:
2210 **
2211 **      DCM_ELEMENTNOTFOUND
2212 **      DCM_ILLEGALOBJECT
2213 **      DCM_LISTFAILURE
2214 **      DCM_MALLOCFAILURE
2215 **      DCM_NORMAL
2216 **      DCM_NULLOBJECT
2217 **
2218 ** Notes:
2219 **
2220 ** Algorithm:
2221 **      Description of the algorithm (optional) and any other notes.
2222 */
2223 CONDITION
2224 DCM_GetElementValueList(DCM_OBJECT ** object, DCM_TAG tag,
2225                   size_t structureSize, long stringOffset, LST_HEAD ** list)
2226 {
2227     PRIVATE_OBJECT
2228         ** obj;
2229     CONDITION
2230         cond;
2231     PRV_GROUP_ITEM
2232         * groupItem;
2233     PRV_ELEMENT_ITEM
2234         * elementItem;
2235     CTNBOOLEAN
2236         found = FALSE;
2237     char
2238        *src,
2239        *dst,
2240        *p;
2241     U32
2242         l;
2243 
2244     obj = (PRIVATE_OBJECT **) object;
2245     cond = checkObject(obj, "DCM_GetSequenceList");
2246     if (cond != DCM_NORMAL)
2247         return cond;
2248 
2249     groupItem = LST_Head(&(*obj)->groupList);
2250     if (groupItem == NULL)
2251         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2252                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2253                                   DCM_TAG_ELEMENT(tag),
2254                                   "DCM_GetSequenceList");
2255 
2256     (void) LST_Position(&(*obj)->groupList, groupItem);
2257     while (groupItem != NULL) {
2258         if (groupItem->group == DCM_TAG_GROUP(tag))
2259             break;
2260 
2261         groupItem = LST_Next(&(*obj)->groupList);
2262     }
2263     if (groupItem == NULL)
2264         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2265                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2266                                   DCM_TAG_ELEMENT(tag),
2267                                   "DCM_GetSequenceList");
2268 
2269     elementItem = LST_Head(&groupItem->elementList);
2270     if (elementItem == NULL)
2271         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2272                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2273                                   DCM_TAG_GROUP(tag),
2274                                   "DCM_GetSequenceTag");
2275 
2276     (void) LST_Position(&groupItem->elementList, elementItem);
2277     while (!found && (elementItem != NULL)) {
2278         if (elementItem->element.tag == tag) {
2279             found = TRUE;
2280         } else
2281             elementItem = LST_Next(&groupItem->elementList);
2282     }
2283     if (!found)
2284         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2285                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2286                                   DCM_TAG_ELEMENT(tag),
2287                                   "DCM_GetElementValueList");
2288 
2289     if (!DCM_IsString(elementItem->element.representation)) {
2290         return COND_PushCondition(DCM_UNEXPECTEDREPRESENTATION,
2291         DCM_Message(DCM_UNEXPECTEDREPRESENTATION), "DCM_GetElementValueList",
2292                                   "string");
2293     }
2294     src = elementItem->element.d.string;
2295     l = elementItem->element.length;
2296     while (l > 0) {
2297         while (l > 1 && (*src == ' ' || *src == DCM_DELIMITOR)) {
2298             l--;
2299             src++;
2300         }
2301         if ((l == 1) && (*src == ' ' || *src == DCM_DELIMITOR))
2302             l--;
2303 
2304         if (l != 0) {
2305             p = CTN_MALLOC(structureSize);
2306             if (p == NULL)
2307                 return COND_PushCondition(DCM_MALLOCFAILURE,
2308                               DCM_Message(DCM_MALLOCFAILURE), structureSize,
2309                                           "DCM_GetElementValueList");
2310             dst = p + stringOffset;
2311             while ((l > 1) && (*src != DCM_DELIMITOR)) {
2312                 *dst++ = *src++;
2313                 l--;
2314             }
2315             if ((l == 1) && (*src != ' ')) {
2316                 *dst++ = *src++;
2317                 l--;
2318             }
2319             *dst = '\0';;
2320             cond = LST_Enqueue(list, p);
2321             if (cond != LST_NORMAL)
2322                 return COND_PushCondition(DCM_LISTFAILURE,
2323                    DCM_Message(DCM_LISTFAILURE), "DCM_GetElementValueList");
2324         }
2325     }
2326     return DCM_NORMAL;
2327 }
2328 
2329 /* DCM_AddElementList
2330 **
2331 ** Purpose:
2332 **      Add an element list to the DICOM object
2333 **
2334 ** Parameter Dictionary:
2335 **      callerObject            Handle to object to which the element is to be
2336 **                              added
2337 **      element                 The element in which the string obtained from
2338 **                              the list is to be stored. Finally the element
2339 **                              is added to the DICOM object.
2340 **      list                    List of structures , each containing a string
2341 **                              starting at some offset specified by the
2342 **                              parameter "offset"
2343 **      offset                  Offset in each individual structure (see
2344 **                              explanation for parameter list)
2345 **
2346 ** Return Values:
2347 **
2348 **      DCM_ILLEGALOBJECT
2349 **      DCM_ILLEGALREPRESENTATION
2350 **      DCM_INSERTFAILED
2351 **      DCM_NORMAL
2352 **      DCM_NULLOBJECT
2353 **
2354 ** Notes:
2355 **
2356 ** Algorithm:
2357 **      Description of the algorithm (optional) and any other notes.
2358 */
2359 CONDITION
2360 DCM_AddElementList(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
2361                    LST_HEAD * list, long offset)
2362 {
2363     DCM_ELEMENT
2364         e;                      /* Local copy of caller's element */
2365     CONDITION
2366         cond;
2367     char
2368        *s;
2369 
2370     e = *element;
2371     cond = DCM_ListToString(list, offset, &s);
2372     if (cond != DCM_NORMAL)
2373         return cond;
2374 
2375     e.d.string = s;
2376     e.length = strlen(s);
2377     cond = DCM_AddElement(callerObject, &e);
2378     CTN_FREE(s);
2379     return cond;
2380 }
2381 
2382 /* DCM_GetElement
2383 **
2384 ** Purpose:
2385 **      Get the element with the specified tag number from the given DICOM
2386 **      object
2387 **
2388 ** Parameter Dictionary:
2389 **      callerObject            Handle to the DICOM object
2390 **      tag                     Tag number of the element to be obtained
2391 **                              from the object
2392 **      element                 The element to be returned
2393 **
2394 ** Return Values:
2395 **
2396 **      DCM_ELEMENTNOTFOUND
2397 **      DCM_ILLEGALOBJECT
2398 **      DCM_NORMAL
2399 **      DCM_NULLOBJECT
2400 **
2401 ** Notes:
2402 **
2403 ** Algorithm:
2404 **      Description of the algorithm (optional) and any other notes.
2405 */
2406 CONDITION
2407 DCM_GetElement(DCM_OBJECT ** callerObject, DCM_TAG tag, DCM_ELEMENT * element)
2408 {
2409     PRIVATE_OBJECT
2410         ** obj;
2411     CONDITION
2412         cond;
2413     PRV_ELEMENT_ITEM
2414         * elementItem;
2415 
2416     obj = (PRIVATE_OBJECT **) callerObject;
2417     cond = checkObject(obj, "DCM_GetElementVM");
2418     if (cond != DCM_NORMAL)
2419         return cond;
2420 
2421     elementItem = locateElement(obj, tag);
2422     if (elementItem == NULL)
2423         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
2424                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
2425                                   DCM_TAG_ELEMENT(tag),
2426                                   "DCM_GetElementVM");
2427     *element = elementItem->element;
2428     element->d.ot = NULL;
2429     return DCM_NORMAL;
2430 }
2431 
2432 CONDITION
2433 DCM_ComputeExportLength(DCM_OBJECT ** callerObject, unsigned long opt,
2434                         unsigned long *length)
2435 {
2436     PRIVATE_OBJECT
2437         ** object;
2438     unsigned char
2439         buf[2048];
2440     CONDITION
2441         cond;
2442 
2443     object = (PRIVATE_OBJECT **) callerObject;
2444     cond = checkObject(object, "DCM_ComputeExportSize");
2445     if (cond != DCM_NORMAL)
2446         return cond;
2447 
2448     *length = 0;
2449     cond = DCM_ExportStream(callerObject, opt, buf,
2450                             (unsigned long) sizeof(buf), countBytes, length);
2451     if (cond != DCM_NORMAL)
2452         return cond;
2453 
2454     return DCM_NORMAL;
2455 }
2456 
2457 CONDITION
2458 DCM_CompareAttributes(DCM_OBJECT ** o1, DCM_OBJECT ** o2,
2459                       void (*callback) (const DCM_ELEMENT * e1,
2460                                         const DCM_ELEMENT * e2,
2461                                         void *ctx),
2462                       void *ctx)
2463 {
2464     PRIVATE_OBJECT **object1,
2465       **object2;
2466     PRV_GROUP_ITEM *groupItem1,
2467        *groupItem2;
2468     CONDITION cond;
2469 
2470     object1 = (PRIVATE_OBJECT **) o1;
2471     cond = checkObject(object1, "DCM_CompareAttributes");
2472     if (cond != DCM_NORMAL)
2473         return cond;
2474 
2475     object2 = (PRIVATE_OBJECT **) o2;
2476     cond = checkObject(object1, "DCM_CompareAttributes");
2477     if (cond != DCM_NORMAL)
2478         return cond;
2479 
2480     groupItem1 = LST_Head(&(*object1)->groupList);
2481     if (groupItem1 != NULL)
2482         (void) LST_Position(&(*object1)->groupList, groupItem1);
2483 
2484     groupItem2 = LST_Head(&(*object2)->groupList);
2485     if (groupItem2 != NULL)
2486         (void) LST_Position(&(*object2)->groupList, groupItem2);
2487 
2488 
2489     while (groupItem1 != NULL) {
2490         if (groupItem2 == NULL) {
2491             compareGroup(groupItem1, NULL, callback, ctx);
2492             groupItem1 = LST_Next(&(*object1)->groupList);
2493         } else if (groupItem1->group == groupItem2->group) {
2494             compareGroup(groupItem1, groupItem2, callback, ctx);
2495             groupItem1 = LST_Next(&(*object1)->groupList);
2496             groupItem2 = LST_Next(&(*object2)->groupList);
2497         } else if (groupItem1->group > groupItem2->group) {
2498             compareGroup(NULL, groupItem2, callback, ctx);
2499             groupItem2 = LST_Next(&(*object2)->groupList);
2500         } else {
2501             groupItem1 = LST_Next(&(*object1)->groupList);
2502             compareGroup(groupItem1, NULL, callback, ctx);
2503         }
2504     }
2505 
2506     while (groupItem2 != NULL) {
2507         compareGroup(NULL, groupItem2, callback, ctx);
2508         groupItem2 = LST_Next(&(*object2)->groupList);
2509     }
2510     return DCM_NORMAL;
2511 }
2512 
2513 
2514 
2515 /*     ------------------------------------------------------------
2516 **  Private functions below here
2517 */
2518 
2519 /* newElementItem
2520 **
2521 ** Purpose:
2522 **      Create a new element item suitable for placing in the linked
2523 **      list representation of an ACR object.  Copy data from an
2524 **      existing element, but skip the actual data field.
2525 **      Describe the purpose of the function
2526 **
2527 ** Parameter Dictionary:
2528 **      src     Pointer to source element that is to be copied
2529 **      dst     Pointer to pointer to destination element which is allocated
2530 **              by this routine and filled in appropriately.
2531 **
2532 ** Return Values:
2533 **      DCM_NORMAL
2534 **      DCM_ELEMENTCREATEFAILED
2535 **
2536 ** Algorithm:
2537 **      Allocate new element item of size:
2538 **              Size PRV_ELEMENT_ITEM + length of data value
2539 **      Copy data from caller's DCM_ELEMENT into newly created
2540 **              PRV_ELEMENT_ITEM.
2541 **      Point data value of newly created PRV_ELEMENT_ITEM to part of the
2542 **      allocated space (just past the end of the PRV_ELEMENT_ITEM).
2543 */
2544 static CONDITION
2545 newElementItem(DCM_ELEMENT * src, CTNBOOLEAN allocateData,
2546                PRV_ELEMENT_ITEM ** dst)
2547 {
2548     U32
2549     l;
2550 
2551     if (allocateData && (src->representation != DCM_SQ)) {
2552         l = src->length;
2553         if (l & 1)
2554             l++;
2555     } else
2556         l = 0;
2557 
2558     if (debug)
2559         fprintf(stderr, "newElementItem: CTN_MALLOC %8d %8d ", l,
2560                 sizeof(PRV_ELEMENT_ITEM) + l);
2561 
2562     *dst = (PRV_ELEMENT_ITEM *) CTN_MALLOC(sizeof(PRV_ELEMENT_ITEM) + l);
2563     if (debug)
2564         fprintf(stderr, "%8x\n", *dst);
2565 
2566     if (*dst == NULL) {
2567         return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
2568                      DCM_Message(DCM_ELEMENTCREATEFAILED), "newElementItem",
2569                                   DCM_TAG_GROUP(src->tag),
2570                                   DCM_TAG_ELEMENT(src->tag),
2571                                   l);
2572     }
2573     memset(*dst, 0, sizeof(PRV_ELEMENT_ITEM));
2574     (*dst)->element = *src;
2575     (*dst)->byteOrder = NATIVE_ORDER;
2576     (*dst)->allocatedDataLength = (size_t) l;
2577     (*dst)->originalDataLength = src->length;
2578     (*dst)->paddedDataLength = src->length;
2579     if (allocateData)
2580         (*dst)->element.d.ot = ((char *) (*dst)) + sizeof(PRV_ELEMENT_ITEM);
2581     else
2582         (*dst)->element.d.ot = NULL;
2583 
2584     return DCM_NORMAL;
2585 }
2586 
2587 /* findCreateGroup
2588 **
2589 ** Purpose:
2590 **      Find the group in the DCM object corresponding to the group
2591 **      passed by the caller.  If the group does not yet exist, create
2592 **      a new group.  Set the CURRENT pointer in the linked list
2593 **      to point at that group.
2594 **
2595 ** Parameter Dictionary:
2596 **      object          Pointer to caller's DCM object
2597 **      group           Group number to locate/create
2598 **      groupPtr        Mechanism for returning pointer to located group
2599 **
2600 ** Return Values:
2601 **
2602 **      DCM_ELEMENTCREATEFAILED
2603 **      DCM_LISTFAILURE
2604 **      DCM_NORMAL
2605 **
2606 ** Algorithm:
2607 **      Set ITEM to head of linked list of ACR object
2608 **      Set CURRENT item in linked list to ITEM
2609 **      Search sequentially through linked list until:
2610 **          - Reach exisiting group that matches caller's group
2611 **          - Reach a group with larger group number than caller's group
2612 **          - Reach end of linked list
2613 **      Each time you move to a new item, update CURRENT to point to that item
2614 **      If reached existing group
2615 **          return
2616 **      If reached a group with larger group number than caller's group,
2617 **          Insert new group with Group Length Element (0000) just before
2618 **          the group with the larger group number.
2619 **          Set CURRENT pointer in linked list to point at new group
2620 **          If group is COMMAND or IDENTIFYING,
2621 **              Insert Length to End Element
2622 **          Return
2623 **      If reached end of the linked list
2624 **          Append new group with Group Length Element (0000) to the end
2625 **          of the linked list.
2626 **          Set CURRENT pointer in linked list to point at new group
2627 **          If group is COMMAND or IDENTIFYING,
2628 **              Insert Length to End Element
2629 **          Return
2630 **
2631 */
2632 
2633 static CONDITION
2634 findCreateGroup(PRIVATE_OBJECT ** object, unsigned short group,
2635                 PRV_GROUP_ITEM ** groupItem)
2636 {
2637     PRV_GROUP_ITEM
2638     * item;
2639     CONDITION
2640         cond;
2641     CTNBOOLEAN
2642         tooFar = FALSE;
2643 
2644     item = LST_Head(&(*object)->groupList);
2645     if (item != NULL)
2646         (void) LST_Position(&(*object)->groupList, item);
2647 
2648     while (item != NULL && !tooFar) {
2649         if (item->group == group) {
2650             *groupItem = item;
2651             return DCM_NORMAL;
2652         } else if (item->group > group) {
2653             tooFar = TRUE;
2654         } else {
2655             item = LST_Next(&(*object)->groupList);
2656         }
2657     }
2658 
2659     {
2660         U32 l;
2661         PRV_GROUP_ITEM *newGroupItem;
2662         DCM_ELEMENT groupLength = {0, DCM_UL, "", 1, sizeof(l), NULL};
2663         PRV_ELEMENT_ITEM *groupLengthItem;
2664 
2665         newGroupItem = CTN_MALLOC(sizeof(*newGroupItem));
2666         if (newGroupItem == NULL)
2667             return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
2668                                       DCM_Message(DCM_ELEMENTCREATEFAILED),
2669                                       "findCreateGroup",
2670                                       group, 0xffff, sizeof(*newGroupItem));
2671 
2672 
2673         *groupItem = newGroupItem;
2674         newGroupItem->group = group;
2675         newGroupItem->baseLength = 0;
2676         newGroupItem->longVRAttributes = 0;
2677         newGroupItem->elementList = LST_Create();
2678         if (newGroupItem->elementList == NULL)
2679             return COND_PushCondition(DCM_LISTFAILURE,
2680                                       DCM_Message(DCM_LISTFAILURE),
2681                                       "findCreateGroup");
2682 
2683         if (tooFar)
2684             cond = LST_Insert(&(*object)->groupList, newGroupItem, LST_K_BEFORE);
2685         else
2686             cond = LST_Enqueue(&(*object)->groupList, newGroupItem);
2687         if (cond != LST_NORMAL)
2688             return COND_PushCondition(DCM_LISTFAILURE,
2689                                       DCM_Message(DCM_LISTFAILURE),
2690                                       "findCreateGroup");
2691         (void) LST_Position(&(*object)->groupList, newGroupItem);
2692         if (cond != LST_NORMAL)
2693             return COND_PushCondition(DCM_LISTFAILURE,
2694                                       DCM_Message(DCM_LISTFAILURE),
2695                                       "findCreateGroup");
2696 
2697         groupLength.d.ul = &l;
2698         l = 0;
2699         if ((*object)->groupLengthFlag) {
2700             groupLength.tag = DCM_MAKETAG(group, 0);
2701             cond = newElementItem(&groupLength, TRUE, &groupLengthItem);
2702             (void) memcpy(groupLengthItem->element.d.ot, &l, sizeof(l));
2703 
2704             if (LST_Insert(&newGroupItem->elementList, groupLengthItem, LST_K_AFTER) !=
2705                 LST_NORMAL)
2706                 return COND_PushCondition(DCM_LISTFAILURE,
2707                                           DCM_Message(DCM_LISTFAILURE),
2708                                           "findCreateGroup");
2709 
2710             (*object)->objectSize += 8 + groupLengthItem->element.length;
2711         }
2712     }
2713     return DCM_NORMAL;
2714 }
2715 
2716 /* insertNewElement
2717 **
2718 ** Purpose:
2719 **      Create a new DCM_ELEMENT item using a copy of the caller's
2720 **      DCM_ELEMENT and insert it into the ACR object's linked list.
2721 **
2722 ** Parameter Dictionary:
2723 **      object          Pointer to caller's ACR_OBJECT
2724 **      element         Pointer to caller's ACR_ELEMENT to be copied
2725 **                      and inserted into linked list.
2726 **
2727 ** Return Values:
2728 **
2729 **      DCM_ELEMENTCREATEFAILED
2730 **      DCM_LISTFAILURE
2731 **      DCM_NORMAL
2732 **      DCM_UNEVENELEMENTLENGTH
2733 **      DCM_BADELEMENTINGROUP
2734 **
2735 ** Algorithm:
2736 **      Call newElementItem to create a copy of the DCM_ELEMENT
2737 **      Copy caller's data into data area allocated by newElementItem
2738 **      Increment object's OBJECTSIZE field by size of new element
2739 **      Use CURRENT pointer in DCM object linked list to get pointer
2740 **      to the group where we insert this element
2741 **      Update Group Length by adding size of new element
2742 **      Search sequentially through linked list until we reach:
2743 **          - End of linked list
2744 **          - A different group
2745 **          - An element in the same group with a larger element number
2746 **      If reached end of linked list
2747 **          Append new ACR_ELEMENTITEM to end of linked list
2748 **      If reached a different group
2749 **          Insert new ACR_ELEMENTITEM just before new group
2750 **      If reached an element in the same group with a larger element number
2751 **          Insert new ACR_ELEMENTITEM just before the "larger" element
2752 */
2753 static CONDITION
2754 insertNewElement(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
2755 {
2756     PRV_ELEMENT_ITEM
2757     * nextItem,
2758     *newItem;
2759     PRV_GROUP_ITEM
2760         * groupItem;
2761     CONDITION
2762         cond;
2763     char
2764        *p;
2765 
2766     cond = newElementItem(element, TRUE, &newItem);
2767     if (cond != DCM_NORMAL) {
2768         return cond;
2769     }
2770     newItem->byteOrder = DCM_ORDERNATIVE;
2771     if ((newItem->element.length & 1) != 0) {
2772         if (newItem->element.representation == DCM_AE) {
2773             p = newItem->element.d.string;      /* repair, check for 16 */
2774             p[newItem->element.length] = ' ';
2775             newItem->paddedDataLength = element->length + 1;
2776             (void) memcpy(p, element->d.string, element->length);
2777         } else if (newItem->element.representation == DCM_AS) {
2778             p = newItem->element.d.string;
2779             p[newItem->element.length] = ' ';
2780             newItem->paddedDataLength = element->length + 1;
2781             (void) memcpy(p, element->d.string, element->length);
2782         } else if (newItem->element.representation == DCM_CS) {
2783             p = newItem->element.d.string;
2784             p[newItem->element.length] = ' ';
2785             newItem->paddedDataLength = element->length + 1;
2786             (void) memcpy(p, element->d.string, element->length);
2787         } else if (newItem->element.representation == DCM_DA) {
2788             p = newItem->element.d.string;
2789             p[newItem->element.length] = ' ';
2790             newItem->paddedDataLength = element->length + 1;
2791             (void) memcpy(p, element->d.string, element->length);
2792         } else if (newItem->element.representation == DCM_DS) {
2793             p = newItem->element.d.string;
2794             p[newItem->element.length] = ' ';
2795             newItem->paddedDataLength = element->length + 1;
2796             (void) memcpy(p, element->d.string, element->length);
2797         } else if (newItem->element.representation == DCM_IS) {
2798             p = newItem->element.d.string;
2799             p[newItem->element.length] = ' ';
2800             newItem->paddedDataLength = element->length + 1;
2801             (void) memcpy(p, element->d.string, element->length);
2802         } else if (newItem->element.representation == DCM_LT) {
2803             p = newItem->element.d.string;
2804             p[newItem->element.length] = ' ';
2805             newItem->paddedDataLength = element->length + 1;
2806             (void) memcpy(p, element->d.string, element->length);
2807         } else if (newItem->element.representation == DCM_LO) {
2808             p = newItem->element.d.string;
2809             p[newItem->element.length] = ' ';
2810             newItem->paddedDataLength = element->length + 1;
2811             (void) memcpy(p, element->d.string, element->length);
2812         } else if (newItem->element.representation == DCM_PN) {
2813             p = newItem->element.d.string;
2814             p[newItem->element.length] = ' ';
2815             newItem->paddedDataLength = element->length + 1;
2816             (void) memcpy(p, element->d.string, element->length);
2817         } else if (newItem->element.representation == DCM_SH) {
2818             p = newItem->element.d.string;
2819             p[newItem->element.length] = ' ';
2820             newItem->paddedDataLength = element->length + 1;
2821             (void) memcpy(p, element->d.string, element->length);
2822         } else if (newItem->element.representation == DCM_ST) {
2823             p = newItem->element.d.string;
2824             p[newItem->element.length] = ' ';
2825             newItem->paddedDataLength = element->length + 1;
2826             (void) memcpy(p, element->d.string, element->length);
2827         } else if (newItem->element.representation == DCM_TM) {
2828             p = newItem->element.d.string;
2829             p[newItem->element.length] = ' ';
2830             newItem->paddedDataLength = element->length + 1;
2831             (void) memcpy(p, element->d.string, element->length);
2832         } else if (newItem->element.representation == DCM_UI) {
2833             p = newItem->element.d.string;
2834             p[newItem->element.length] = '\0';
2835             newItem->paddedDataLength = element->length + 1;
2836             (void) memcpy(p, element->d.string, element->length);
2837         } else if (newItem->element.representation == DCM_SQ) {
2838 /*          newItem->element.length = 0xffffffff; */
2839             newItem->element.d.sq = element->d.sq;
2840         } else {
2841             CTN_FREE(newItem);
2842             return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
2843                                       DCM_Message(DCM_UNEVENELEMENTLENGTH),
2844                                       DCM_TAG_GROUP(element->tag),
2845                              DCM_TAG_ELEMENT(element->tag), element->length,
2846                                       "insertNewElement");
2847         }
2848     } else if (newItem->element.representation != DCM_SQ) {
2849         (void) memcpy(newItem->element.d.ot, element->d.ot, element->length);
2850     } else {
2851 /*      newItem->element.length = 0xffffffff; */
2852         newItem->element.d.sq = element->d.sq;
2853     }
2854     if ((*object)->objectSize != DCM_UNSPECIFIEDLENGTH)
2855         (*object)->objectSize += 8 + newItem->paddedDataLength;
2856 
2857 /* repair */
2858     cond = updateSpecialElements(object, newItem);
2859     if (cond != DCM_NORMAL)
2860         return cond;
2861 
2862     groupItem = LST_Current(&(*object)->groupList);
2863     if (groupItem == NULL)
2864         return COND_PushCondition(DCM_LISTFAILURE,
2865                           DCM_Message(DCM_LISTFAILURE), "insertNewElement");
2866 
2867     if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH)
2868         groupItem->baseLength += 2 + 2 + 4 + newItem->paddedDataLength;
2869 
2870     if (newItem->element.representation == DCM_OW ||
2871         newItem->element.representation == DCM_OB ||
2872         newItem->element.representation == DCM_SQ) {
2873         groupItem->longVRAttributes++;
2874         (*object)->longVRAttributes++;
2875     }
2876     if ((nextItem = LST_Head(&groupItem->elementList)) == NULL) {
2877         cond = LST_Enqueue(&groupItem->elementList, newItem);
2878         if (cond != LST_NORMAL)
2879             return COND_PushCondition(DCM_LISTFAILURE,
2880                                       DCM_Message(DCM_LISTFAILURE),
2881                                       "insertNewElement");
2882         else
2883             return DCM_NORMAL;
2884     }
2885     (void) LST_Position(&groupItem->elementList, nextItem);
2886     if (DCM_TAG_ELEMENT(nextItem->element.tag) == 0x0000)
2887         (void) memcpy(nextItem->element.d.ot, &groupItem->baseLength,
2888                       sizeof(groupItem->baseLength));
2889 
2890 /*  Now, search through the linked list for a place to insert/append
2891 **  this new item.
2892 */
2893 
2894     while (nextItem != NULL) {
2895         if (DCM_TAG_GROUP(element->tag) !=
2896             DCM_TAG_GROUP(nextItem->element.tag)) {
2897             return COND_PushCondition(DCM_BADELEMENTINGROUP,
2898                                       DCM_Message(DCM_BADELEMENTINGROUP),
2899                                       DCM_TAG_GROUP(nextItem->element.tag),
2900                                       DCM_TAG_ELEMENT(nextItem->element.tag),
2901                                       groupItem->group, "insertNewElement");
2902         } else if (DCM_TAG_ELEMENT(element->tag) <
2903                    DCM_TAG_ELEMENT(nextItem->element.tag)) {
2904             cond = LST_Insert(&groupItem->elementList, newItem, LST_K_BEFORE);
2905             if (cond != LST_NORMAL)
2906                 return COND_PushCondition(DCM_LISTFAILURE,
2907                                           DCM_Message(DCM_LISTFAILURE),
2908                                           "insertNewElement");
2909             else
2910                 return DCM_NORMAL;
2911         }
2912         nextItem = LST_Next(&groupItem->elementList);
2913     }
2914 
2915 /*  If we fall out of the loop, we must have reached the end of
2916 **  the group.  Add the element to the end of the list of elements
2917 **  in this group.
2918 */
2919 
2920     cond = LST_Enqueue(&groupItem->elementList, newItem);
2921     if (cond != LST_NORMAL)
2922         return COND_PushCondition(DCM_LISTFAILURE,
2923                                   DCM_Message(DCM_LISTFAILURE),
2924                                   "insertNewElement");
2925     else
2926         return DCM_NORMAL;
2927 }
2928 
2929 /* updateObjectType
2930 **
2931 ** Purpose:
2932 **      Possibly modify the objectType field of an DCM object to identify
2933 **      the object as COMMAND, DATASET or MESSAGE.
2934 **
2935 ** Parameter Dictionary:
2936 **      object          Pointer to caller's PRIVATE object to be updated
2937 **      element         Pointer to DCM_ELEMENT which will be added to
2938 **                      the object and possibly cause a change in the
2939 **                      type of the object.
2940 **
2941 ** Return Values:
2942 **      DCM_NORMAL
2943 **
2944 ** Algorithm:
2945 **      Description of the algorithm (optional) and any other notes.
2946 */
2947 
2948 static CONDITION
2949 updateObjectType(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
2950 {
2951     switch ((*object)->objectType) {
2952         case DCM_OBJECTUNKNOWN:
2953         if (DCM_TAG_GROUP(element->tag) == DCM_GROUPCOMMAND)
2954             (*object)->objectType = DCM_OBJECTCOMMAND;
2955         else
2956             (*object)->objectType = DCM_OBJECTELEMENTLIST;
2957         break;
2958     case DCM_OBJECTCOMMAND:
2959         if (DCM_TAG_GROUP(element->tag) != DCM_GROUPCOMMAND)
2960             (*object)->objectType = DCM_OBJECTELEMENTLIST;
2961         break;
2962     case DCM_OBJECTELEMENTLIST:
2963     case DCM_OBJECTIMAGE:
2964         break;
2965     default:
2966         break;
2967     }
2968     return DCM_NORMAL;
2969 }
2970 
2971 /* updateSpecialElements
2972 **
2973 ** Purpose:
2974 **      Update special elements in a DICOM object when a new data element
2975 **      is added to the object.  These special fields are used by other
2976 **      parts of the package which have to refer to those fields and wish
2977 **      to do so without searching through the entire list.  This could
2978 **      get messy and is a candidate for redesign.
2979 **
2980 ** Parameter Dictionary:
2981 **      object          Pointer to caller's PRIVATE DICOM object
2982 **      element         Pointer to DCM_ELEMENT that is being added to
2983 **                      the DICOM object
2984 **
2985 ** Return Values:
2986 **      DCM_NORMAL
2987 **
2988 ** Algorithm:
2989 **      Description of the algorithm (optional) and any other notes.
2990 */
2991 static CONDITION
2992 updateSpecialElements(PRIVATE_OBJECT ** object,
2993                       PRV_ELEMENT_ITEM * item)
2994 {
2995     int idx;
2996 
2997     switch (item->element.tag) {
2998     case DCM_IMGBITSALLOCATED:
2999         (*object)->pixelBitsAllocated = *item->element.d.us;
3000         break;
3001     case DCM_IMGPIXELREPRESENTATION:
3002         (*object)->pixelRepresentation = *item->element.d.us;
3003         break;
3004     case DCM_METAGROUPLENGTH:
3005         (*object)->metaHeaderLength = *item->element.d.ul;
3006         break;
3007     case DCM_METATRANSFERSYNTAX:
3008         if (strcmp(item->element.d.string, DICOM_TRANSFERLITTLEENDIAN) == 0) {
3009             (*object)->dataOptions = DCM_ORDERLITTLEENDIAN;
3010         } else if (strcmp(item->element.d.string, DICOM_TRANSFERLITTLEENDIANEXPLICIT) == 0) {
3011             (*object)->dataOptions = DCM_EXPLICITLITTLEENDIAN;
3012         } else if (strcmp(item->element.d.string, DICOM_TRANSFERBIGENDIANEXPLICIT) == 0) {
3013             (*object)->dataOptions = DCM_EXPLICITBIGENDIAN;
3014         }
3015         break;
3016     case DCM_MAKETAG(0x003a, 0x0103):
3017         strncpy((*object)->waveformDataVR, item->element.d.string,
3018                 item->element.length);
3019         (*object)->waveformDataVR[item->element.length] = '\0';
3020         idx = item->element.length - 1;
3021         while (idx >= 0 && (*object)->waveformDataVR[idx] == ' ') {
3022             (*object)->waveformDataVR[idx] = '\0';
3023             idx--;
3024         }
3025         break;
3026     default:
3027         break;
3028     }
3029     return DCM_NORMAL;
3030 }
3031 
3032 typedef struct {
3033     DCM_VALUEREPRESENTATION representation;
3034     char code[3];
3035 }   VRMAP;
3036 
3037 static VRMAP vrMap[] = {
3038     {DCM_AE, "AE"},
3039     {DCM_AS, "AS"},
3040     {DCM_AT, "AT"},
3041     {DCM_CS, "CS"},
3042     {DCM_DA, "DA"},
3043     {DCM_DD, "DD"},
3044     {DCM_DS, "DS"},
3045     {DCM_FD, "FD"},
3046     {DCM_FL, "FL"},
3047     {DCM_IS, "IS"},
3048     {DCM_LO, "LO"},
3049     {DCM_LT, "LT"},
3050     {DCM_OT, "OT"},
3051     {DCM_SH, "SH"},
3052     {DCM_SL, "SL"},
3053     {DCM_SQ, "SQ"},
3054     {DCM_SS, "SS"},
3055     {DCM_ST, "ST"},
3056     {DCM_TM, "TM"},
3057     {DCM_UI, "UI"},
3058     {DCM_UL, "UL"},
3059     {DCM_US, "US"},
3060     {DCM_UNKNOWN, "UK"},
3061     {DCM_RET, "RT"},
3062     {DCM_CTX, "  "},
3063     {DCM_PN, "PN"},
3064     {DCM_OB, "OB"},
3065     {DCM_OW, "OW"},
3066     {DCM_DT, "DT"},
3067     {DCM_DLM, ""}
3068 };
3069 
3070 static VRMAP *
3071 lookupVRCode(const char *code)
3072 {
3073     int i;
3074 
3075     for (i = 0; i < (int) DIM_OF(vrMap); i++) {
3076         if (strcmp(code, vrMap[i].code) == 0)
3077             return &vrMap[i];
3078     }
3079 
3080     return NULL;
3081 }
3082 
3083 static void
3084 mapVRtoASCII(DCM_VALUEREPRESENTATION vr, char *s)
3085 {
3086     int i;
3087 
3088     for (i = 0; i < (int) DIM_OF(vrMap); i++) {
3089         if (vr == vrMap[i].representation) {
3090             strcpy(s, vrMap[i].code);
3091             return;
3092         }
3093     }
3094 
3095     strcpy(s, "");
3096     return;
3097 }
3098 
3099 static void
3100 exportVRLength(DCM_ELEMENT * e, unsigned char *b, int byteOrder,
3101                U32 * rtnLength)
3102 {
3103     int i;
3104     char *c = "xx";
3105     unsigned char *p;
3106     U16 shortLength;
3107     DCM_VALUEREPRESENTATION vr;
3108 
3109     vr = e->representation;
3110     if (e->tag == DCM_MAKETAG(0x003a, 0x1000))
3111         vr = DCM_OB;
3112 
3113     for (i = 0; i < DIM_OF(vrMap); i++) {
3114         if (vr == vrMap[i].representation) {
3115             c = vrMap[i].code;
3116             break;
3117         }
3118     }
3119 
3120     *b++ = *c++;
3121     *b++ = *c++;
3122     *rtnLength += 2;
3123 
3124     if (vr == DCM_OB || vr == DCM_OW || vr == DCM_SQ) {
3125         *b++ = 0x00;
3126         *b++ = 0x00;
3127         if (byteOrder == BYTEORDER_SAME) {
3128             p = (unsigned char *) &e->length;
3129             *b++ = *p++;
3130             *b++ = *p++;
3131             *b++ = *p++;
3132             *b++ = *p++;
3133         } else {
3134             p = (unsigned char *) &e->length;
3135             *b++ = p[3];
3136             *b++ = p[2];
3137             *b++ = p[1];
3138             *b++ = p[0];
3139         }
3140         *rtnLength += 6;
3141     } else {
3142         shortLength = (U16) e->length;
3143         if (byteOrder == BYTEORDER_SAME) {
3144             p = (unsigned char *) &shortLength;
3145             *b++ = *p++;
3146             *b++ = *p++;
3147         } else {
3148             p = (unsigned char *) &shortLength;
3149             *b++ = p[1];
3150             *b++ = p[0];
3151         }
3152         *rtnLength += 2;
3153     }
3154 }
3155 
3156 static CONDITION
3157 exportPreamble(PRIVATE_OBJECT ** obj, unsigned char *dst,
3158                U32 bufferLength, U32 * rtnLength)
3159 {
3160     *rtnLength = 0;
3161     if (bufferLength < (DCM_PREAMBLELENGTH + 4))
3162         return COND_PushCondition(DCM_EXPORTBUFFERTOOSMALL,
3163                   DCM_Message(DCM_EXPORTBUFFERTOOSMALL), (int) bufferLength,
3164                                   "exportPreamble");
3165 
3166     (void) memcpy(dst, (*obj)->preamble, DCM_PREAMBLELENGTH);
3167     dst += DCM_PREAMBLELENGTH;
3168     (void) memcpy(dst, "DICM", 4);
3169     *rtnLength += DCM_PREAMBLELENGTH + 4;
3170 
3171     return DCM_NORMAL;
3172 }
3173 
3174 /* exportFixedFields
3175 **
3176 ** Purpose:
3177 **      This function exports the fixed length fields of an DCM_ELEMENT
3178 **      to the caller's buffer if there is sufficient space in the
3179 **      caller's buffer.
3180 **
3181 ** Parameter Dictionary:
3182 **      element         Pointer to the actual data element to be exported
3183 **      b               Pointer to the caller's buffer to hold exported data
3184 **      length          Length of the remaining space in the caller's
3185 **                      buffer
3186 **      byteOrder       flag giving the order of the bytes as they are
3187 **                      exported.  Should be one of:
3188 **                              BYTEORDER_SAME
3189 **                              BYTEORDER_REVERSE
3190 **      rtnLength       Pointer to caller variable to hold the length
3191 **                      of the data exported.  The length of the data
3192 **                      exported will be 0 if the caller's buffer is
3193 **                      too small to hold the fixed length fields.
3194 **
3195 ** Return Values:
3196 **      None
3197 **
3198 ** Algorithm:
3199 **      If caller buffer is too small to hold all fixed length fields
3200 **          Place 0 in caller's rtnLength variable
3201 **          return
3202 **      Else
3203 **          If byteOrder is the same
3204 **              Copy fixed length fields in same byte order
3205 **          Else
3206 **              Copy fixed length fields in reverse byte order
3207 **          Set caller's rtnLength variable to 8 (short, short, long)
3208 */
3209 
3210 static void
3211 exportFixedFields(DCM_ELEMENT * e,
3212                   unsigned char *b, U32 length, int byteOrder,
3213                   CTNBOOLEAN explicitVR, U32 * rtnLength)
3214 {
3215     unsigned char
3216        *p;
3217     unsigned short
3218         group,
3219         element;
3220     U32
3221         minimumLength;
3222 
3223     group = DCM_TAG_GROUP(e->tag);
3224     element = DCM_TAG_ELEMENT(e->tag);
3225     if (e->representation == DCM_DLM)
3226         explicitVR = FALSE;
3227 
3228     minimumLength = sizeof(group) + sizeof(element) + sizeof(e->length);
3229     if (explicitVR)
3230         minimumLength += 4;
3231 
3232     *rtnLength = 0;
3233     if (length >= minimumLength) {
3234         if (byteOrder == BYTEORDER_SAME) {
3235             p = (unsigned char *) &group;
3236             *b++ = *p++;
3237             *b++ = *p++;
3238             p = (unsigned char *) &element;
3239             *b++ = *p++;
3240             *b++ = *p++;
3241             *rtnLength += 4;
3242             if (explicitVR) {
3243                 exportVRLength(e, b, byteOrder, rtnLength);
3244             } else {
3245                 p = (unsigned char *) &e->length;
3246                 *b++ = *p++;
3247                 *b++ = *p++;
3248                 *b++ = *p++;
3249                 *b++ = *p++;
3250                 *rtnLength += 4;
3251             }
3252         } else {
3253             p = (unsigned char *) &group;
3254             *b++ = p[1];
3255             *b++ = p[0];
3256             p = (unsigned char *) &element;
3257             *b++ = p[1];
3258             *b++ = p[0];
3259             *rtnLength += 4;
3260             if (explicitVR) {
3261                 exportVRLength(e, b, byteOrder, rtnLength);
3262             } else {
3263                 p = (unsigned char *) &e->length;
3264                 *b++ = p[3];
3265                 *b++ = p[2];
3266                 *b++ = p[1];
3267                 *b++ = p[0];
3268                 *rtnLength += 4;
3269             }
3270         }
3271     }
3272 }
3273 
3274 /* exportData
3275 **
3276 ** Purpose:
3277 **      Export the data part of a DCM_ELEMENT.  This function exports
3278 **      all or part of the data portion of an DCM_ELEMENT in the byte order
3279 **      requested by the caller.  The caller specifies the byte order
3280 **      in a formal argument.  The function uses context information to
3281 **      know where to start the export in one data element.  The function
3282 **      does not update the context information but does return the
3283 **      number of bytes exported.
3284 **
3285 ** Parameter Dictionary:
3286 **      object          Pointer to the caller's ACR object which is
3287 **                      being exported.
3288 **      element         Pointer to the ACR_ELEMENT that is being exported
3289 **      b               Pointer to the caller's buffer to hold the
3290 **                      exported data.
3291 **      length          Length of the caller's buffer to hold the data.
3292 **      byteOrder       Flag giving the order of the bytes in the exported
3293 **                      stream.  Flag should be one of:
3294 **                          BYTEORDER_SAME
3295 **                          BYTEORDER_REVERSE
3296 **      rtnLength       Pointer to caller variable to hold number of bytes
3297 **                      that are actually exported.
3298 **
3299 ** Return Values:
3300 **
3301 **      DCM_FILEACCESSERROR
3302 **      DCM_NORMAL
3303 **
3304 ** Algorithm
3305 **
3306 **      Set caller's rtnLength variable to 0
3307 **      Export data based on representation of data element
3308 **      CASE 16 bit binary:
3309 **          While (length >= 2)
3310 **              If (byte order is same OR element is 8 bit pixel data)
3311 **                  Copy 2 bytes to output area
3312 **                  Increment input/output pointers by 2
3313 **              Else
3314 **                  Copy and swap 2 bytes to output area
3315 **                  Increment input/output pointers by 2
3316 **              Endif
3317 **              Decrement length by 2
3318 **              Increment caller's rtnLength by 2
3319 **          End while
3320 **
3321 **      CASE 32 bit binary:
3322 **          While (length >= 4)
3323 **              If (byte order is same)
3324 **                  Copy 4 bytes to output area
3325 **                  Increment input/output pointers by 4
3326 **              Else
3327 **                  Copy and swap 4 bytes to output area
3328 **                  Increment input/output pointers by 4
3329 **              Endif
3330 **              Decrement length by 4
3331 **              Increment caller's rtnLength by 4
3332 **
3333 **      CASE ascii text, ascii numeric, or unknown:
3334 **          Use memcpy to copy as of the remaining data as will fit
3335 **              in the caller's buffer.
3336 **          Set caller's rtnLength to the amount of data copied.
3337 **
3338 */
3339 union {
3340     unsigned short sh[2];
3341     unsigned char ch[4];
3342 }   groupElement;
3343 
3344 static CONDITION
3345 exportData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
3346            unsigned char *src,
3347            unsigned char *b, U32 length, int byteOrder,
3348            U32 * rtnLength)
3349 {
3350 /* repair OT for pixel data*/
3351     unsigned char
3352        *p;
3353     DCM_TAG
3354         * tag;
3355     DCM_ELEMENT
3356         * element;
3357     int nBytes;
3358     CONDITION cond;
3359 
3360     element = &item->element;
3361 
3362     *rtnLength = 0;
3363     if (element->d.ot == NULL) {
3364         if ((*object)->fd != -1) {
3365             (void) lseek((*object)->fd, item->currentOffset, SEEK_SET);
3366             nBytes = read((*object)->fd, b, (int) length);
3367         } else {
3368             (*object)->sk((*object)->userCtx, item->currentOffset, SEEK_SET);
3369             cond = (*object)->rd((*object)->userCtx, b, (long) length, &nBytes);
3370         }
3371         if ((U32) nBytes != length) {
3372             char b[512];
3373             sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
3374             (void) COND_PushCondition(DCM_GENERALWARNING,
3375                           DCM_Message(DCM_GENERALWARNING), "exportData", b);
3376             return COND_PushCondition(DCM_FILEACCESSERROR,
3377                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
3378                                       "exportData");
3379         }
3380 #ifdef LITTLE_ENDIAN_ARCHITECTURE
3381         if (item->element.representation == DCM_AT) {
3382             DCM_ELEMENT e;
3383             e = *element;
3384             e.length = length;
3385             e.d.ot = b;
3386             swapATGroupElement(&e);
3387         }
3388 #endif
3389         if (byteOrder != item->byteOrder) {
3390             DCM_ELEMENT e;
3391             e = *element;
3392             e.length = length;
3393             e.d.ot = b;
3394             swapInPlace(object, &e);
3395         }
3396         *rtnLength = (U32) nBytes;
3397         item->currentOffset += nBytes;
3398     } else {
3399         p = src;
3400         switch (element->representation) {
3401         case DCM_AE:
3402         case DCM_AS:
3403         case DCM_CS:
3404         case DCM_DA:
3405         case DCM_DT:
3406         case DCM_DD:
3407         case DCM_DS:
3408         case DCM_FD:
3409         case DCM_IS:
3410         case DCM_LO:
3411         case DCM_LT:
3412         case DCM_OB:
3413         case DCM_OT:
3414         case DCM_PN:
3415         case DCM_SH:
3416         case DCM_SQ:
3417         case DCM_ST:
3418         case DCM_TM:
3419         case DCM_UI:
3420             (void) memcpy(b, p, length);
3421             *rtnLength = length;
3422             break;
3423         case DCM_AT:
3424             tag = (DCM_TAG *) p;
3425             while (length >= 4) {
3426                 groupElement.sh[0] = DCM_TAG_GROUP(*tag);
3427                 groupElement.sh[1] = DCM_TAG_ELEMENT(*tag);
3428                 if (byteOrder == BYTEORDER_SAME) {
3429                     *b++ = groupElement.ch[0];  /* Copy the group */
3430                     *b++ = groupElement.ch[1];
3431                     *b++ = groupElement.ch[2];  /* Now, the element */
3432                     *b++ = groupElement.ch[3];
3433                 } else {
3434                     *b++ = groupElement.ch[1];  /* Copy the group */
3435                     *b++ = groupElement.ch[0];
3436                     *b++ = groupElement.ch[3];  /* Now, the element */
3437                     *b++ = groupElement.ch[2];
3438                 }
3439                 tag++;
3440                 length -= 4;
3441                 *rtnLength += 4;
3442             }
3443             break;
3444         case DCM_SL:
3445         case DCM_UL:
3446         case DCM_FL:
3447             while (length >= 4) {
3448                 if (byteOrder == BYTEORDER_SAME) {
3449                     *b++ = *p++;
3450                     *b++ = *p++;
3451                     *b++ = *p++;
3452                     *b++ = *p++;
3453                 } else {
3454                     *b++ = p[3];
3455                     *b++ = p[2];
3456                     *b++ = p[1];
3457                     *b++ = p[0];
3458                     p += 4;
3459                 }
3460                 length -= 4;
3461                 *rtnLength += 4;
3462             }
3463             break;
3464         case DCM_SS:
3465         case DCM_US:
3466         case DCM_OW:
3467             /*
3468              * Temorary hack by Nilesh to support memory mapping for testing
3469              * purposes.
3470              */
3471             length &= ~1;
3472             *rtnLength += length;
3473             if (element->tag == DCM_PXLPIXELDATA) {
3474                 if (byteOrder == item->byteOrder)
3475                     (void) memcpy(b, p, length);
3476                 else
3477 #ifdef SOLARIS
3478                     swab((char *) p, (char *) b, length);
3479 #elif defined AIXV3
3480                 swab((short *) p, (short *) b, length);
3481 #elif defined MACOS
3482                 /* Not Yet Defined */
3483 #else
3484                     swab(p, b, length);
3485 #endif
3486             } else {
3487                 if (byteOrder == BYTEORDER_SAME)
3488                     (void) memcpy(b, p, length);
3489                 else
3490 #ifdef SOLARIS
3491                     swab((char *) p, (char *) b, length);
3492 #elif defined AIXV3
3493                 swab((short *) p, (short *) b, length);
3494 #elif defined MACOS
3495                 /* Not Yet Defined */
3496 #else
3497                     swab(p, b, length);
3498 #endif
3499             }
3500             break;
3501         case DCM_UNKNOWN:
3502         default:
3503 #if 0
3504             fprintf(stderr, "Should not get to default in exportData: %08x\n",
3505                     element->tag);
3506 #endif
3507             (void) memcpy(b, p, length);
3508             *rtnLength = length;
3509             break;
3510         }
3511     }
3512     return DCM_NORMAL;
3513 }
3514 
3515 /* fileSize
3516 **
3517 ** Purpose:
3518 **      Determine the file size of a file on an open descriptor.
3519 **
3520 ** Parameter Dictionary:
3521 **      fd      File descriptor for an open file.
3522 **
3523 ** Return Values:
3524 **      the size of the open file in bytes (nonnegative)
3525 **      a negative status value returned by fstat
3526 **
3527 ** Algorithm:
3528 **      call unix fstat system call to get file size.
3529 **      if successful call
3530 **          return file size
3531 **      else
3532 **          return status returned by fstat call (-1)
3533 */
3534 #ifdef MACOS
3535 static long
3536 #else
3537 static int
3538 #endif
3539 fileSize(int fd)
3540 {
3541     int
3542         status;
3543     struct stat
3544         im_stat;
3545 
3546     status = fstat(fd, &im_stat);
3547     if (status < 0) {
3548         return status;
3549     } else
3550         return im_stat.st_size;
3551 }
3552 
3553 /* swapInPlace
3554 **
3555 ** Purpose:
3556 **      Swap data in place for byte order adjustment.  Bytes are swapped
3557 **      for data with representations of DCM_US and DCM_UL (binary values).
3558 **      Special care is taken with pixel data which may be 8 bits.
3559 **
3560 ** Parameter Dictionary:
3561 **      object          Pointer to caller's DCM object containing the
3562 **                      element with the data to be swapped
3563 **      element         Pointer to DCM_ELEMENT that contains the data to be
3564 **                      swapped.
3565 **
3566 ** Return Values:
3567 **      None
3568 **
3569 ** Algorithm:
3570 **      If (element->representation is 16 bit binary)
3571 **          If (element is pixel data and pixel data is not 16 bits)
3572 **              return
3573 **          Swap in place short integers for this element.
3574 **      Else if (element->representation is 32 bit binary)
3575 **          Swap in place long integers for this element
3576 */
3577 
3578 static void
3579 swapInPlace(PRIVATE_OBJECT ** object, DCM_ELEMENT * e)
3580 {
3581     U32
3582     length;
3583     unsigned char
3584         tmp,
3585        *p1;
3586 
3587     length = e->length;
3588     p1 = e->d.ot;
3589     if (e->representation == DCM_US || e->representation == DCM_SS ||
3590         e->representation == DCM_OW || e->representation == DCM_AT) {
3591         if (e->tag == DCM_PXLPIXELDATA &&
3592             (*object)->pixelBitsAllocated != 16)
3593             return;
3594 
3595         while (length > 0) {
3596             tmp = p1[0];
3597             p1[0] = p1[1];
3598             p1[1] = tmp;
3599             p1 += 2;
3600             length -= 2;
3601         }
3602     } else if (e->representation == DCM_UL || e->representation == DCM_SL) {
3603         while (length > 0) {
3604             tmp = p1[0];
3605             p1[0] = p1[3];
3606             p1[3] = tmp;
3607             tmp = p1[1];
3608             p1[1] = p1[2];
3609             p1[2] = tmp;
3610             length -= 4;
3611             p1 += 4;
3612         }
3613     }
3614 }
3615 
3616 
3617 /* checkObject
3618 **
3619 ** Purpose:
3620 **      Examine a PRIVATE OBJECT to see if it looks like is has the proper
3621 **      fields defined.  This function is used to try to make certain that
3622 **      users call the DCM routines with the proper objects.  If the object
3623 **      is legal, the function returns DCM_NORMAL.  If the object is not
3624 **      legal, the function will return an error.
3625 **
3626 ** Parameter Dictionary:
3627 **      object          PRIVATE_OBJECT to be examined by this function
3628 **      caller          Name of the function (ASCIZ) that called this
3629 **                      function.  In case of failure, this becomes part of
3630 **                      the error message that is pushed on the stack.
3631 **
3632 ** Return Values:
3633 **      DCM_NORMAL
3634 **      DCM_NULLOBJECT
3635 **      DCM_ILLEGALOBJECT
3636 **
3637 ** Algorithm:
3638 **      Description of the algorithm (optional) and any other notes.
3639 */
3640 
3641 static CONDITION
3642 checkObject(PRIVATE_OBJECT ** object, char *caller)
3643 {
3644     if (object == NULL)
3645         return COND_PushCondition(DCM_NULLOBJECT, DCM_Message(DCM_NULLOBJECT),
3646                                   caller);
3647     if (*object == NULL)
3648         return COND_PushCondition(DCM_NULLOBJECT, DCM_Message(DCM_NULLOBJECT),
3649                                   caller);
3650 
3651     if (strcmp((*object)->keyType, KEY_DCM_OBJECT) != 0)
3652         return COND_PushCondition(DCM_ILLEGALOBJECT,
3653                                   DCM_Message(DCM_ILLEGALOBJECT), caller);
3654     return DCM_NORMAL;
3655 }
3656 
3657 
3658 /* writeFile
3659 **
3660 ** Purpose:
3661 **      Write the data in the buffer into the file specified by the file
3662 **      descriptor
3663 **
3664 ** Parameter Dictionary:
3665 **      buffer          Buffer holding the information to be written
3666 **      length          Length of the buffer
3667 **      flag            Unused
3668 **      fd              File descriptor
3669 **
3670 ** Return Values:
3671 **
3672 **      DCM_FILEIOERROR
3673 **      DCM_NORMAL
3674 **
3675 ** Notes:
3676 **
3677 ** Algorithm:
3678 **      Description of the algorithm (optional) and any other notes.
3679 */
3680 
3681 static CONDITION
3682 writeFile(void *buffer, U32 length, int flag,
3683           void /* int */ *fdPtr)
3684 {
3685     int
3686         bytesWritten;
3687     int *fd;
3688 
3689     fd = (int *) fdPtr;
3690 
3691     bytesWritten = write(*fd, buffer, (int) length);
3692     if (bytesWritten != (int) length)
3693         return COND_PushCondition(DCM_FILEIOERROR,
3694                           DCM_Message(DCM_FILEIOERROR), "", strerror(errno),
3695                                   "writeFile");
3696     else
3697         return DCM_NORMAL;
3698 }
3699 
3700 static CONDITION
3701 countBytes(void *buffer, U32 length, int flag,
3702            void /* unsigned long */ *sizePtr)
3703 {
3704     unsigned long *size;
3705 
3706     size = (unsigned long *) sizePtr;
3707 
3708     *size += length;
3709 
3710     return DCM_NORMAL;
3711 }
3712 
3713 static CONDITION
3714 setFileOptions(DCM_OBJECT ** obj, unsigned long *opt)
3715 {
3716     CONDITION cond;
3717     char xferSyntax[DICOM_UI_LENGTH + 1];
3718     DCM_ELEMENT e = {DCM_METATRANSFERSYNTAX, DCM_UI, "", 1, sizeof(xferSyntax),
3719     NULL};
3720 
3721     e.d.string = xferSyntax;
3722     cond = DCM_ParseObject(obj, &e, 1, NULL, 0, NULL);
3723     if (cond != DCM_NORMAL)
3724         return cond;
3725 
3726     *opt = 0;
3727     if (strcmp(xferSyntax, DICOM_TRANSFERLITTLEENDIAN) == 0) {
3728         *opt = DCM_ORDERLITTLEENDIAN;
3729     } else if (strcmp(xferSyntax, DICOM_TRANSFERLITTLEENDIANEXPLICIT) == 0) {
3730         *opt = DCM_EXPLICITLITTLEENDIAN;
3731     } else if (strcmp(xferSyntax, DICOM_TRANSFERBIGENDIANEXPLICIT) == 0) {
3732         *opt = DCM_EXPLICITBIGENDIAN;
3733     } else
3734         return 0;               /* repair */
3735 
3736     return DCM_NORMAL;
3737 }
3738 
3739 static CONDITION
3740 extractFileOptions(unsigned long opt, CTNBOOLEAN * part10File,
3741                    CTNBOOLEAN * explicitVR, int *byteOrder)
3742 {
3743     *part10File = *explicitVR = FALSE;
3744 
3745     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
3746         *part10File = TRUE;
3747         opt &= ~DCM_ORDERMASK;
3748         opt |= DCM_EXPLICITLITTLEENDIAN;
3749     }
3750     if ((opt & DCM_ORDERMASK) == 0)
3751         return COND_PushCondition(DCM_ILLEGALOPTION,
3752                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
3753                                   "extractFileOptions");
3754 
3755     switch (opt & DCM_ORDERMASK) {
3756     case DCM_ORDERNATIVE:
3757         *byteOrder = NATIVE_ORDER;
3758         break;
3759     case DCM_ORDERLITTLEENDIAN:
3760         *byteOrder = LITTLE_ORDER;
3761         break;
3762     case DCM_EXPLICITLITTLEENDIAN:
3763         *byteOrder = LITTLE_ORDER;
3764         *explicitVR = TRUE;
3765         break;
3766     case DCM_ORDERBIGENDIAN:
3767         *byteOrder = BIG_ORDER;
3768         break;
3769     case DCM_EXPLICITBIGENDIAN:
3770         *byteOrder = BIG_ORDER;
3771         *explicitVR = TRUE;
3772         break;
3773     default:
3774         *byteOrder = LITTLE_ORDER;
3775         break;
3776     }
3777 
3778     return DCM_NORMAL;
3779 }
3780 
3781 static U32
3782 computeGroupLength(PRV_GROUP_ITEM * groupItem,
3783                    CTNBOOLEAN explicitVR)
3784 {
3785     return (explicitVR) ?
3786     groupItem->baseLength + 4 * groupItem->longVRAttributes :
3787     groupItem->baseLength;
3788 
3789 }
3790 
3791 /* exportStream
3792 **
3793 ** Purpose:
3794 **      Export a DICOM object into the stream format suitable
3795 **      for network transmission or disk storage.
3796 **
3797 ** Parameter Dictionary:
3798 **      callerObject            Handle to caller's DICOM object
3799 **      opt                     Bit mask giving options for exporting data
3800 **      buffer                  Pointer to caller's buffer to hold next chunk
3801 **                              of DCM stream data
3802 **      bufferlength            Length of caller's buffer to hold stream data
3803 **      callback                Callback routine to be called.
3804 **      ctx                     Pointer to context variable we maintain to keep
3805 **                              track of our location in export process.
3806 **      sequenceLevel           Current level in the sequence hierarchy
3807 **
3808 ** Return Values:
3809 **
3810 **      DCM_FILEACCESSERROR
3811 **      DCM_ILLEGALOBJECT
3812 **      DCM_LISTFAILURE
3813 **      DCM_NORMAL
3814 **      DCM_NULLOBJECT
3815 **      DCM_CALLBACKABORTED
3816 **
3817 ** Notes:
3818 **
3819 ** Algorithm:
3820 **      Description of the algorithm (optional) and any other notes.
3821 */
3822 
3823 static CONDITION
3824 exportStream(DCM_OBJECT ** callerObject, unsigned long opt,
3825              void *buffer, U32 bufferlength, CONDITION(*callback) (),
3826              void *ctx, int sequenceLevel)
3827 {
3828     PRIVATE_OBJECT
3829     ** object;
3830     PRV_GROUP_ITEM
3831         * groupItem;
3832     PRV_ELEMENT_ITEM
3833         * elementItem;
3834     DCM_ELEMENT
3835         element;
3836     int
3837         byteOrder;
3838     int
3839         lastFlag = 0;
3840     unsigned char
3841        *src,
3842        *dst;
3843     U32
3844         c,
3845         bytesExported = 0,
3846         rtnLength,
3847         remainingData,
3848         exportLength;
3849     CONDITION
3850         cond;
3851     DCM_SEQUENCE_ITEM
3852         * sequenceItem;
3853     DCM_ELEMENT
3854         itemMarker = {
3855         DCM_DLMITEM, DCM_DLM, "", 1, DCM_UNSPECIFIEDLENGTH, NULL
3856     },
3857         itemDelimiter = {
3858         DCM_DLMITEMDELIMITATIONITEM, DCM_DLM, "", 1, 0, NULL
3859     },
3860         sequenceDelimiter = {
3861         DCM_DLMSEQUENCEDELIMITATIONITEM, DCM_DLM, "", 1, 0, NULL
3862     };
3863     CTNBOOLEAN
3864         unspecifiedSQLength = FALSE,
3865         explicitVR = FALSE,
3866         part10File = FALSE;
3867     unsigned long fileOptions = 0;
3868 
3869     object = (PRIVATE_OBJECT **) callerObject;
3870     cond = checkObject(object, "exportStream");
3871     if (cond != DCM_NORMAL)
3872         return cond;
3873 
3874     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
3875         part10File = TRUE;
3876         opt &= ~DCM_ORDERMASK;
3877         opt |= DCM_EXPLICITLITTLEENDIAN;
3878         cond = setFileOptions(callerObject, &fileOptions);
3879         if (cond != DCM_NORMAL)
3880             return cond;
3881     }
3882     if ((opt & DCM_ORDERMASK) == 0)
3883         return COND_PushCondition(DCM_ILLEGALOPTION,
3884                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
3885                                   "exportStream");
3886 
3887     switch (opt & DCM_ORDERMASK) {
3888     case DCM_ORDERNATIVE:
3889         byteOrder = NATIVE_ORDER;
3890         break;
3891     case DCM_ORDERLITTLEENDIAN:
3892         byteOrder = LITTLE_ORDER;
3893         break;
3894     case DCM_EXPLICITLITTLEENDIAN:
3895         byteOrder = LITTLE_ORDER;
3896         explicitVR = TRUE;
3897         break;
3898     case DCM_ORDERBIGENDIAN:
3899         byteOrder = BIG_ORDER;
3900         break;
3901     case DCM_EXPLICITBIGENDIAN:
3902         byteOrder = BIG_ORDER;
3903         explicitVR = TRUE;
3904         break;
3905     default:
3906         byteOrder = LITTLE_ORDER;
3907         break;
3908     }
3909 
3910 /*  We are making this step mandatory for now (smm)*/
3911 
3912     opt &= ~DCM_SEQUENCELENGTHMASK;
3913     opt |= DCM_UNSPECIFIEDLENGTHFLAG;
3914 
3915 /*  End of something that is out of place */
3916 
3917     if ((opt & DCM_SEQUENCELENGTHMASK) == DCM_UNSPECIFIEDLENGTHFLAG)
3918         unspecifiedSQLength = TRUE;
3919 
3920     dst = (unsigned char *) buffer;
3921     c = bufferlength;
3922 
3923     if (part10File) {
3924         cond = exportPreamble(object, dst, c, &rtnLength);
3925         if (cond != DCM_NORMAL)
3926             return cond;
3927 
3928         dst += rtnLength;
3929         c -= rtnLength;
3930         bytesExported += rtnLength;
3931     }
3932     if (sequenceLevel != 0) {
3933         if (!unspecifiedSQLength)
3934             itemMarker.length = (*object)->objectSize;
3935         exportFixedFields(&itemMarker, dst, bufferlength, byteOrder,
3936                           explicitVR, &rtnLength);
3937         dst += rtnLength;
3938         c -= rtnLength;
3939         bytesExported += rtnLength;
3940     }
3941     groupItem = LST_Head(&(*object)->groupList);
3942 
3943 /*  Take this code out to allow empty groups. */
3944 #if 0
3945     if (groupItem == NULL)
3946         return COND_PushCondition(DCM_LISTFAILURE,
3947                               DCM_Message(DCM_LISTFAILURE), "exportStream");
3948 #endif
3949     if (groupItem != NULL)
3950         (void) LST_Position(&(*object)->groupList, groupItem);
3951 
3952     while (groupItem != NULL) {
3953         if (part10File && groupItem->group != DCM_GROUPFILEMETA) {
3954             if (opt != fileOptions) {
3955                 opt = fileOptions;
3956                 cond = extractFileOptions(opt, &part10File,
3957                                           &explicitVR, &byteOrder);
3958                 if (cond != DCM_NORMAL)
3959                     return cond;
3960             }
3961         }
3962         elementItem = LST_Head(&groupItem->elementList);
3963         if (elementItem != NULL)
3964             (void) LST_Position(&groupItem->elementList, elementItem);
3965         if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
3966             U32 l;
3967             l = computeGroupLength(groupItem, explicitVR);
3968             *elementItem->element.d.ul = l;
3969 
3970 /* We have some problems computing group length for groups with sequences.
3971 ** For now, just remove this attribute, except for group 0000 and 0002.
3972 */
3973             if (groupItem->group != 0x0000 && groupItem->group != 0x0002)
3974                 elementItem = LST_Next(&groupItem->elementList);
3975         }
3976         while (elementItem != NULL) {
3977             if (elementItem->element.tag == DCM_MAKETAG(0x003a, 0x01000)) {
3978                 printf("Found waveform for export\n");
3979             }
3980             if (c <= 20) {
3981                 cond = callback(buffer, bytesExported, 0, ctx);
3982                 if (cond != DCM_NORMAL)
3983                     return COND_PushCondition(DCM_CALLBACKABORTED,
3984                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
3985 
3986                 bytesExported = 0;
3987                 c = bufferlength;
3988                 dst = (unsigned char *) buffer;
3989             }
3990             element = elementItem->element;
3991             if (element.representation == DCM_SQ) {
3992                 if (unspecifiedSQLength)
3993                     element.length = DCM_UNSPECIFIEDLENGTH;
3994 
3995                 exportFixedFields(&element, dst, bufferlength, byteOrder,
3996                                   explicitVR, &rtnLength);
3997             } else {
3998                 element.length = elementItem->paddedDataLength;
3999                 exportFixedFields(&element, dst, bufferlength, byteOrder,
4000                                   explicitVR, &rtnLength);
4001             }
4002             dst += rtnLength;
4003             c -= rtnLength;
4004             bytesExported += rtnLength;
4005 
4006             remainingData = element.length;
4007             src = element.d.ot;
4008             elementItem->currentOffset = elementItem->dataOffset;
4009 
4010             if (element.representation == DCM_SQ) {
4011 
4012                 cond = callback(buffer, bytesExported, 0, ctx);
4013                 if (cond != DCM_NORMAL)
4014                     return COND_PushCondition(DCM_CALLBACKABORTED,
4015                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
4016 
4017                 bytesExported = 0;
4018                 c = bufferlength;
4019                 dst = (unsigned char *) buffer;
4020 
4021                 if (element.d.sq != NULL) {
4022                     sequenceItem = LST_Head(&element.d.sq);
4023                     if (sequenceItem != NULL)
4024                         (void) LST_Position(&element.d.sq, sequenceItem);
4025                     while (sequenceItem != NULL) {
4026                         cond = exportStream(&sequenceItem->object, opt,
4027                                         buffer, bufferlength, callback, ctx,
4028                                             sequenceLevel + 1);
4029                         if (cond != DCM_NORMAL)
4030                             return cond;
4031                         sequenceItem = LST_Next(&element.d.sq);
4032                     }
4033                 }
4034                 if (element.length == DCM_UNSPECIFIEDLENGTH) {
4035                     sequenceDelimiter.length = 0;
4036                     exportFixedFields(&sequenceDelimiter, dst, bufferlength,
4037                                       byteOrder, explicitVR, &rtnLength);
4038                     dst += rtnLength;
4039                     c -= rtnLength;
4040                     bytesExported += rtnLength;
4041                 }
4042             } else {
4043                 while (remainingData > 0) {
4044                     if (debug)
4045                         fprintf(stderr, "Export: (%08x) %d\n",
4046                                 element.tag, element.length);
4047                     if (element.d.ot != NULL)
4048                         remainingData = element.length -
4049                             (src - ((unsigned char *) element.d.ot));
4050                     else
4051                         remainingData = element.length -
4052                             (elementItem->currentOffset - elementItem->dataOffset);
4053 
4054                     exportLength = (remainingData < c) ? remainingData : c;
4055                     cond = exportData(object, elementItem, src, dst,
4056                                       exportLength, byteOrder, &rtnLength);
4057                     if (cond != DCM_NORMAL)
4058                         return cond;
4059 
4060                     src += rtnLength;
4061                     dst += rtnLength;
4062                     bytesExported += rtnLength;
4063                     c -= rtnLength;
4064 
4065                     if (c <= 20) {
4066                         cond = callback(buffer, bytesExported, 0, ctx);
4067                         if (cond != DCM_NORMAL)
4068                             return COND_PushCondition(DCM_CALLBACKABORTED,
4069                                                       DCM_Message(DCM_CALLBACKABORTED), "exportStream");
4070 
4071                         bytesExported = 0;
4072                         c = bufferlength;
4073                         dst = (unsigned char *) buffer;
4074                     }
4075                 }
4076             }
4077             elementItem = LST_Next(&groupItem->elementList);
4078         }
4079         groupItem = LST_Next(&(*object)->groupList);
4080     }
4081     if ((sequenceLevel != 0) && unspecifiedSQLength) {
4082         if (c <= 20) {
4083             cond = callback(buffer, bytesExported, 0, ctx);
4084             if (cond != DCM_NORMAL)
4085                 return COND_PushCondition(DCM_CALLBACKABORTED,
4086                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
4087 
4088             bytesExported = 0;
4089             c = bufferlength;
4090             dst = (unsigned char *) buffer;
4091         }
4092         exportFixedFields(&itemDelimiter, dst, bufferlength, byteOrder,
4093                           explicitVR, &rtnLength);
4094         dst += rtnLength;
4095         c -= rtnLength;
4096         bytesExported += rtnLength;
4097     }
4098     lastFlag = (sequenceLevel == 0) ? 1 : 0;
4099     cond = callback(buffer, bytesExported, lastFlag, ctx);
4100     if (cond != DCM_NORMAL)
4101         return COND_PushCondition(DCM_CALLBACKABORTED,
4102                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
4103 
4104     return DCM_NORMAL;
4105 }
4106 
4107 /* verifyFormat
4108 **
4109 ** Purpose:
4110 **  This routine verifies the format of the data value of attributes according to
4111 **  the DICOM v3 standard.
4112 **
4113 ** Parameter Dictionary:
4114 **   element    Pointer to the DCM_ELEMENT containing the element to be examined.
4115 **
4116 ** Return Values:
4117 **      DCM_NORMAL
4118 **
4119 ** Algorithm:
4120 **      switch(representation) {
4121 **      case DCM_DA:
4122 **          Retain all characters that are digits, '-', or '\'
4123 **          If the resulting string is of odd length
4124 **              Pad the string with ' '
4125 **          break;
4126 **      case DCM_TM:
4127 **          Retain all characters that are digits, '.', '-', or '\'
4128 **          If the resulting string is of odd length
4129 **              Pad the string with ' '
4130 **          break;
4131 **      case DCM_CS, DCM_AS, DCM_DS, DCM_IS, DCM_LO, DCM_SH:
4132 **          Delete all the leading and trailing spaces.
4133 **          If the resulting string is of odd length
4134 **              Pad the string with ' '
4135 **          break;
4136 **      case DCM_LT, DCM_ST, DCM_PN:
4137 **          Delete all the trailing spaces.
4138 **          If the resulting string is of odd length
4139 **              Pad the string with ' '
4140 **          break;
4141 **      }
4142 */
4143 
4144 static CONDITION
4145 verifyFormat(PRV_ELEMENT_ITEM * item)
4146 {
4147     int
4148         i,
4149         l;
4150     char
4151        *src,
4152        *dst,
4153        *p;
4154     DCM_ELEMENT
4155         * element;
4156     CTNBOOLEAN
4157         stopFlag = FALSE;
4158 
4159     element = &item->element;
4160     if (element->length > 0) {
4161         switch (element->representation) {
4162         case DCM_DA:
4163             src = dst = element->d.string;
4164             l = (int) element->length;
4165             for (i = 0; i < l; i++) {
4166                 if (isdigit(*src) || (*src == '-') || (*src == '\\')) {
4167                     *dst++ = *src++;
4168                 } else {
4169                     src++;
4170                     element->length--;
4171                 }
4172             }
4173             item->paddedDataLength = element->length;
4174             if (element->length & 1) {
4175                 *dst = ' ';
4176                 item->paddedDataLength++;
4177             }
4178             break;
4179         case DCM_TM:
4180             l = (int) element->length;
4181             src = dst = element->d.string;
4182             for (i = 0; i < l; i++) {
4183                 if (isdigit(*src) || (*src == '.') || (*src == '-') || (*src == '\\')) {
4184                     *dst++ = *src++;
4185                 } else {
4186                     src++;
4187                     element->length--;
4188                 }
4189             }
4190             item->paddedDataLength = element->length;
4191             if (element->length & 1) {
4192                 *dst = ' ';
4193                 item->paddedDataLength++;
4194             }
4195             break;
4196             /*
4197              * Both the leading and trailing spaces are non-significant.
4198              */
4199         case DCM_CS:
4200         case DCM_AS:
4201         case DCM_DS:
4202         case DCM_IS:
4203         case DCM_LO:
4204         case DCM_SH:
4205             l = (int) element->length;
4206             src = dst = element->d.string;
4207             for (i = 0; i < l; i++) {
4208                 if ((*src == ' ') && !stopFlag) {
4209                     src++;
4210                     element->length--;
4211                 } else {
4212                     stopFlag = TRUE;
4213                     *dst++ = *src++;
4214                 }
4215             }
4216             /*
4217              * Right now, dst points to the char follows the last char in the
4218              * string.
4219              */
4220             stopFlag = FALSE;
4221             l = (int) element->length;
4222             p = dst - 1;
4223             for (i = l; (i > 0) && !stopFlag; i--) {
4224                 if ((*p == ' ') && !stopFlag) {
4225                     p--;
4226                     dst--;
4227                     element->length--;
4228                 } else
4229                     stopFlag = TRUE;
4230             }
4231             item->paddedDataLength = element->length;
4232             if (element->length & 1) {
4233                 *dst = ' ';
4234                 item->paddedDataLength++;
4235             }
4236             break;
4237             /*
4238              * The trailing spaces are non-significant.
4239              */
4240         case DCM_LT:
4241         case DCM_ST:
4242             l = (int) element->length;
4243             src = element->d.string + l - 1;
4244             for (i = l; (i > 0) && !stopFlag; i--) {
4245                 if ((*src == ' ') && !stopFlag) {
4246                     src--;
4247                     element->length--;
4248                 } else
4249                     stopFlag = TRUE;
4250             }
4251             item->paddedDataLength = element->length;
4252             if (element->length & 1) {
4253                 *++src = ' ';
4254                 item->paddedDataLength++;
4255             }
4256             break;
4257         case DCM_PN:
4258             /*
4259              * Strip off the trailing spaces.
4260              */
4261             l = (int) element->length;
4262             src = element->d.string + l - 1;
4263             for (i = l; (i > 0) && !stopFlag; i--) {
4264                 if ((*src == ' ') && !stopFlag) {
4265                     src--;
4266                     element->length--;
4267                 } else
4268                     stopFlag = TRUE;
4269             }
4270             /*
4271              * Convert the name to the standard V3 format.
4272              */
4273             src = dst = element->d.string;
4274             l = element->length;
4275             for (i = 0; i < l;) {
4276                 if ((src[i] == ',') || (src[i] == '^')) {
4277                     *dst++ = '^';
4278                     i++;
4279                     while ((i < l) && (src[i] == ' ')) {
4280                         element->length--;
4281                         i++;
4282                     }
4283                 } else {
4284                     *dst++ = src[i++];
4285                 }
4286             }
4287 
4288             item->paddedDataLength = element->length;
4289             if (element->length & 1) {
4290                 *dst = ' ';
4291                 item->paddedDataLength++;
4292             }
4293             break;
4294         case DCM_UI:
4295             if (element->d.string[element->length - 1] == '\0')
4296                 element->length--;
4297             if (element->d.string[element->length - 1] == ' ') {
4298                 element->d.string[element->length - 1] = '\0';
4299                 element->length--;
4300             }
4301             break;
4302         default:
4303             break;
4304         }
4305     }
4306     return DCM_NORMAL;
4307 }
4308 
4309 /* readFile
4310 **
4311 ** Purpose:
4312 **      Read DICOM object from a file
4313 **
4314 ** Parameter Dictionary:
4315 **      name                    Name of the file
4316 **      callerBuf               Buffer from which to read the object
4317 **      fd                      File descriptor
4318 **      size                    Size of the file
4319 **      fileOffset              Offset in the file from which point read starts
4320 **      recursionLevel          Level of recursion
4321 **      opt                     Indicates in what byte order to read
4322 **      callerObject            The object into which the contents are stored
4323 **      scannedLength           Length of data scanned
4324 **      remainOpenFlag          Indicates whether the file remains open
4325 **
4326 ** Return Values:
4327 **
4328 **      DCM_ELEMENTCREATEFAILED
4329 **      DCM_ELEMENTLENGTHERROR
4330 **      DCM_ELEMENTOUTOFORDER
4331 **      DCM_FILEACCESSERROR
4332 **      DCM_ILLEGALSTREAMLENGTH
4333 **      DCM_LISTFAILURE
4334 **      DCM_NORMAL
4335 **      DCM_OBJECTCREATEFAILED
4336 **      DCM_UNEVENELEMENTLENGTH
4337 **
4338 ** Notes:
4339 **
4340 ** Algorithm:
4341 **      Description of the algorithm (optional) and any other notes.
4342 */
4343 static CONDITION
4344 readFile(char *name, unsigned char *callerBuf, int fd, long size,
4345          off_t fileOffset, int recursionLevel,
4346          unsigned long opt, DCM_OBJECT ** callerObject,
4347          U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
4348          void *ctx,
4349          CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
4350          CONDITION(*sk) (void *ctx, int offset, int flag))
4351 {
4352     CONDITION
4353     cond;
4354     int
4355         byteOrder;
4356     long
4357         lastGroup = -1,
4358         lastElement = -1;
4359     U32
4360         sequenceLength,
4361         localLength;
4362     PRIVATE_OBJECT
4363         ** object;
4364     PRV_GROUP_ITEM
4365         * groupItem = NULL;
4366     unsigned short
4367         group,
4368         element,
4369         tagGroup,
4370         tagElement;
4371     DCM_ELEMENT
4372         e,
4373         tagE;
4374     CTNBOOLEAN
4375         pixelFlag,
4376         convertFlag = FALSE,
4377         done = FALSE,
4378         knownLength = TRUE,
4379         sequenceDone = FALSE,
4380         createGroupFlag,
4381         explicitVR = FALSE;
4382     unsigned char
4383         buf[8],
4384        *ptr;
4385     int
4386         nBytes;
4387     PRV_ELEMENT_ITEM
4388         * elementItem = NULL;
4389     DCM_OBJECT
4390         * sequenceObject;
4391     DCM_SEQUENCE_ITEM
4392         * sequenceItem;
4393     CTNBOOLEAN
4394         fileFlag = TRUE;
4395 
4396     if (callerBuf != NULL) {
4397         ptr = callerBuf;
4398         fileFlag = FALSE;
4399     } else
4400         ptr = buf;
4401 
4402     switch (opt & DCM_ORDERMASK) {
4403     case DCM_ORDERNATIVE:
4404         byteOrder = NATIVE_ORDER;
4405         break;
4406     case DCM_ORDERLITTLEENDIAN:
4407         byteOrder = LITTLE_ORDER;
4408         break;
4409     case DCM_EXPLICITLITTLEENDIAN:
4410         byteOrder = LITTLE_ORDER;
4411         explicitVR = TRUE;
4412         break;
4413     case DCM_ORDERBIGENDIAN:
4414         byteOrder = BIG_ORDER;
4415         break;
4416     case DCM_EXPLICITBIGENDIAN:
4417         byteOrder = BIG_ORDER;
4418         explicitVR = TRUE;
4419         break;
4420     default:
4421         byteOrder = NATIVE_ORDER;
4422         break;
4423     }
4424     if ((opt & DCM_CONVERTMASK) == DCM_FORMATCONVERSION)
4425         convertFlag = TRUE;
4426 
4427     if (scannedLength != NULL)
4428         *scannedLength = 0;
4429 
4430     cond = DCM_CreateObject(callerObject, opt);
4431     if (cond != DCM_NORMAL)
4432         return cond;
4433 
4434     object = (PRIVATE_OBJECT **) callerObject;
4435     if (fileFlag)
4436         strcpy((*object)->fileName, name);
4437 
4438     (*object)->fd = -1;
4439     (*object)->rd = rd;
4440     (*object)->sk = sk;
4441     (*object)->userCtx = ctx;
4442     if (size == (long) DCM_UNSPECIFIEDLENGTH)
4443         knownLength = FALSE;
4444 
4445     if ((fileFlag) && ((opt & DCM_DELETEMASK) == DCM_DELETEONCLOSE) && (recursionLevel == 0))
4446         (*object)->deleteFlag = TRUE;
4447 
4448     if (knownLength && (size == 0))
4449         done = TRUE;
4450 
4451     while (!done) {
4452 
4453         if ((size < 8) && knownLength) {
4454             if (debug)
4455                 (void) DCM_DumpElements(callerObject, 0);
4456             (void) DCM_CloseObject(callerObject);
4457             return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
4458                                  DCM_Message(DCM_ILLEGALSTREAMLENGTH), size,
4459                                       "readFile");
4460         }
4461         if (fileFlag) {
4462             if (fd != -1) {
4463                 nBytes = read(fd, buf, 4);
4464             } else {
4465                 cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
4466             }
4467 
4468             if (nBytes != 4)
4469                 return COND_PushCondition(DCM_FILEACCESSERROR,
4470                                      DCM_Message(DCM_FILEACCESSERROR), name,
4471                                           "readFile");
4472             ptr = buf;
4473         }
4474         if (knownLength)
4475             size -= 4;
4476         fileOffset += (off_t) 4;
4477         if (scannedLength != NULL)
4478             (*scannedLength) += 4;
4479         (*object)->objectSize += 4;
4480 
4481         if (byteOrder == BYTEORDER_SAME) {
4482             GET_SHORT_SAME_ORDER(ptr, group);
4483             GET_SHORT_SAME_ORDER(ptr + 2, element);
4484             e.tag = DCM_MAKETAG(group, element);
4485         } else {
4486             GET_SHORT_REVERSE_ORDER(ptr, group);
4487             GET_SHORT_REVERSE_ORDER(ptr + 2, element);
4488             e.tag = DCM_MAKETAG(group, element);
4489         }
4490         ptr += 4;
4491 
4492         if (explicitVR) {
4493             if (fileFlag) {
4494                 if (fd != -1) {
4495                     nBytes = read(fd, buf, 4);
4496                 } else {
4497                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
4498                 }
4499 
4500                 if (nBytes != 4)
4501                     return COND_PushCondition(DCM_FILEACCESSERROR,
4502                                      DCM_Message(DCM_FILEACCESSERROR), name,
4503                                               "readFile");
4504                 ptr = buf;
4505             }
4506             if (knownLength)
4507                 size -= 4;
4508             fileOffset += (off_t) 4;
4509             if (scannedLength != NULL)
4510                 (*scannedLength) += 4;
4511             (*object)->objectSize += 4;
4512             if ((strncmp((char *) ptr, "OB", 2) == 0) ||
4513                 (strncmp((char *) ptr, "OW", 2) == 0) ||
4514                 (strncmp((char *) ptr, "SQ", 2) == 0)) {
4515             } else {
4516             }
4517         } else {
4518 
4519             if (fileFlag) {
4520                 if (fd != -1) {
4521                     nBytes = read(fd, buf, 4);
4522                 } else {
4523                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
4524                 }
4525 
4526                 if (nBytes != 4)
4527                     return COND_PushCondition(DCM_FILEACCESSERROR,
4528                                      DCM_Message(DCM_FILEACCESSERROR), name,
4529                                               "readFile");
4530                 ptr = buf;
4531             }
4532             if (knownLength)
4533                 size -= 4;
4534             fileOffset += (off_t) 4;
4535             if (scannedLength != NULL)
4536                 (*scannedLength) += 4;
4537             (*object)->objectSize += 4;
4538 
4539 
4540             if (byteOrder == BYTEORDER_SAME) {
4541                 GET_LONG_SAME_ORDER(ptr, e.length);
4542             } else {
4543                 GET_LONG_REVERSE_ORDER(ptr, e.length);
4544             }
4545             ptr += 4;
4546         }
4547 
4548         if (((e.length & 1) != 0) && (e.length != DCM_UNSPECIFIEDLENGTH)) {
4549             if (debug)
4550                 (void) DCM_DumpElements(callerObject, 0);
4551             (void) DCM_CloseObject(callerObject);
4552             return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
4553                                       DCM_Message(DCM_UNEVENELEMENTLENGTH),
4554                                       group, element, e.length,
4555                                       "readFile");
4556         }
4557         if ((e.length != (U32) DCM_UNSPECIFIEDLENGTH) && (e.length > (U32) size)) {
4558             if (debug)
4559                 (void) DCM_DumpElements(callerObject, 0);
4560             (void) DCM_CloseObject(callerObject);
4561             return COND_PushCondition(DCM_ELEMENTLENGTHERROR,
4562                                       DCM_Message(DCM_ELEMENTLENGTHERROR),
4563                                 group, element, e.length, size, "readFile");
4564         }
4565         if ((e.tag == DCM_DLMITEMDELIMITATIONITEM) ||
4566             (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)) {
4567             return DCM_NORMAL;
4568         }
4569         cond = DCM_LookupElement(&e);
4570         if (cond != DCM_NORMAL)
4571             (void) COND_PopCondition(0);
4572         if (e.representation == DCM_CTX)
4573             ctxSensitiveLookup(object, &e);
4574 
4575         if (e.representation == DCM_SQ) {
4576             cond = newElementItem(&e, FALSE, &elementItem);
4577             if (cond != DCM_NORMAL)
4578                 return cond;
4579             elementItem->element.d.sq = LST_Create();
4580             if (elementItem->element.d.sq == NULL)
4581                 return COND_PushCondition(DCM_LISTFAILURE,
4582                                   DCM_Message(DCM_LISTFAILURE), "readFile");
4583 
4584             localLength = elementItem->element.length;
4585             sequenceDone = (localLength == 0);
4586 
4587             while (!sequenceDone) {
4588                 if (debug)
4589                     fprintf(stderr, "Sequence Length: %d %x\n", localLength,
4590                             localLength);
4591                 if (fileFlag) {
4592                     if (fd != -1) {
4593                         nBytes = read(fd, buf, 8);
4594                     } else {
4595                         cond = (*object)->rd((*object)->userCtx, buf, 8, &nBytes);
4596                     }
4597                     if (nBytes != 8)
4598                         return COND_PushCondition(DCM_FILEACCESSERROR,
4599                                      DCM_Message(DCM_FILEACCESSERROR), name,
4600                                                   "readFile");
4601                     ptr = buf;
4602                 }
4603                 if (size != (long) DCM_UNSPECIFIEDLENGTH)
4604                     size -= 8;
4605                 fileOffset += (off_t) 8;
4606                 if (scannedLength != NULL)
4607                     (*scannedLength) += 8;
4608                 (*object)->objectSize += 8;
4609                 if (localLength != DCM_UNSPECIFIEDLENGTH)
4610                     localLength -= 8;
4611 
4612                 if (byteOrder == BYTEORDER_SAME) {
4613                     GET_SHORT_SAME_ORDER(ptr, tagGroup);
4614                     GET_SHORT_SAME_ORDER(ptr + 2, tagElement);
4615                     tagE.tag = DCM_MAKETAG(tagGroup, tagElement);
4616                     GET_LONG_SAME_ORDER(ptr + 4, tagE.length);
4617                 } else {
4618                     GET_SHORT_REVERSE_ORDER(ptr, tagGroup);
4619                     GET_SHORT_REVERSE_ORDER(ptr + 2, tagElement);
4620                     tagE.tag = DCM_MAKETAG(tagGroup, tagElement);
4621                     GET_LONG_REVERSE_ORDER(ptr + 4, tagE.length);
4622                 }
4623                 ptr += 8;
4624                 if (debug)
4625                     fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
4626                             tagGroup, tagElement, tagE.length, tagE.length);
4627                 if (tagE.tag == DCM_DLMITEM) {
4628 /*                  if (size != DCM_UNSPECIFIEDLENGTH)
4629                         size -= 8;
4630 */
4631 /*                  fileOffset += 8;
4632 */
4633                     cond = readFile(name,
4634                                     (fileFlag) ? NULL : ptr,
4635                                     fd, tagE.length,
4636                                     fileOffset, recursionLevel + 1, opt,
4637                                     &sequenceObject, &sequenceLength,
4638                                     remainOpenFlag, ctx, rd, sk);
4639                     if (cond == DCM_NORMAL) {
4640                         sequenceItem = CTN_MALLOC(sizeof(*sequenceItem));
4641                         if (sequenceItem == NULL)
4642                             return COND_PushCondition(DCM_MALLOCFAILURE,
4643                                              DCM_Message(DCM_MALLOCFAILURE),
4644                                          sizeof(*sequenceItem), "readFile");
4645 
4646                         sequenceItem->object = sequenceObject;
4647                         cond = LST_Enqueue(&elementItem->element.d.sq,
4648                                            sequenceItem);
4649                         if (cond != LST_NORMAL)
4650                             return COND_PushCondition(DCM_LISTFAILURE,
4651                                   DCM_Message(DCM_LISTFAILURE), "readFile");
4652                         if (size != (long) DCM_UNSPECIFIEDLENGTH)
4653                             size -= sequenceLength;
4654                         fileOffset += (off_t) sequenceLength;
4655                         if (scannedLength != NULL)
4656                             *scannedLength += sequenceLength;
4657                         (*object)->objectSize += sequenceLength;
4658                         if (localLength != DCM_UNSPECIFIEDLENGTH)
4659                             localLength -= sequenceLength;
4660                         ptr += sequenceLength;
4661                     } else
4662                         return cond;
4663                 } else {
4664                     sequenceDone = TRUE;
4665                 }
4666                 if (localLength == 0)
4667                     sequenceDone = TRUE;
4668             }
4669         } else {
4670             pixelFlag = (e.tag == DCM_PXLPIXELDATA);
4671             cond = newElementItem(&e, (pixelFlag == FALSE), &elementItem);
4672             if (cond != DCM_NORMAL) {
4673                 (void) DCM_CloseObject(callerObject);
4674                 return cond;
4675             }
4676             if (pixelFlag) {
4677                 if (fileFlag)
4678                     *remainOpenFlag = TRUE;
4679                 elementItem->byteOrder = byteOrder;
4680                 elementItem->dataOffset = fileOffset;
4681                 elementItem->currentOffset = 0;
4682                 if (fileFlag)
4683                     elementItem->element.d.ot = NULL;
4684                 else
4685                     elementItem->element.d.ot = (void *) ptr;
4686                 if ((*object)->pixelBitsAllocated == 8)
4687                     elementItem->element.representation = DCM_OB;
4688                 else
4689                     elementItem->element.representation = DCM_OW;
4690                 if (fileFlag) {
4691                     if (fd != -1) {
4692                         (void) lseek(fd, (off_t) elementItem->element.length, SEEK_CUR);
4693                     } else {
4694                         (*object)->sk((*object)->userCtx,
4695                                       elementItem->element.length, SEEK_CUR);
4696                     }
4697                     (*object)->fd = fd;
4698                 }
4699             } else {
4700                 if (fileFlag) {
4701                     if (fd != -1) {
4702                         nBytes = read(fd, elementItem->element.d.ot,
4703                                       (int) elementItem->element.length);
4704                     } else {
4705                         cond = (*object)->rd((*object)->userCtx,
4706                                              elementItem->element.d.ot,
4707                                (long) elementItem->element.length, &nBytes);
4708                     }
4709                     if (nBytes != (int) elementItem->element.length) {
4710                         (void) DCM_CloseObject(callerObject);
4711                         return COND_PushCondition(DCM_FILEACCESSERROR,
4712                         DCM_Message(DCM_FILEACCESSERROR), name, "readFile");
4713                     }
4714                 } else {
4715                     (void) memcpy(elementItem->element.d.ot, ptr,
4716                                   elementItem->element.length);
4717                     ptr += elementItem->originalDataLength;
4718                 }
4719 
4720 #ifdef LITTLE_ENDIAN_ARCHITECTURE
4721                 if (elementItem->element.representation == DCM_AT)
4722                     swapATGroupElement(&elementItem->element);
4723 #endif
4724                 if (byteOrder != BYTEORDER_SAME)
4725                     swapInPlace(object, &elementItem->element);
4726                 if (convertFlag) {
4727                     cond = verifyFormat(elementItem);
4728                     if (cond != DCM_NORMAL)
4729                         return cond;
4730                 }
4731             }
4732             if (size != (long) DCM_UNSPECIFIEDLENGTH)
4733                 size -= elementItem->originalDataLength;
4734             fileOffset += (off_t) elementItem->originalDataLength;
4735             if (scannedLength != NULL)
4736                 (*scannedLength) += elementItem->originalDataLength;
4737 
4738             elementItem->paddedDataLength = elementItem->element.length;
4739             if (elementItem->paddedDataLength & 1)
4740                 elementItem->paddedDataLength += 1;
4741             (*object)->objectSize += elementItem->paddedDataLength;
4742         }
4743 
4744         computeVM(object, &elementItem->element);
4745 
4746         if ((long) DCM_TAG_GROUP(e.tag) == lastGroup) {
4747             if ((long) DCM_TAG_ELEMENT(e.tag) <= lastElement)
4748                 return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
4749                                           DCM_Message(DCM_ELEMENTOUTOFORDER),
4750                                           group, element, "readFile");
4751         } else if ((long) DCM_TAG_GROUP(e.tag) > lastGroup) {
4752         } else {
4753             return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
4754                          DCM_Message(DCM_ELEMENTOUTOFORDER), group, element,
4755                                       "readFile");
4756         }
4757         lastGroup = (long) group;
4758         lastElement = (long) element;
4759 
4760         if (groupItem == NULL)
4761             createGroupFlag = TRUE;
4762         else if (groupItem->group != group)
4763             createGroupFlag = TRUE;
4764         else
4765             createGroupFlag = FALSE;
4766 
4767         if (createGroupFlag == TRUE) {
4768             groupItem = CTN_MALLOC(sizeof(*groupItem));
4769             if (groupItem == NULL) {
4770                 (void) DCM_CloseObject(callerObject);
4771                 return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
4772                                        DCM_Message(DCM_ELEMENTCREATEFAILED),
4773                                           "readFile",
4774                                           group, 0xffff, sizeof(*groupItem));
4775             }
4776             groupItem->group = group;
4777             groupItem->baseLength = 0;
4778             groupItem->longVRAttributes = 0;
4779             groupItem->elementList = LST_Create();
4780             if (groupItem->elementList == NULL) {
4781                 (void) DCM_CloseObject(callerObject);
4782                 return COND_PushCondition(DCM_LISTFAILURE,
4783                                           DCM_Message(DCM_LISTFAILURE),
4784                                           "readFile");
4785             }
4786             if (LST_Enqueue(&(*object)->groupList, groupItem) != LST_NORMAL) {
4787                 (void) DCM_CloseObject(callerObject);
4788                 return COND_PushCondition(DCM_LISTFAILURE,
4789                                           DCM_Message(DCM_LISTFAILURE),
4790                                           "readFile");
4791             }
4792         }
4793         if (element != 0x0000)
4794             groupItem->baseLength += 8 + elementItem->paddedDataLength;
4795         if ((element == 0x0000) && ((*object)->groupLengthFlag == FALSE)) {
4796             CTN_FREE(elementItem);
4797         } else {
4798             cond = LST_Enqueue(&groupItem->elementList, elementItem);
4799             if (cond != LST_NORMAL) {
4800                 (void) DCM_CloseObject(callerObject);
4801                 return COND_PushCondition(DCM_LISTFAILURE,
4802                                           DCM_Message(DCM_LISTFAILURE),
4803                                           "readFile");
4804             }
4805             cond = updateObjectType(object, &elementItem->element);     /* repair */
4806 
4807             cond = updateSpecialElements(object, elementItem);  /* repair */
4808         }
4809 
4810         if (size == 0)
4811             done = TRUE;
4812 
4813 #ifdef DEBUG
4814         if (debug) {
4815 /*lint -e644 */
4816             (void) fprintf(stderr, "Address: %px Group %2x, element %2x, length %ld ",
4817                            elementItem,
4818                            DCM_TAG_GROUP(elementItem->element.tag),
4819                            DCM_TAG_ELEMENT(elementItem->element.tag),
4820                            elementItem->element.length);
4821 /*lint +e644 */
4822             (void) fprintf(stderr, "Object size: %d\n", (*object)->objectSize);
4823         }
4824 #endif
4825     }
4826 
4827     groupItem = LST_Head(&(*object)->groupList);
4828     if (groupItem != NULL) {
4829         (void) LST_Position(&(*object)->groupList, groupItem);
4830         while (groupItem != NULL) {
4831             elementItem = LST_Head(&groupItem->elementList);
4832             if (elementItem != NULL) {
4833                 if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
4834                     *elementItem->element.d.ul = groupItem->baseLength;
4835                 }
4836             }
4837             groupItem = LST_Next(&(*object)->groupList);
4838         }
4839     }
4840     return DCM_NORMAL;
4841 }
4842 
4843 static CONDITION
4844 readPreamble(const char *name, unsigned char **ptr, int fd, U32 * size,
4845              off_t * fileOffset, CTNBOOLEAN knownLength,
4846              PRIVATE_OBJECT ** object, U32 * scannedLength)
4847 {
4848     int nBytes,
4849         tmp;
4850     CONDITION cond;
4851     char label[4];
4852 
4853     if (*size == 0)
4854         return DCM_STREAMCOMPLETE;
4855 
4856     if ((*size < DCM_PREAMBLELENGTH + 4) && knownLength) {
4857         if (debug)
4858             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
4859         (void) DCM_CloseObject((DCM_OBJECT **) object);
4860         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
4861                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
4862                                   "readPreamble");
4863     }
4864     if (*ptr == NULL) {
4865         if (fd != -1) {
4866             nBytes = read(fd, (*object)->preamble, DCM_PREAMBLELENGTH);
4867             nBytes += read(fd, label, sizeof(label));
4868         } else {
4869             cond = (*object)->rd((*object)->userCtx, (*object)->preamble,
4870                                  DCM_PREAMBLELENGTH, &nBytes);
4871             cond = (*object)->rd((*object)->userCtx, label,
4872                                  sizeof(label), &tmp);
4873             nBytes += tmp;
4874         }
4875 
4876         if (nBytes != DCM_PREAMBLELENGTH + sizeof(label))
4877             return COND_PushCondition(DCM_FILEACCESSERROR,
4878                                       DCM_Message(DCM_FILEACCESSERROR), name,
4879                                       "readPreamble");
4880     } else {
4881         (void) memcpy((*object)->preamble, *ptr, DCM_PREAMBLELENGTH);
4882         (void) memcpy(label, (*ptr) + DCM_PREAMBLELENGTH, sizeof(label));
4883     }
4884 
4885     if (knownLength)
4886         *size -= DCM_PREAMBLELENGTH + sizeof(label);
4887     *fileOffset += (off_t) DCM_PREAMBLELENGTH + sizeof(label);
4888     if (*ptr != NULL)
4889         *ptr += DCM_PREAMBLELENGTH + sizeof(label);
4890     (*object)->objectSize += DCM_PREAMBLELENGTH + sizeof(label);
4891 
4892     if (strncmp(label, "DICM", 4) != 0)
4893         return 0;
4894 
4895     (*object)->preambleFlag = TRUE;
4896     return DCM_NORMAL;
4897 }
4898 
4899 
4900 static CONDITION
4901 readGroupElement(const char *name, unsigned char **ptr, int fd, U32 * size,
4902                  off_t * fileOffset, CTNBOOLEAN knownLength, int byteOrder,
4903                  CTNBOOLEAN explicitVR, CTNBOOLEAN acceptVRMismatch,
4904                  PRIVATE_OBJECT ** object, U32 * scannedLength,
4905                  DCM_ELEMENT * e)
4906 {
4907     unsigned char *localPtr;
4908     unsigned char buf[4];
4909     int nBytes;
4910     CONDITION cond;
4911     unsigned short group,
4912         element;
4913 
4914     if (*size == 0)
4915         return DCM_STREAMCOMPLETE;
4916 
4917     if ((*size < 4) && knownLength) {
4918         if (debug)
4919             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
4920         (void) DCM_CloseObject((DCM_OBJECT **) object);
4921         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
4922                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
4923                                   "readFile");
4924     }
4925     if (*ptr == NULL) {
4926         if (fd != -1) {
4927             nBytes = read(fd, buf, 4);
4928         } else {
4929             cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
4930         }
4931 
4932         if (nBytes != 4)
4933             return COND_PushCondition(DCM_FILEACCESSERROR,
4934                                       DCM_Message(DCM_FILEACCESSERROR), name,
4935                                       "readGroupElement");
4936         localPtr = buf;
4937     } else {
4938         localPtr = *ptr;
4939     }
4940 
4941     if (knownLength)
4942         *size -= 4;
4943     *fileOffset += (off_t) 4;
4944     if (scannedLength != NULL)
4945         (*scannedLength) += 4;
4946     (*object)->objectSize += 4;
4947 
4948     if (byteOrder == BYTEORDER_SAME) {
4949         GET_SHORT_SAME_ORDER(localPtr, group);
4950         GET_SHORT_SAME_ORDER(localPtr + 2, element);
4951         e->tag = DCM_MAKETAG(group, element);
4952     } else {
4953         GET_SHORT_REVERSE_ORDER(localPtr, group);
4954         GET_SHORT_REVERSE_ORDER(localPtr + 2, element);
4955         e->tag = DCM_MAKETAG(group, element);
4956     }
4957     if (*ptr != NULL)
4958         *ptr += 4;
4959 
4960     if (debug)
4961         fprintf(stderr, "%04x %04x ", group, element);
4962 
4963     cond = DCM_LookupElement(e);
4964     if (cond != DCM_NORMAL)
4965         (void) COND_PopCondition(0);
4966     if (e->representation == DCM_CTX)
4967         ctxSensitiveLookup(object, e);
4968 
4969     return DCM_NORMAL;
4970 }
4971 
4972 static CONDITION
4973 readVRLength(const char *name, unsigned char **ptr, int fd, U32 * size,
4974              off_t * fileOffset,
4975              CTNBOOLEAN knownLength, int byteOrder, CTNBOOLEAN explicitVR,
4976              CTNBOOLEAN acceptVRMismatch,
4977              PRIVATE_OBJECT ** object, U32 * scannedLength, DCM_ELEMENT * e)
4978 {
4979     unsigned char *localPtr;
4980     unsigned char buf[4];
4981     char vrCode[3];
4982     VRMAP *vrPtr;
4983     int nBytes;
4984     CONDITION cond;
4985     CTNBOOLEAN calculatedLength = FALSE;
4986 
4987     if (*size == 0)
4988         return DCM_STREAMCOMPLETE;
4989 
4990     if ((*size < 4) && knownLength) {
4991         if (debug)
4992             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
4993         (void) DCM_CloseObject((DCM_OBJECT **) object);
4994         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
4995                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
4996                                   "readVRLength");
4997     }
4998     if (*ptr == NULL) {
4999         if (fd != -1) {
5000             nBytes = read(fd, buf, 4);
5001         } else {
5002             cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
5003         }
5004 
5005         if (nBytes != 4)
5006             return COND_PushCondition(DCM_FILEACCESSERROR,
5007                                       DCM_Message(DCM_FILEACCESSERROR), name,
5008                                       "readVRLength");
5009         localPtr = buf;
5010     } else
5011         localPtr = *ptr;
5012 
5013     if (knownLength)
5014         *size -= 4;
5015     *fileOffset += (off_t) 4;
5016     if (scannedLength != NULL)
5017         (*scannedLength) += 4;
5018     (*object)->objectSize += 4;
5019 
5020     e->length = 0;
5021     if (e->representation == DCM_DLM) {
5022         explicitVR = FALSE;     /* Special rule for delimitors */
5023     }
5024     if (explicitVR) {
5025         vrCode[0] = buf[0];
5026         vrCode[1] = buf[1];
5027         vrCode[2] = '\0';
5028         vrPtr = lookupVRCode(vrCode);
5029         if (vrPtr == NULL)
5030             return COND_PushCondition(DCM_UNRECOGNIZEDVRCODE,
5031                                 DCM_Message(DCM_UNRECOGNIZEDVRCODE), vrCode,
5032                                       "readVRLength");
5033 
5034         if (vrPtr->representation != e->representation) {
5035             if (vrPtr->representation == DCM_OB) {
5036                 /* This is probably from the waveform supplement where they */
5037                 /* transmit as OB and expect us to pull it out later */
5038                 /* We will just keep our VR which was based on context in */
5039                 /* the object */
5040             } else if (e->representation == DCM_UNKNOWN ||
5041                        e->representation == DCM_CTX ||
5042                        vrPtr->representation == DCM_OW ||
5043                        acceptVRMismatch) {      /* Believe input */
5044                 e->representation = vrPtr->representation;
5045             } else {
5046                 if (e->tag != DCM_PXLPIXELDATA)
5047                     return COND_PushCondition(DCM_VRMISMATCH,
5048                                DCM_Message(DCM_VRMISMATCH), vrCode, e->tag);
5049             }
5050         }
5051         if (vrPtr->representation != DCM_OW &&
5052             vrPtr->representation != DCM_OB &&
5053             vrPtr->representation != DCM_SQ) {
5054             unsigned short shortLength;
5055             if (byteOrder == BYTEORDER_SAME) {
5056                 GET_SHORT_SAME_ORDER(localPtr + 2, shortLength);
5057             } else {
5058                 GET_SHORT_REVERSE_ORDER(localPtr + 2, shortLength);
5059             }
5060             e->length = shortLength;
5061             if (*ptr != NULL)
5062                 *ptr += 4;
5063             calculatedLength = TRUE;
5064         } else {
5065             if ((*size < 4) && knownLength) {
5066                 if (debug)
5067                     (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
5068                 (void) DCM_CloseObject((DCM_OBJECT **) object);
5069                 return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
5070                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
5071                                           "readVRLength");
5072             }
5073             if (*ptr == NULL) {
5074                 if (fd != -1) {
5075                     nBytes = read(fd, buf, 4);
5076                 } else {
5077                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
5078                 }
5079 
5080                 if (nBytes != 4)
5081                     return COND_PushCondition(DCM_FILEACCESSERROR,
5082                                      DCM_Message(DCM_FILEACCESSERROR), name,
5083                                               "readVRLength");
5084                 localPtr = buf;
5085             } else
5086                 localPtr = *ptr;
5087 
5088             if (knownLength)
5089                 *size -= 4;
5090             *fileOffset += (off_t) 4;
5091             if (scannedLength != NULL)
5092                 (*scannedLength) += 4;
5093             (*object)->objectSize += 4;
5094         }
5095     }
5096     if (!calculatedLength) {
5097         if (byteOrder == BYTEORDER_SAME) {
5098             GET_LONG_SAME_ORDER(localPtr, e->length);
5099         } else {
5100             GET_LONG_REVERSE_ORDER(localPtr, e->length);
5101         }
5102         if (*ptr != NULL)
5103             *ptr += 4;
5104     }
5105     if (debug) {
5106         char localVR[10];
5107         mapVRtoASCII(e->representation, localVR);
5108         fprintf(stderr, "%2s %6d %06x %s\n", localVR, e->length, *fileOffset,
5109                 e->description);
5110     }
5111     if (((e->length & 1) != 0) && (e->length != DCM_UNSPECIFIEDLENGTH)) {
5112         if (debug)
5113             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
5114         (void) DCM_CloseObject((DCM_OBJECT **) object);
5115         return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
5116                                   DCM_Message(DCM_UNEVENELEMENTLENGTH),
5117                              DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag),
5118                                   e->length, "readFile");
5119     }
5120     if ((e->length != (U32) DCM_UNSPECIFIEDLENGTH) && (e->length > (U32) (*size))) {
5121         if (debug)
5122             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
5123         (void) DCM_CloseObject((DCM_OBJECT **) object);
5124         return COND_PushCondition(DCM_ELEMENTLENGTHERROR,
5125                                   DCM_Message(DCM_ELEMENTLENGTHERROR),
5126                              DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag),
5127                                   e->length, *size, "readFile");
5128     }
5129     return DCM_NORMAL;
5130 }
5131 
5132 static CONDITION
5133 readSequence(const char *name, unsigned char **ptr, int fd, U32 * size,
5134              off_t * fileOffset, int recursionLevel, unsigned long opt,
5135           int byteOrder, CTNBOOLEAN explicitVR, CTNBOOLEAN acceptVRMismatch,
5136              CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
5137              CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
5138              U32 * scannedLength, DCM_ELEMENT * e,
5139              PRV_ELEMENT_ITEM ** elementItem)
5140 {
5141     CTNBOOLEAN knownLength = TRUE;
5142     CONDITION cond;
5143     U32 sequenceLength;
5144 
5145     U32 localLength;
5146     CTNBOOLEAN sequenceDone;
5147     DCM_ELEMENT tagE;
5148     DCM_OBJECT
5149         * sequenceObject;
5150     DCM_SEQUENCE_ITEM *sequenceItem;
5151     CONDITION flag;
5152     unsigned char *localPtr;
5153     off_t itemTagOffset;
5154 
5155     if (*size == (long) DCM_UNSPECIFIEDLENGTH)
5156         knownLength = FALSE;
5157 
5158     cond = newElementItem(e, FALSE, elementItem);
5159     if (cond != DCM_NORMAL)
5160         return cond;
5161     (*elementItem)->element.d.sq = LST_Create();
5162     if ((*elementItem)->element.d.sq == NULL)
5163         return COND_PushCondition(DCM_LISTFAILURE,
5164                               DCM_Message(DCM_LISTFAILURE), "readSequence");
5165 
5166     localLength = (*elementItem)->element.length;
5167     sequenceDone = (localLength == 0);
5168 
5169     while (!sequenceDone) {
5170         if (debug)
5171             fprintf(stderr, "Sequence Length: %d %x\n", localLength,
5172                     localLength);
5173 
5174         sequenceLength = 0;
5175         itemTagOffset = *fileOffset;
5176 
5177         flag = readGroupElement(name, ptr, fd, &localLength, fileOffset, knownLength,
5178                                 byteOrder, explicitVR, acceptVRMismatch, object, &sequenceLength, &tagE);
5179         if (flag == DCM_STREAMCOMPLETE)
5180             break;
5181         else if (flag != DCM_NORMAL)
5182             return flag;
5183 
5184         flag = readVRLength(name, ptr, fd, &localLength, fileOffset, knownLength,
5185                             byteOrder, explicitVR, acceptVRMismatch, object,
5186                             &sequenceLength, &tagE);
5187         if (flag != DCM_NORMAL)
5188             return flag;
5189 
5190         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
5191             *size -= sequenceLength;
5192         if (scannedLength != NULL)
5193             *scannedLength += sequenceLength;
5194 
5195         sequenceLength = 0;
5196 
5197 
5198         if (debug)
5199             fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
5200                     DCM_TAG_GROUP(tagE.tag),
5201                     DCM_TAG_ELEMENT(tagE.tag), tagE.length, tagE.length);
5202         if (tagE.tag == DCM_DLMITEM) {
5203             localPtr = *ptr;
5204             cond = readFile1(name,
5205                              localPtr,
5206                              fd, tagE.length,
5207                              fileOffset, recursionLevel + 1, opt,
5208                              object, &sequenceObject, &sequenceLength,
5209                           remainOpenFlag, (*object)->userCtx, (*object)->rd,
5210                              (*object)->sk);
5211             *ptr = localPtr;
5212             if (cond == DCM_NORMAL) {
5213                 sequenceItem = CTN_MALLOC(sizeof(*sequenceItem));
5214                 if (sequenceItem == NULL)
5215                     return COND_PushCondition(DCM_MALLOCFAILURE,
5216                                               DCM_Message(DCM_MALLOCFAILURE),
5217                                          sizeof(*sequenceItem), "readFile");
5218 
5219                 ((PRIVATE_OBJECT *) sequenceObject)->offset = itemTagOffset;
5220                 sequenceItem->object = sequenceObject;
5221                 cond = LST_Enqueue(&(*elementItem)->element.d.sq,
5222                                    sequenceItem);
5223                 if (cond != LST_NORMAL)
5224                     return COND_PushCondition(DCM_LISTFAILURE,
5225                                   DCM_Message(DCM_LISTFAILURE), "readFile");
5226                 if (*size != (long) DCM_UNSPECIFIEDLENGTH)
5227                     *size -= sequenceLength;
5228                 if (scannedLength != NULL)
5229                     *scannedLength += sequenceLength;
5230                 (*object)->objectSize += sequenceLength;
5231                 if (localLength != DCM_UNSPECIFIEDLENGTH)
5232                     localLength -= sequenceLength;
5233             } else
5234                 return cond;
5235         } else {
5236             sequenceDone = TRUE;
5237         }
5238         if (localLength == 0)
5239             sequenceDone = TRUE;
5240     }
5241     return DCM_NORMAL;
5242 }
5243 
5244 static CONDITION
5245 scanCompressedPixels(char *name, unsigned char **ptr, int fd, U32 * size,
5246                   off_t * fileOffset, int recursionLevel, unsigned long opt,
5247                      int byteOrder, CTNBOOLEAN explicitVR,
5248                      CTNBOOLEAN acceptVRMismatch,
5249                      CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
5250                      CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
5251                      U32 * scannedLength, DCM_ELEMENT * e,
5252                      PRV_ELEMENT_ITEM ** elementItem)
5253 {
5254     CTNBOOLEAN knownLength = TRUE;
5255     U32 sequenceLength;
5256     U32 scannedBytes = 0;
5257 
5258     U32 localLength;
5259     CTNBOOLEAN sequenceDone;
5260     DCM_ELEMENT tagE;
5261     CONDITION flag;
5262     unsigned char *localPtr;
5263 
5264     if (*size == (long) DCM_UNSPECIFIEDLENGTH)
5265         knownLength = FALSE;
5266 
5267     localLength = (*elementItem)->element.length;
5268     sequenceDone = (localLength == 0);
5269 
5270     while (!sequenceDone) {
5271         sequenceLength = 0;
5272         flag = readGroupElement(name, ptr, fd, &localLength, fileOffset,
5273                              FALSE, byteOrder, explicitVR, acceptVRMismatch,
5274                                 object, &sequenceLength, &tagE);
5275         if (flag == DCM_STREAMCOMPLETE)
5276             break;
5277         else if (flag != DCM_NORMAL)
5278             return flag;
5279 
5280         flag = readVRLength(name, ptr, fd, &localLength, fileOffset, knownLength,
5281                             byteOrder, explicitVR, acceptVRMismatch, object,
5282                             &sequenceLength, &tagE);
5283         if (flag != DCM_NORMAL)
5284             return flag;
5285 
5286         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
5287             *size -= sequenceLength;
5288         if (scannedLength != NULL)
5289             *scannedLength += sequenceLength;
5290         scannedBytes += sequenceLength;
5291 
5292         if (debug)
5293             fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
5294                     DCM_TAG_GROUP(tagE.tag),
5295                     DCM_TAG_ELEMENT(tagE.tag), tagE.length, tagE.length);
5296         if (tagE.tag == DCM_DLMITEM) {
5297             localPtr = *ptr;
5298             if (tagE.length != 0) {
5299                 lseek(fd, tagE.length, SEEK_CUR);
5300                 *fileOffset += tagE.length;
5301                 if (*size != (long) DCM_UNSPECIFIEDLENGTH)
5302                     *size -= tagE.length;
5303                 if (scannedLength != NULL)
5304                     *scannedLength += tagE.length;
5305             }
5306         } else {
5307             sequenceDone = TRUE;
5308         }
5309         if (localLength == 0)
5310             sequenceDone = TRUE;
5311 
5312         if (debug)
5313             fprintf(stderr, "Scanned Bytes: %d\n", scannedBytes);
5314     }
5315     if ((scannedBytes & 1) != 0) {
5316         lseek(fd, 1, SEEK_CUR);
5317         *fileOffset += 1;
5318         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
5319             *size -= 1;
5320     }
5321     return DCM_NORMAL;
5322 }
5323 
5324 static CONDITION
5325 readData(const char *name, unsigned char **ptr, int fd, U32 * size,
5326          off_t * fileOffset,
5327          CTNBOOLEAN knownLength, int byteOrder, CTNBOOLEAN explicitVR,
5328          CTNBOOLEAN acceptVRMismatch,
5329          CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
5330          CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
5331          U32 * scannedLength, DCM_ELEMENT * e,
5332          PRV_ELEMENT_ITEM ** elementItem)
5333 {
5334     CTNBOOLEAN pixelFlag;
5335     CONDITION cond;
5336     int nBytes;
5337 
5338     pixelFlag = (e->tag == DCM_PXLPIXELDATA);
5339     cond = newElementItem(e, (pixelFlag == FALSE), elementItem);
5340     if (cond != DCM_NORMAL) {
5341         (void) DCM_CloseObject((DCM_OBJECT **) object);
5342         return cond;
5343     }
5344     if (pixelFlag) {
5345         if (fileFlag)
5346             *remainOpenFlag = TRUE;
5347         (*elementItem)->byteOrder = byteOrder;
5348         (*elementItem)->dataOffset = *fileOffset;
5349         (*elementItem)->currentOffset = 0;
5350         (*elementItem)->element.d.ot = NULL;
5351         if ((*object)->pixelBitsAllocated == 8)
5352             (*elementItem)->element.representation = DCM_OB;
5353         else
5354             (*elementItem)->element.representation = DCM_OW;
5355         if (fileFlag) {
5356             if (fd != -1) {
5357                 if ((*elementItem)->element.length != DCM_UNSPECIFIEDLENGTH)
5358                     (void) lseek(fd,
5359                                  (off_t) (*elementItem)->element.length,
5360                                  SEEK_CUR);
5361                 else {
5362                     U32 l1 = 0;
5363                     U32 s1;
5364                     off_t f1 = 0;
5365 
5366                     s1 = *size;
5367                     scanCompressedPixels("", ptr, fd,
5368                                          &s1,   /* size */
5369                                          &f1,   /* fileOffset */
5370                                          0, 0,
5371                                          byteOrder, explicitVR,
5372                                          acceptVRMismatch,
5373                                          fileFlag, remainOpenFlag,
5374                                          convertFlag, object,
5375                                          &l1,   /* scannedLength */
5376                                          e, elementItem);
5377                     (*elementItem)->originalDataLength = l1;
5378                 }
5379             } else {
5380                 (*object)->sk((*object)->userCtx,
5381                               (*elementItem)->element.length, SEEK_CUR);
5382             }
5383             (*object)->fd = fd;
5384         }
5385     } else {
5386         if (fileFlag) {
5387             if (fd != -1) {
5388                 nBytes = read(fd, (*elementItem)->element.d.ot,
5389                               (int) (*elementItem)->element.length);
5390             } else {
5391                 cond = (*object)->rd((*object)->userCtx,
5392                                      (*elementItem)->element.d.ot,
5393                             (long) (*elementItem)->element.length, &nBytes);
5394             }
5395             if (nBytes != (int) (*elementItem)->element.length) {
5396                 (void) DCM_CloseObject((DCM_OBJECT **) object);
5397                 return COND_PushCondition(DCM_FILEACCESSERROR,
5398                         DCM_Message(DCM_FILEACCESSERROR), name, "readFile");
5399             }
5400         } else {
5401             (void) memcpy((*elementItem)->element.d.ot, ptr,
5402                           (*elementItem)->element.length);
5403             ptr += (*elementItem)->originalDataLength;
5404         }
5405 #ifdef LITTLE_ENDIAN_ARCHITECTURE
5406         if ((*elementItem)->element.representation == DCM_AT)
5407             swapATGroupElement(&(*elementItem)->element);
5408 #endif
5409         if (byteOrder != BYTEORDER_SAME)
5410             swapInPlace(object, &(*elementItem)->element);
5411         if (convertFlag) {
5412             cond = verifyFormat(*elementItem);
5413             if (cond != DCM_NORMAL)
5414                 return cond;
5415         }
5416     }
5417     if (*size != (long) DCM_UNSPECIFIEDLENGTH)
5418         *size -= (*elementItem)->originalDataLength;
5419     *fileOffset += (off_t) (*elementItem)->originalDataLength;
5420     if (scannedLength != NULL)
5421         (*scannedLength) += (*elementItem)->originalDataLength;
5422 
5423     (*elementItem)->paddedDataLength = (*elementItem)->element.length;
5424     if ((*elementItem)->paddedDataLength & 1)
5425         (*elementItem)->paddedDataLength += 1;
5426     (*object)->objectSize += (*elementItem)->paddedDataLength;
5427 
5428     return DCM_NORMAL;
5429 
5430 }
5431 
5432 static CONDITION
5433 checkAttributeOrder(DCM_ELEMENT * e, long *lastGroup, long *lastElement)
5434 {
5435     unsigned short group;
5436     unsigned short element;
5437 
5438     group = DCM_TAG_GROUP(e->tag);
5439     element = DCM_TAG_ELEMENT(e->tag);
5440 
5441     if ((long) group == *lastGroup) {
5442         if ((long) element <= *lastElement)
5443             return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
5444                                       DCM_Message(DCM_ELEMENTOUTOFORDER),
5445                                       group, element, "checkAttributeOrder");
5446     } else if ((long) group > *lastGroup) {
5447     } else {
5448         return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
5449                                   DCM_Message(DCM_ELEMENTOUTOFORDER),
5450                                   group, element, "checkAttributeOrder");
5451     }
5452     *lastGroup = (long) group;
5453     *lastElement = (long) element;
5454 
5455     return DCM_NORMAL;
5456 }
5457 
5458 static CONDITION
5459 handleGroupItem(PRIVATE_OBJECT ** obj, PRV_GROUP_ITEM ** groupItem,
5460                 unsigned short group)
5461 {
5462     CTNBOOLEAN createGroupFlag;
5463 
5464     if (*groupItem == NULL)
5465         createGroupFlag = TRUE;
5466     else if ((*groupItem)->group != group)
5467         createGroupFlag = TRUE;
5468     else
5469         createGroupFlag = FALSE;
5470 
5471     if (createGroupFlag == TRUE) {
5472         *groupItem = CTN_MALLOC(sizeof(**groupItem));
5473         if (*groupItem == NULL) {
5474             (void) DCM_CloseObject((DCM_OBJECT **) obj);
5475             return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
5476                                       DCM_Message(DCM_ELEMENTCREATEFAILED),
5477                                       "handleGroupItem",
5478                                       group, 0xffff, sizeof(**groupItem));
5479         }
5480         (*groupItem)->group = group;
5481         (*groupItem)->baseLength = 0;
5482         (*groupItem)->longVRAttributes = 0;
5483         (*groupItem)->elementList = LST_Create();
5484         if ((*groupItem)->elementList == NULL) {
5485             (void) DCM_CloseObject((DCM_OBJECT **) obj);
5486             return COND_PushCondition(DCM_LISTFAILURE,
5487                                       DCM_Message(DCM_LISTFAILURE),
5488                                       "handleGroupItem");
5489         }
5490         if (LST_Enqueue(&(*obj)->groupList, *groupItem) != LST_NORMAL) {
5491             (void) DCM_CloseObject((DCM_OBJECT **) obj);
5492             return COND_PushCondition(DCM_LISTFAILURE,
5493                                       DCM_Message(DCM_LISTFAILURE),
5494                                       "handleGroupItem");
5495         }
5496     }
5497     return DCM_NORMAL;
5498 }
5499 
5500 static CONDITION
5501 readFile1(const char *name, unsigned char *callerBuf, int fd, U32 size,
5502           off_t * fileOffset, int recursionLevel,
5503           unsigned long opt, PRIVATE_OBJECT ** parentObject,
5504           DCM_OBJECT ** callerObject,
5505           U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
5506           void *ctx,
5507           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
5508           CONDITION(*sk) (void *ctx, int offset, int flag))
5509 {
5510     CONDITION
5511     cond;
5512     int
5513         byteOrder;
5514     long
5515         lastGroup = -1,
5516         lastElement = -1;
5517     U32
5518         sequenceLength,
5519         scannedSequenceLength;
5520     PRIVATE_OBJECT
5521         ** object;
5522     PRV_GROUP_ITEM
5523         * groupItem = NULL;
5524     DCM_ELEMENT
5525         e;
5526     CTNBOOLEAN
5527         convertFlag = FALSE,
5528         done = FALSE,
5529         knownLength = TRUE,
5530         explicitVR = FALSE,
5531         acceptVRMismatch = FALSE,
5532         part10Flag = FALSE;
5533     unsigned char
5534        *ptr = NULL;
5535     PRV_ELEMENT_ITEM
5536         * elementItem = NULL;
5537     CTNBOOLEAN
5538         fileFlag = TRUE;
5539     CONDITION flag;
5540 
5541     ptr = callerBuf;
5542     if (ptr != NULL)
5543         fileFlag = FALSE;
5544 
5545     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
5546         part10Flag = TRUE;
5547         opt &= ~DCM_ORDERMASK;
5548         opt &= ~DCM_FILEFORMATMASK;
5549         opt |= DCM_EXPLICITLITTLEENDIAN;
5550     }
5551     switch (opt & DCM_ORDERMASK) {
5552     case DCM_ORDERNATIVE:
5553         byteOrder = NATIVE_ORDER;
5554         break;
5555     case DCM_ORDERLITTLEENDIAN:
5556         byteOrder = LITTLE_ORDER;
5557         break;
5558     case DCM_EXPLICITLITTLEENDIAN:
5559         byteOrder = LITTLE_ORDER;
5560         explicitVR = TRUE;
5561         break;
5562     case DCM_ORDERBIGENDIAN:
5563         byteOrder = BIG_ORDER;
5564         break;
5565     case DCM_EXPLICITBIGENDIAN:
5566         byteOrder = BIG_ORDER;
5567         explicitVR = TRUE;
5568         break;
5569     default:
5570         byteOrder = NATIVE_ORDER;
5571         break;
5572     }
5573     if ((opt & DCM_CONVERTMASK) == DCM_FORMATCONVERSION)
5574         convertFlag = TRUE;
5575     if ((opt & DCM_VRMASK) == DCM_ACCEPTVRMISMATCH)
5576         acceptVRMismatch = TRUE;
5577 
5578     if (scannedLength != NULL)
5579         *scannedLength = 0;
5580 
5581     cond = DCM_CreateObject(callerObject, opt);
5582     if (cond != DCM_NORMAL)
5583         return cond;
5584 
5585     object = (PRIVATE_OBJECT **) callerObject;
5586     if (fileFlag)
5587         strcpy((*object)->fileName, name);
5588 
5589     (*object)->fd = -1;
5590     (*object)->rd = rd;
5591     (*object)->sk = sk;
5592     (*object)->userCtx = ctx;
5593     (*object)->dataOptions = 0;
5594     if (size == (long) DCM_UNSPECIFIEDLENGTH)
5595         knownLength = FALSE;
5596 
5597     if ((fileFlag) && ((opt & DCM_DELETEMASK) == DCM_DELETEONCLOSE) && (recursionLevel == 0))
5598         (*object)->deleteFlag = TRUE;
5599 
5600     if (parentObject != NULL)
5601         (*object)->pixelRepresentation = (*parentObject)->pixelRepresentation;
5602 
5603     if (recursionLevel == 0 && part10Flag) {
5604         flag = readPreamble(name, &ptr, fd, &size, fileOffset, knownLength,
5605                             object, scannedLength);
5606         if (flag != DCM_NORMAL)
5607             goto abort;
5608     }
5609     while (!done) {
5610         flag = readGroupElement(name, &ptr, fd, &size, fileOffset, knownLength,
5611                             byteOrder, explicitVR, acceptVRMismatch, object,
5612                                 scannedLength, &e);
5613         if (flag == DCM_STREAMCOMPLETE)
5614             break;
5615         else if (flag != DCM_NORMAL)
5616             goto abort;
5617 
5618         if (e.tag == DCM_MAKETAG(0x003a, 0x1000)) {
5619             fprintf(stderr, "Found waveform\n");
5620         }
5621         flag = readVRLength(name, &ptr, fd, &size, fileOffset, knownLength,
5622                             byteOrder, explicitVR, acceptVRMismatch, object,
5623                             scannedLength, &e);
5624         if (flag != DCM_NORMAL)
5625             goto abort;
5626 
5627         if ((e.representation == DCM_UNKNOWN) &&
5628             (e.length == DCM_UNSPECIFIEDLENGTH)) {
5629             e.representation = DCM_SQ;
5630         }
5631 #ifndef SMM
5632         if ((e.tag == DCM_DLMITEMDELIMITATIONITEM) ||
5633             (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)) {
5634             return DCM_NORMAL;
5635         }
5636 #else
5637         if (e.tag == DCM_DLMITEMDELIMITATIONITEM) {
5638             (*object)->objectSize -= 8;
5639             return DCM_NORMAL;
5640         }
5641         if (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)
5642             return DCM_NORMAL;
5643 #endif
5644 
5645         if (e.representation == DCM_SQ) {
5646             sequenceLength = e.length;
5647             scannedSequenceLength = 0;
5648             flag = readSequence(name, &ptr, fd, &sequenceLength,
5649                                 fileOffset, recursionLevel, opt,
5650                                 byteOrder, explicitVR, acceptVRMismatch,
5651                                 fileFlag, remainOpenFlag,
5652                                 convertFlag, object, &scannedSequenceLength,
5653                                 &e, &elementItem);
5654             if (flag != DCM_NORMAL)
5655                 goto abort;
5656             if (size != (long) DCM_UNSPECIFIEDLENGTH)
5657                 size -= scannedSequenceLength;
5658             if (scannedLength != NULL)
5659                 *scannedLength += scannedSequenceLength;
5660 
5661         } else {
5662 
5663             flag = readData(name, &ptr, fd, &size, fileOffset, knownLength,
5664                           byteOrder, explicitVR, acceptVRMismatch, fileFlag,
5665                             remainOpenFlag, convertFlag,
5666                             object, scannedLength, &e, &elementItem);
5667             if (flag != DCM_NORMAL)
5668                 goto abort;
5669         }
5670         computeVM(object, &elementItem->element);
5671 
5672         cond = checkAttributeOrder(&e, &lastGroup, &lastElement);
5673         if (cond != DCM_NORMAL)
5674              /* goto abort; ASG */ return cond;
5675 
5676         cond = handleGroupItem(object, &groupItem, DCM_TAG_GROUP(e.tag));
5677         if (cond != DCM_NORMAL)
5678              /* goto abort; ASG */ return cond;
5679 
5680         if (DCM_TAG_ELEMENT(e.tag) != 0x0000) {
5681             groupItem->baseLength += 8 + elementItem->paddedDataLength;
5682             if (elementItem->element.representation == DCM_OB ||
5683                 elementItem->element.representation == DCM_OW ||
5684                 elementItem->element.representation == DCM_SQ) {
5685                 groupItem->longVRAttributes++;
5686                 (*object)->longVRAttributes++;
5687             }
5688         }
5689         if ((DCM_TAG_ELEMENT(e.tag) == 0x0000) && ((*object)->groupLengthFlag == FALSE)) {
5690             CTN_FREE(elementItem);
5691         } else {
5692             cond = LST_Enqueue(&groupItem->elementList, elementItem);
5693             if (cond != LST_NORMAL) {
5694                 (void) DCM_CloseObject(callerObject);
5695                 return COND_PushCondition(DCM_LISTFAILURE,
5696                                           DCM_Message(DCM_LISTFAILURE),
5697                                           "readFile");
5698             }
5699             cond = updateObjectType(object, &elementItem->element);     /* repair */
5700 
5701             cond = updateSpecialElements(object, elementItem);  /* repair */
5702         }
5703 
5704         if (size == 0)
5705             done = TRUE;
5706 
5707         if (part10Flag) {
5708             if ((*object)->objectSize == (DCM_PREAMBLELENGTH + 4 + 12 + (*object)->metaHeaderLength)) {
5709                 opt &= ~DCM_ORDERMASK;
5710                 opt |= (*object)->dataOptions & DCM_ORDERMASK;
5711                 explicitVR = FALSE;
5712                 switch (opt & DCM_ORDERMASK) {
5713                 case DCM_ORDERNATIVE:
5714                     byteOrder = NATIVE_ORDER;
5715                     break;
5716                 case DCM_ORDERLITTLEENDIAN:
5717                     byteOrder = LITTLE_ORDER;
5718                     break;
5719                 case DCM_EXPLICITLITTLEENDIAN:
5720                     byteOrder = LITTLE_ORDER;
5721                     explicitVR = TRUE;
5722                     break;
5723                 case DCM_ORDERBIGENDIAN:
5724                     byteOrder = BIG_ORDER;
5725                     break;
5726                 case DCM_EXPLICITBIGENDIAN:
5727                     byteOrder = BIG_ORDER;
5728                     explicitVR = TRUE;
5729                     break;
5730                 default:
5731                     byteOrder = LITTLE_ORDER;
5732                     explicitVR = TRUE;
5733                     break;
5734                 }
5735             }
5736         }
5737     }
5738 
5739 #ifdef SMM
5740 #endif
5741 
5742     groupItem = LST_Head(&(*object)->groupList);
5743     if (groupItem != NULL) {
5744         (void) LST_Position(&(*object)->groupList, groupItem);
5745         while (groupItem != NULL) {
5746             elementItem = LST_Head(&groupItem->elementList);
5747             if (elementItem != NULL) {
5748                 if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
5749                     *elementItem->element.d.ul = groupItem->baseLength;
5750                 }
5751             }
5752             groupItem = LST_Next(&(*object)->groupList);
5753         }
5754     }
5755     return DCM_NORMAL;
5756 
5757 abort:
5758     return flag;
5759 }
5760 
5761 /* locateElement
5762 **
5763 ** Purpose:
5764 **      Locate the DICOM element with the specified tag number in the given
5765 **      DICOM object
5766 **
5767 ** Parameter Dictionary:
5768 **      obj             Handle to the DICOM object to be searched
5769 **      tag             Tag number of the element to be searched
5770 **
5771 ** Return Values:
5772 **      Pointer to the element if found else NULL
5773 **
5774 ** Notes:
5775 **
5776 ** Algorithm:
5777 **      Description of the algorithm (optional) and any other notes.
5778 */
5779 static PRV_ELEMENT_ITEM *
5780 locateElement(PRIVATE_OBJECT ** obj, DCM_TAG tag)
5781 {
5782     PRV_GROUP_ITEM
5783     * groupItem;
5784     PRV_ELEMENT_ITEM
5785         * elementItem;
5786     CTNBOOLEAN
5787         found = FALSE;
5788 
5789     groupItem = LST_Head(&(*obj)->groupList);
5790     if (groupItem == NULL)
5791         return NULL;
5792 
5793     (void) LST_Position(&(*obj)->groupList, groupItem);
5794     while (groupItem != NULL) {
5795         if (groupItem->group == DCM_TAG_GROUP(tag))
5796             break;
5797 
5798         groupItem = LST_Next(&(*obj)->groupList);
5799     }
5800     if (groupItem == NULL)
5801         return NULL;
5802 
5803     elementItem = LST_Head(&groupItem->elementList);
5804     if (elementItem == NULL)
5805         return NULL;
5806 
5807     (void) LST_Position(&groupItem->elementList, elementItem);
5808     while (!found && (elementItem != NULL)) {
5809         if (elementItem->element.tag == tag) {
5810             found = TRUE;
5811         } else
5812             elementItem = LST_Next(&groupItem->elementList);
5813     }
5814     if (found)
5815         return elementItem;
5816     else
5817         return NULL;
5818 }
5819 
5820 /* computeVM
5821 **
5822 ** Purpose:
5823 **      Compute the multiplicity of the specified element in the DICOM
5824 **      object
5825 **
5826 ** Parameter Dictionary:
5827 **      object          Handle to the DICOM object
5828 **      element         Element whose value multiplicity is to be found out.
5829 **
5830 ** Return Values:
5831 **      None
5832 **
5833 ** Notes:
5834 **
5835 ** Algorithm:
5836 **      Description of the algorithm (optional) and any other notes.
5837 */
5838 static void
5839 computeVM(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
5840 {
5841     char
5842        *c;
5843     int
5844         i;
5845 
5846     switch (element->representation) {
5847     case DCM_AE:                /* Application Entity */
5848     case DCM_AS:                /* Age string */
5849     case DCM_CS:                /* Control string */
5850     case DCM_DA:                /* Date */
5851     case DCM_DS:                /* Decimal string */
5852     case DCM_DT:                /* Date/Time */
5853     case DCM_IS:                /* Integer string */
5854     case DCM_LO:                /* Long string */
5855     case DCM_PN:                /* Person Name */
5856     case DCM_SH:                /* Short string */
5857     case DCM_TM:                /* Time */
5858     case DCM_UI:                /* Unique identifier (UID) */
5859         element->multiplicity = 1;
5860         c = element->d.string;
5861         for (i = 0; i < (int) element->length; i++)
5862             if (*c++ == '\\')
5863                 element->multiplicity++;
5864         break;
5865 
5866     case DCM_FD:                /* Floating double */
5867         element->multiplicity = element->length / 8;
5868         break;
5869     case DCM_AT:                /* Attribute tag */
5870     case DCM_FL:                /* Float */
5871     case DCM_SL:                /* Signed long */
5872     case DCM_UL:                /* Unsigned long */
5873         element->multiplicity = element->length / 4;
5874         break;
5875     case DCM_SS:                /* Signed short */
5876     case DCM_US:                /* Unsigned short */
5877         element->multiplicity = element->length / 2;
5878         break;
5879     case DCM_LT:                /* Long text */
5880     case DCM_OT:                /* Other binary value */
5881     case DCM_SQ:                /* Sequence of items */
5882     case DCM_ST:                /* Short text */
5883     case DCM_UNKNOWN:
5884     case DCM_RET:
5885     case DCM_CTX:
5886     case DCM_DD:                /* Data set */
5887     default:
5888         element->multiplicity = 1;
5889         break;
5890     }
5891 }
5892 /* ctxSensitiveLookup
5893 **
5894 ** Purpose:
5895 **      Lookup representation of elements that are context sensitive
5896 **
5897 ** Parameter Dictionary:
5898 **      object          Handle to the DICOM object containing this element.
5899 **      element         Element who representation is to be determined.
5900 **
5901 ** Return Values:
5902 **      None
5903 **
5904 ** Notes:
5905 **
5906 */
5907 static void
5908 ctxSensitiveLookup(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
5909 {
5910     switch (element->tag) {
5911         case DCM_IMGSMALLESTIMAGEPIXELVALUE:
5912         case DCM_IMGLARGESTIMAGEPIXELVALUE:
5913         case DCM_IMGSMALLESTPIXELVALUESERIES:
5914         case DCM_IMGLARGESTPIXELVALUESERIES:
5915         case DCM_IMGSMALLESTIMAGEPIXELVALUEPLANE:
5916         case DCM_IMGLARGESTIMAGEPIXELVALUEPLANE:
5917         case DCM_IMGLUTDESCRIPTOR:
5918         case DCM_IMGLUTDATA:
5919         case DCM_IMGLOOKUPDATARED:
5920         case DCM_IMGLOOKUPDATAGREEN:
5921         case DCM_IMGLOOKUPDATABLUE:
5922         if ((*object)->pixelRepresentation == 0x0000)
5923             element->representation = DCM_US;
5924         else if ((*object)->pixelRepresentation == 0x0001)
5925             element->representation = DCM_SS;
5926         else
5927             element->representation = DCM_US;
5928         break;
5929     case DCM_MAKETAG(0x003a, 0x1000):
5930         if (strcmp((*object)->waveformDataVR, "SS") == 0)
5931             element->representation = DCM_SS;
5932         break;
5933 
5934     default:
5935         break;
5936     }
5937 }
5938 
5939 static CONDITION
5940 copyData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * from,
5941          DCM_ELEMENT * to, U32 * rtnLength)
5942 {
5943     unsigned char *p = NULL;
5944     U32 l;
5945     int nBytes;
5946     CONDITION cond;
5947 
5948     if (from->element.representation == DCM_SQ)
5949         return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
5950                                   DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
5951                               from->element.tag, "copyData (DCM internal)");
5952 
5953     l = MIN(from->element.length, to->length);
5954     if (rtnLength != NULL)
5955         *rtnLength = l;
5956 
5957     if (from->element.d.ot == NULL) {
5958         if ((*object)->fd != -1) {
5959             (void) lseek((*object)->fd,
5960                          from->dataOffset + (off_t) p, SEEK_SET);
5961             nBytes = read((*object)->fd, to->d.ot, (int) l);
5962         } else {
5963             (*object)->sk((*object)->userCtx,
5964                           (long) (from->dataOffset + (off_t) p), SEEK_SET);
5965             cond = (*object)->rd((*object)->userCtx, to->d.ot, (long) l, &nBytes);
5966         }
5967         if (nBytes != (int) l) {
5968             return COND_PushCondition(DCM_FILEACCESSERROR,
5969                                       DCM_Message(DCM_FILEACCESSERROR),
5970                                       (*object)->fileName,
5971                                       "copyData (DCM internal)");
5972         }
5973 #ifdef LITTLE_ENDIAN_ARCHITECTURE
5974         if (from->element.representation == DCM_AT) {
5975             DCM_ELEMENT e;
5976             e = from->element;
5977             e.length = l;
5978             e.d.ot = to->d.ot;
5979             swapATGroupElement(&e);
5980         }
5981 #endif
5982         if (from->byteOrder == BYTEORDER_REVERSE) {
5983             DCM_ELEMENT e;
5984             e = from->element;
5985             e.length = l;
5986             e.d.ot = to->d.ot;
5987             swapInPlace(object, &e);
5988         }
5989     } else {
5990         unsigned char *q;
5991         q = (unsigned char *) from->element.d.ot +
5992             (U32) p;
5993         (void) memcpy(to->d.ot, q, l);
5994     }
5995     p += l;
5996     if ((unsigned) p == from->element.length)
5997         return DCM_NORMAL;
5998     else
5999         return DCM_GETINCOMPLETE;
6000 }
6001 
6002 static CONDITION
6003 readLengthToEnd(int fd, const char *fileName,
6004                 unsigned long opt, U32 * lengthToEnd)
6005 {
6006     unsigned char buf[24];
6007     DCM_OBJECT *obj;
6008     CONDITION cond;
6009     DCM_ELEMENT e = {DCM_MAKETAG(0x0008, 0x0001), DCM_UL, "", 1, 4, NULL};
6010     void *ctx = NULL;
6011     U32 rtnLength = 0;
6012 
6013     if (read(fd, buf, 24) != 24)
6014         return COND_PushCondition(DCM_FILEACCESSERROR,
6015                                   DCM_Message(DCM_FILEACCESSERROR), fileName,
6016                                   "(DCM)readLengthToEnd");
6017 
6018     cond = DCM_ImportStream(buf, 24, opt, &obj);
6019     if (cond != DCM_NORMAL)
6020         return cond;
6021 
6022     e.d.ul = lengthToEnd;
6023     cond = DCM_GetElementValue(&obj, &e, &rtnLength, &ctx);
6024 
6025     (void) DCM_CloseObject(&obj);
6026 
6027     return cond;
6028 }
6029 
6030 #ifdef LITTLE_ENDIAN_ARCHITECTURE
6031 static void
6032 swapATGroupElement(DCM_ELEMENT * e)
6033 {
6034     U32
6035     length;
6036     unsigned short
6037         tmp,
6038        *us;
6039 
6040     length = e->length;
6041     us = e->d.us;
6042     while (length >= 4) {
6043         tmp = us[0];
6044         us[0] = us[1];
6045         us[1] = tmp;
6046         us += 2;
6047         length -= 4;
6048     }
6049 }
6050 #endif
6051 
6052 static void
6053 dumpSS(short *ss, long vm)
6054 {
6055     long index = 0;
6056     while (index < vm) {
6057         printf("%7d ", *(ss++));
6058         if ((++index) % 8 == 0)
6059             printf("\n");
6060     }
6061     printf("\n");
6062 }
6063 
6064 static void
6065 dumpSL(S32 * sl, long vm)
6066 {
6067     long index = 0;
6068     while (index < vm) {
6069         printf("%7d ", *(sl++));
6070         if ((++index) % 8 == 0)
6071             printf("\n");
6072     }
6073     printf("\n");
6074 }
6075 
6076 static void
6077 dumpUS(unsigned short *us, long vm)
6078 {
6079     long index = 0;
6080     while (index < vm) {
6081         printf("%7d ", *(us++));
6082         if ((++index) % 8 == 0)
6083             printf("\n");
6084     }
6085     printf("\n");
6086 }
6087 static void
6088 dumpUL(U32 * ul, long vm)
6089 {
6090     long index = 0;
6091     while (index < vm) {
6092         printf("%7d ", *(ul++));
6093         if ((++index) % 8 == 0)
6094             printf("\n");
6095     }
6096     printf("\n");
6097 }
6098 
6099 static void
6100 dumpBinaryData(void *d, DCM_VALUEREPRESENTATION vr, long vm,
6101                long vmLimit)
6102 {
6103     vm = (vm < vmLimit) ? vm : vmLimit;
6104 
6105     if (vm <= 1)
6106         return;
6107 
6108 
6109     switch (vr) {
6110     case DCM_SL:
6111         dumpSL((S32 *) d, vm);
6112         break;
6113     case DCM_UL:
6114         dumpUL((U32 *) d, vm);
6115         break;
6116     case DCM_SS:
6117         dumpSS((short *) d, vm);
6118         break;
6119     case DCM_US:
6120         dumpUS((unsigned short *) d, vm);
6121         break;
6122     default:
6123         break;
6124     }
6125 }
6126 
6127 static void
6128 compareGroup(PRV_GROUP_ITEM * g1, PRV_GROUP_ITEM * g2,
6129              void (*callback) (const DCM_ELEMENT * e1,
6130                                const DCM_ELEMENT * e2,
6131                                void *ctx),
6132              void *ctx)
6133 {
6134     PRV_ELEMENT_ITEM *e1 = NULL,
6135        *e2 = NULL;
6136 
6137     if (g1 != NULL) {
6138         e1 = LST_Head(&g1->elementList);
6139         if (e1 != NULL)
6140             LST_Position(&g1->elementList, e1);
6141     }
6142     if (g2 != NULL) {
6143         e2 = LST_Head(&g2->elementList);
6144         if (e2 != NULL)
6145             LST_Position(&g2->elementList, e2);
6146     }
6147     while (e1 != NULL) {
6148         if (e2 == NULL) {
6149             callback(&e1->element, NULL, ctx);
6150             e1 = LST_Next(&g1->elementList);
6151         } else if (e1->element.tag == e2->element.tag) {
6152             callback(&e1->element, &e2->element, ctx);
6153             e1 = LST_Next(&g1->elementList);
6154             e2 = LST_Next(&g2->elementList);
6155         } else if (e1->element.tag < e2->element.tag) {
6156             callback(&e1->element, NULL, ctx);
6157             e1 = LST_Next(&g1->elementList);
6158         } else {
6159             callback(NULL, &e2->element, ctx);
6160             e2 = LST_Next(&g2->elementList);
6161         }
6162     }
6163 
6164     while (e2 != NULL) {
6165         callback(NULL, &e2->element, ctx);
6166         e2 = LST_Next(&g2->elementList);
6167     }
6168 }
6169 
6170 static void
6171 remapFileName(const char *name, char *mapName)
6172 {
6173     char c;
6174 
6175     while ((c = *name++) != '\0') {
6176         if (c == '\\')
6177             *mapName++ = '/';
6178         else if (isupper(c))
6179             *mapName++ = tolower(c);
6180         else
6181             *mapName++ = c;
6182     }
6183     *mapName = '\0';
6184 }
6185 
6186 static void
6187 copySequence(PRIVATE_OBJECT ** dstObj, DCM_ELEMENT * e)
6188 {
6189     LST_HEAD *lst;
6190     DCM_SEQUENCE_ITEM *sqItem;
6191     DCM_ELEMENT newElement;
6192 
6193     lst = LST_Create();
6194     if (e->d.sq != NULL) {
6195         sqItem = LST_Head(&e->d.sq);
6196         (void) LST_Position(&e->d.sq, sqItem);
6197     }
6198     while (sqItem != NULL) {
6199         DCM_OBJECT *copy;
6200         DCM_SEQUENCE_ITEM *copyItem;
6201 
6202         DCM_CopyObject(&sqItem->object, &copy);
6203         copyItem = malloc(sizeof(*copyItem));
6204         copyItem->object = copy;
6205         (void) LST_Enqueue(&lst, copyItem);
6206 
6207         sqItem = LST_Next(&e->d.sq);
6208     }
6209 
6210     memset(&newElement, 0, sizeof(newElement));
6211     newElement.tag = e->tag;
6212     newElement.representation = e->representation;
6213     newElement.d.sq = lst;
6214     DCM_AddSequenceElement((DCM_OBJECT **) dstObj, &newElement);
6215 }
6216 
6217 /* Restart public functions */
6218 
6219 CONDITION
6220 DCM_GetCompressedValue(DCM_OBJECT ** callerObject, DCM_TAG tag, void *buf,
6221                        size_t bufSize,
6222                        CONDITION(*callback) (void *buf, U32 bytesExported, int index, int startFlag, int lastFlag, void *ctx),
6223                        void *ctx)
6224 {
6225     PRIVATE_OBJECT
6226         ** object;
6227     PRV_ELEMENT_ITEM
6228         * elementItem;
6229     S32 nBytes;
6230     S32 toRead;
6231     CONDITION cond;
6232     int doneFlag = 0;
6233     size_t elementLength;
6234     unsigned char *ptr;
6235     U32 size = 0;
6236     off_t fileOffset = 0;
6237     unsigned long opt;
6238     int byteOrder;
6239     int explicitVR;
6240     CTNBOOLEAN acceptVRMismatch = FALSE;
6241     DCM_ELEMENT e;
6242     U32 sequenceLength = 0;
6243     CONDITION flag;
6244     int index = 0;
6245     CTNBOOLEAN firstBuffer = TRUE;
6246     U32 *offsetBuffer = NULL;
6247     U32 offsetBufferCount = 0;
6248     U32 streamOffset = 0;
6249 
6250     object = (PRIVATE_OBJECT **) callerObject;
6251     cond = checkObject(object, "DCM_GetCompressedValue");
6252     if (cond != DCM_NORMAL)
6253         return cond;
6254 
6255     elementItem = locateElement(object, tag);
6256 
6257     if (elementItem == NULL)
6258         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
6259                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
6260                                   DCM_TAG_ELEMENT(tag),
6261                                   "DCM_GetEncodedValue");
6262 
6263     elementLength = elementItem->originalDataLength;
6264     ptr = NULL;                 /* Means reading from a file */
6265     size = DCM_UNSPECIFIEDLENGTH;
6266     fileOffset = elementItem->dataOffset;
6267 
6268     opt |= (*object)->dataOptions & DCM_ORDERMASK;
6269     explicitVR = FALSE;
6270     switch (opt & DCM_ORDERMASK) {
6271     case DCM_ORDERNATIVE:
6272         byteOrder = NATIVE_ORDER;
6273         break;
6274     case DCM_ORDERLITTLEENDIAN:
6275         byteOrder = LITTLE_ORDER;
6276         break;
6277     case DCM_EXPLICITLITTLEENDIAN:
6278         byteOrder = LITTLE_ORDER;
6279         explicitVR = TRUE;
6280         break;
6281     case DCM_ORDERBIGENDIAN:
6282         byteOrder = BIG_ORDER;
6283         break;
6284     case DCM_EXPLICITBIGENDIAN:
6285         byteOrder = BIG_ORDER;
6286         explicitVR = TRUE;
6287         break;
6288     default:
6289         byteOrder = LITTLE_ORDER;
6290         explicitVR = TRUE;
6291         break;
6292     }
6293     if ((opt & DCM_VRMASK) == DCM_ACCEPTVRMISMATCH)
6294         acceptVRMismatch = TRUE;
6295 
6296     (void) lseek((*object)->fd, elementItem->dataOffset, SEEK_SET);
6297     while (elementLength != 0) {
6298         sequenceLength = 0;
6299         memset(&e, 0, sizeof(e));
6300         flag = readGroupElement("", &ptr, (*object)->fd, &size, &fileOffset,
6301                              FALSE, byteOrder, explicitVR, acceptVRMismatch,
6302                                 object, &sequenceLength, &e);
6303         if (flag == DCM_STREAMCOMPLETE)
6304             break;
6305         else if (flag != DCM_NORMAL)
6306             return flag;
6307 
6308         flag = readVRLength("", &ptr, (*object)->fd, &size, &fileOffset,
6309                             FALSE,      /* Known length */
6310                             byteOrder, explicitVR, acceptVRMismatch, object,
6311                             &sequenceLength, &e);
6312         if (flag != DCM_NORMAL)
6313             return flag;
6314 
6315         elementLength -= sequenceLength + e.length;
6316 
6317         if (firstBuffer) {
6318             firstBuffer = FALSE;
6319             if (e.length != 0) {
6320                 offsetBuffer = CTN_MALLOC(e.length);
6321                 offsetBufferCount = e.length / sizeof(U32);
6322                 if (offsetBuffer == NULL)
6323                     exit(1);    /* repair */
6324                 nBytes = read((*object)->fd, offsetBuffer, e.length);
6325                 if (nBytes != e.length) {
6326                     exit(1);    /* repair */
6327                 }
6328                 if (byteOrder == BYTEORDER_REVERSE) {
6329                     DCM_ELEMENT offsetBufferElement;
6330                     memset(&offsetBufferElement, 0, sizeof(DCM_ELEMENT));
6331                     offsetBufferElement.length = e.length;
6332                     offsetBufferElement.d.ul = offsetBuffer;
6333                     offsetBufferElement.representation = DCM_UL;
6334                     swapInPlace(object, &offsetBufferElement);
6335                 }
6336                 callback(offsetBuffer, e.length, index, 1, 0, ctx);
6337                 streamOffset = 0;
6338             } else {
6339                 streamOffset = 0xffffffff;
6340             }
6341         } else {
6342             U32 l = e.length;
6343             int j;
6344             int lastIndex;
6345 
6346             lastIndex = index;
6347             for (j = 0; j < offsetBufferCount; j++) {
6348                 if (streamOffset == offsetBuffer[j])
6349                     index = j + 1;
6350             }
6351             do {
6352                 toRead = MIN(bufSize, l);
6353                 nBytes = read((*object)->fd, buf, toRead);
6354                 if (nBytes != toRead) {
6355                     exit(1);    /* repair */
6356                 }
6357                 callback(buf, toRead, index,
6358                          (index != lastIndex) ? 1 : 0,
6359                          0, ctx);
6360                 l -= toRead;
6361                 lastIndex = index;      /* Guarantee first flag is off */
6362             } while (l != 0);
6363             streamOffset += sequenceLength + e.length;
6364         }
6365         fileOffset += e.length;
6366         /* index++; */
6367     }
6368     callback(buf, 0, index, 0, 1, ctx);
6369     return DCM_NORMAL;
6370 }
6371 
6372 CONDITION
6373 DCM_PrintSequenceList(DCM_OBJECT ** object, DCM_TAG tag)
6374 {
6375     PRIVATE_OBJECT **obj,
6376        *sqObject;
6377     CONDITION cond;
6378     PRV_ELEMENT_ITEM *elementItem;
6379     LST_HEAD *lst;
6380     DCM_SEQUENCE_ITEM *sqItem;
6381 
6382     obj = (PRIVATE_OBJECT **) object;
6383     cond = checkObject(obj, "DCM_PrintSequenceList");
6384     if (cond != DCM_NORMAL)
6385         return cond;
6386 
6387     elementItem = locateElement(obj, tag);
6388 
6389     if (elementItem == NULL)
6390         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
6391                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
6392                                   DCM_TAG_ELEMENT(tag),
6393                                   "DCM_PrintSequenceList");
6394 
6395     lst = elementItem->element.d.sq;
6396     sqItem = LST_Head(&lst);
6397     (void) LST_Position(&lst, sqItem);
6398     while (sqItem != NULL) {
6399         sqObject = (PRIVATE_OBJECT *) sqItem->object;
6400         printf("size: %6d offset: %6d, pixel offset: %6d\n",
6401                sqObject->objectSize,
6402                sqObject->offset,
6403                sqObject->pixelOffset);
6404         sqItem = LST_Next(&lst);
6405     }
6406 }
6407 
6408 CONDITION
6409 DCM_GetSequenceByOffset(DCM_OBJECT ** object, DCM_TAG tag, unsigned long offset,
6410                         DCM_OBJECT ** rtnObject)
6411 {
6412     PRIVATE_OBJECT **obj,
6413        *sqObject;
6414     CONDITION cond;
6415     PRV_ELEMENT_ITEM *elementItem;
6416     LST_HEAD *lst;
6417     DCM_SEQUENCE_ITEM *sqItem;
6418 
6419     obj = (PRIVATE_OBJECT **) object;
6420     cond = checkObject(obj, "DCM_PrintSequenceList");
6421     if (cond != DCM_NORMAL)
6422         return cond;
6423 
6424     elementItem = locateElement(obj, tag);
6425 
6426     if (elementItem == NULL)
6427         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
6428                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
6429                                   DCM_TAG_ELEMENT(tag),
6430                                   "DCM_PrintSequenceList");
6431 
6432     lst = elementItem->element.d.sq;
6433     sqItem = LST_Head(&lst);
6434     (void) LST_Position(&lst, sqItem);
6435     while (sqItem != NULL) {
6436         sqObject = (PRIVATE_OBJECT *) sqItem->object;
6437         if (sqObject->offset == offset) {
6438             *rtnObject = sqItem->object;
6439             return DCM_NORMAL;
6440         }
6441         sqItem = LST_Next(&lst);
6442     }
6443     return 0;
6444 }
6445 
6446 CONDITION
6447 DCM_CopyObject(DCM_OBJECT ** src, DCM_OBJECT ** dst)
6448 {
6449     PRIVATE_OBJECT **srcObj;
6450     PRIVATE_OBJECT *dstObj;
6451     PRV_GROUP_ITEM *groupItem;
6452     PRV_ELEMENT_ITEM *elementItem;
6453 
6454     if (src == NULL) {
6455         (void) COND_PushCondition(DCM_NULLADDRESS,
6456                             DCM_Message(DCM_NULLADDRESS), "DCM_CopyObject");
6457         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
6458                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CopyObject");
6459     }
6460     dstObj = (PRIVATE_OBJECT *) CTN_MALLOC(sizeof(PRIVATE_OBJECT));
6461     if (dstObj == NULL) {
6462         (void) COND_PushCondition(DCM_MALLOCFAILURE,
6463                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
6464                                   "DCM_CopyObject");
6465         *dst = NULL;
6466         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
6467                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CopyObject");
6468     }
6469     (void) memset(dstObj, 0, sizeof(PRIVATE_OBJECT));
6470     (void) strcpy(dstObj->keyType, KEY_DCM_OBJECT);
6471 
6472     dstObj->objectType = DCM_OBJECTUNKNOWN;
6473     dstObj->accessMethod = DCM_MEMORY_ACCESS;
6474     dstObj->deleteFlag = FALSE;
6475     dstObj->groupLengthFlag = FALSE;
6476     dstObj->objectSize = 0;
6477     dstObj->offset = 0;
6478     dstObj->pixelSize = 0;
6479     dstObj->pixelOffset = 0;
6480     dstObj->pixelBitsAllocated = 0;
6481     dstObj->pixelRepresentation = 0xffff;
6482     dstObj->groupCtx = NULL;
6483     dstObj->elementCtx = NULL;
6484     dstObj->fd = -1;
6485     dstObj->fileName[0] = '\0';
6486     dstObj->preambleFlag = FALSE;
6487     dstObj->preamble[0] = '\0';
6488     dstObj->dataOptions = 0;
6489     dstObj->metaHeaderLength = 0xffffffff;
6490     dstObj->longVRAttributes = 0;
6491     dstObj->waveformDataVR[0] = '\0';
6492 
6493     dstObj->groupList = LST_Create();
6494     if (dstObj->groupList == NULL) {
6495         CTN_FREE(dstObj);
6496         *dst = NULL;
6497         return COND_PushCondition(DCM_LISTFAILURE,
6498                                   DCM_Message(DCM_LISTFAILURE),
6499                                   "DCM_CreateObject");
6500     }
6501     srcObj = (PRIVATE_OBJECT **) src;
6502 
6503     groupItem = LST_Head(&(*srcObj)->groupList);
6504     if (groupItem != NULL)
6505         (void) LST_Position(&(*srcObj)->groupList, groupItem);
6506 
6507     while (groupItem != NULL) {
6508         elementItem = LST_Head(&groupItem->elementList);
6509         if (elementItem != NULL)
6510             (void) LST_Position(&groupItem->elementList, elementItem);
6511         while (elementItem != NULL) {
6512             if (elementItem->element.representation == DCM_SQ) {
6513                 copySequence(&dstObj, &elementItem->element);
6514             } else {
6515                 DCM_AddElement((DCM_OBJECT **) & dstObj, &elementItem->element);
6516             }
6517             elementItem = LST_Next(&groupItem->elementList);
6518         }
6519         groupItem = LST_Next(&(*srcObj)->groupList);
6520     }
6521 
6522     *dst = (DCM_OBJECT *) dstObj;
6523     return DCM_NORMAL;
6524 }
6525 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.