Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

mri_dicom_hdr.c

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*****************************************************************************/
00003 /*** Function to read DICOM images into memory.
00004      Adapted from dcm_dump_file.c (et cetera) from the RSNA.
00005      July 2002 -- RW Cox -- NIMH/NIH/PHS/HHS/USA                           ***/
00006 /*****************************************************************************/
00007 /*****************************************************************************/
00008 
00009 /*
00010           Copyright (C) 1993, 1994, RSNA and Washington University
00011 
00012           The software and supporting documentation for the Radiological
00013           Society of North America (RSNA) 1993, 1994 Digital Imaging and
00014           Communications in Medicine (DICOM) Demonstration were developed
00015           at the
00016                   Electronic Radiology Laboratory
00017                   Mallinckrodt Institute of Radiology
00018                   Washington University School of Medicine
00019                   510 S. Kingshighway Blvd.
00020                   St. Louis, MO 63110
00021           as part of the 1993, 1994 DICOM Central Test Node project for, and
00022           under contract with, the Radiological Society of North America.
00023 
00024           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00025           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00026           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00027           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00028           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00029           THE SOFTWARE IS WITH THE USER.
00030 
00031           Copyright of the software and supporting documentation is
00032           jointly owned by RSNA and Washington University, and free access
00033           is hereby granted as a license to use this software, copy this
00034           software and prepare derivative works based upon this software.
00035           However, any distribution of this software source code or
00036           supporting documentation or derivative works (source code and
00037           supporting documentation) must include the three paragraphs of
00038           the copyright notice.
00039 */
00040 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
00041 /*
00042 **                              DICOM 93
00043 **                   Electronic Radiology Laboratory
00044 **                 Mallinckrodt Institute of Radiology
00045 **              Washington University School of Medicine
00046 **
00047 ** Author, Date:        Stephen M. Moore, 9-May-93
00048 ** Intent:              This program uses the DICOM OBJECTS package to open
00049 **                      DICOM files and dump their contents to stdout.  Each
00050 **                      argument to the program is expected to be the name
00051 **                      of a file containing a DICOM stream.
00052 **   Usage:
00053 **                      dcm_dump_file [-b] [-g] [-v] [-z] file [file ...]
00054 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
00055 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
00056 ** Revision:            $Revision: 1.21 $
00057 ** Status:              $State: Exp $
00058 */
00059 
00060 #include <stdio.h>
00061 #include <stdlib.h>
00062 #include <string.h>
00063 #include <sys/types.h>
00064 #include <errno.h>
00065 #include <stdlib.h>
00066 #include <stdarg.h>
00067 #include <ctype.h>
00068 
00069 #include "mri_dicom_hdr.h"
00070 
00071 #include "mcw_malloc.h"
00072 #include "Amalloc.h"
00073 #include "debugtrace.h"    /* 10 Sep 2002 */
00074 
00075 /****************************************************************/
00076 /***** Function and variables to set byte order of this CPU *****/
00077 /****************************************************************/
00078 #define BYTEORDER_SAME        1
00079 #define BYTEORDER_REVERSE     2
00080 #define NATIVE_ORDER          BYTEORDER_SAME
00081 
00082 static int LITTLE_ORDER ;
00083 static int BIG_ORDER ;
00084 static int LITTLE_ENDIAN_ARCHITECTURE = -1 ;
00085 
00086 static void RWC_set_endianosity(void)
00087 {
00088    union { unsigned char bb[2] ;
00089            short         ss    ; } fred ;
00090 
00091    if( LITTLE_ENDIAN_ARCHITECTURE < 0 ){
00092      fred.bb[0] = 1 ; fred.bb[1] = 0 ;
00093 
00094      LITTLE_ENDIAN_ARCHITECTURE = (fred.ss == 1) ;
00095 
00096      if( LITTLE_ENDIAN_ARCHITECTURE ){
00097        LITTLE_ORDER = BYTEORDER_SAME ;
00098        BIG_ORDER    = BYTEORDER_REVERSE ;
00099      } else {
00100        BIG_ORDER    = BYTEORDER_SAME ;
00101        LITTLE_ORDER = BYTEORDER_REVERSE ;
00102      }
00103    }
00104 }
00105 
00106 /****************************************************************/
00107 /***** Function and variables to replace printf() ***************/
00108 
00109 static char *pbuf = NULL ;
00110 static int  npbuf = 0 ;
00111 
00112 #define NPBUF 1024
00113 
00114 static void RWC_clear_pbuf(void)
00115 {
00116    if( pbuf != NULL ){ free(pbuf); pbuf = NULL; npbuf = 0; }
00117 }
00118 
00119 static int RWC_printf( char *fmt , ... )
00120 {
00121    static char *sbuf = NULL ;
00122    int nsbuf , nn , lpbuf ;
00123    va_list vararg_ptr ;
00124 
00125    va_start( vararg_ptr , fmt ) ;
00126 
00127    if( sbuf == NULL ) sbuf = AFMALL( char, NPBUF) ;  /* 1st time in */
00128 
00129    sbuf[0] = '\0' ;
00130    nn = vsprintf( sbuf , fmt , vararg_ptr ) ;
00131    va_end( vararg_ptr ) ;
00132    nsbuf = strlen(sbuf) ;
00133    if( nsbuf == 0 ) return(0);
00134 
00135    if( npbuf == 0 ){
00136      pbuf = AFMALL(char,NPBUF) ; npbuf = NPBUF ; pbuf[0] = '\0' ;
00137    }
00138 
00139    lpbuf = strlen(pbuf) ;
00140    if( lpbuf+nsbuf+8 > npbuf ){
00141      npbuf += NPBUF; pbuf = AFREALL( pbuf, char, npbuf);
00142    }
00143 
00144    strcat(pbuf,sbuf) ;
00145    return(nn);
00146 }
00147 
00148 /****************************************************************/
00149 
00150 static off_t        pxl_off = 0 ;  /* store pixel array offset */
00151 static unsigned int pxl_len = 0 ;  /* and length in file */
00152 
00153 void mri_dicom_pxlarr( off_t *poff , unsigned int *plen )
00154 {
00155    *poff = pxl_off ; *plen = pxl_len ;
00156 }
00157 
00158 /****************************************************************/
00159 
00160 static int rwc_opt = 0 ;
00161 
00162 #define RWC_NONAME_MASK  1
00163 #define RWC_NOHEX_MASK   2
00164 
00165 void mri_dicom_noname( int ii )
00166 {
00167    if( ii )
00168      rwc_opt |= RWC_NONAME_MASK ;
00169    else if( rwc_opt & RWC_NONAME_MASK )
00170      rwc_opt ^= RWC_NONAME_MASK ;
00171 }
00172 
00173 void mri_dicom_nohex( int ii )
00174 {
00175    if( ii )
00176      rwc_opt |= RWC_NOHEX_MASK ;
00177    else if( rwc_opt & RWC_NOHEX_MASK )
00178      rwc_opt ^= RWC_NOHEX_MASK ;
00179 }
00180 
00181 /****************************************************************/
00182 
00183 static int rwc_vm=0 ;                     /* 28 Oct 2002 */
00184 
00185 void mri_dicom_setvm( int vv )
00186 {
00187   rwc_vm = vv ;
00188 }
00189 
00190 /****************************************************************/
00191 
00192 static int rwc_err=1 ;                     /* 28 Oct 2002 */
00193 
00194 void mri_dicom_seterr( int vv )
00195 {
00196   rwc_err = vv ;   /* 07 May 2003: an error will subtract 1 from rwc_err */
00197 }
00198 
00199 /****************************************************************/
00200 
00201 static int rwc_fd ;  /* 10 Sep 2002 */
00202 
00203 char * mri_dicom_header( char *fname )
00204 {
00205     DCM_OBJECT * object;
00206     CONDITION cond;
00207     CTNBOOLEAN verbose = FALSE ,
00208                exitFlag = FALSE,
00209                formatFlag = FALSE;
00210     unsigned long
00211         options = DCM_ORDERLITTLEENDIAN;
00212     long vmLimit = rwc_vm ;             /* 28 Oct 2002 */
00213     LST_HEAD* fileNames = 0;
00214     UTL_FILEITEM* p = NULL;
00215 
00216     char *ppp=NULL ;
00217 
00218 ENTRY("mri_dicom_header") ;
00219 
00220     if( fname == NULL ) RETURN(NULL) ;
00221 
00222     RWC_set_endianosity() ;
00223 
00224     { char *eee = getenv("AFNI_TRACE") ;
00225       if( eee!=NULL && (*eee=='y' || *eee=='Y') ) verbose = TRUE ;
00226     }
00227 
00228     DCM_Debug(verbose);
00229 
00230     RWC_clear_pbuf() ; pxl_len = 0 ; pxl_off = 0 ;
00231 
00232 STATUS(fname) ;
00233     rwc_fd = -1 ;
00234     cond = DCM_OpenFile(fname, options, &object);
00235     if (cond != DCM_NORMAL && ((options & DCM_PART10FILE) == 0)) {
00236 STATUS("DCM_OpenFile open failed; try again as Part 10") ;
00237       (void) DCM_CloseObject(&object);
00238       (void) COND_PopCondition(TRUE);
00239       if( rwc_fd >= 0 ){ close(rwc_fd); rwc_fd = -1; }
00240       cond = DCM_OpenFile(fname, options | DCM_PART10FILE, &object);
00241     }
00242     if (cond == DCM_NORMAL) {
00243 STATUS("DCM_OpenFile is good") ;
00244        RWC_printf("DICOM File: %s\n", fname);
00245        if (formatFlag)
00246          cond = DCM_FormatElements(&object, vmLimit, "");
00247        else
00248          cond = DCM_DumpElements(&object, vmLimit);
00249     } else {
00250 STATUS("DCM_OpenFile failed") ;
00251     }
00252     (void) DCM_CloseObject(&object);
00253     (void) COND_PopCondition(TRUE);
00254 
00255     if( pbuf != NULL ){
00256       ppp = strdup(pbuf) ; RWC_clear_pbuf() ;
00257     }
00258 
00259     if( rwc_fd >= 0 ){ close(rwc_fd); rwc_fd = -1; }
00260 
00261     RETURN(ppp);
00262 }
00263 
00264 /*
00265           Copyright (C) 1993, 1994, RSNA and Washington University
00266 
00267           The software and supporting documentation for the Radiological
00268           Society of North America (RSNA) 1993, 1994 Digital Imaging and
00269           Communications in Medicine (DICOM) Demonstration were developed
00270           at the
00271                   Electronic Radiology Laboratory
00272                   Mallinckrodt Institute of Radiology
00273                   Washington University School of Medicine
00274                   510 S. Kingshighway Blvd.
00275                   St. Louis, MO 63110
00276           as part of the 1993, 1994 DICOM Central Test Node project for, and
00277           under contract with, the Radiological Society of North America.
00278 
00279           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00280           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00281           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00282           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00283           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00284           THE SOFTWARE IS WITH THE USER.
00285 
00286           Copyright of the software and supporting documentation is
00287           jointly owned by RSNA and Washington University, and free access
00288           is hereby granted as a license to use this software, copy this
00289           software and prepare derivative works based upon this software.
00290           However, any distribution of this software source code or
00291           supporting documentation or derivative works (source code and
00292           supporting documentation) must include the three paragraphs of
00293           the copyright notice.
00294 */
00295 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
00296 /*
00297 ** @$=@$=@$=
00298 */
00299 /*
00300 **                              DICOM 93
00301 **                   Electronic Radiology Laboratory
00302 **                 Mallinckrodt Institute of Radiology
00303 **              Washington University School of Medicine
00304 **
00305 ** Module Name(s):      COND_PushCondition
00306 **                      COND_ExtractConditions
00307 **                      COND_TopCondition
00308 **                      COND_PopCondition
00309 **                      COND_DumpConditions
00310 **                      COND_CopyText
00311 **                      COND_WriteConditions
00312 ** Author, Date:        Stephen M. Moore, 15-Apr-93
00313 ** Intent:              This file contains functions implementing a simple
00314 **                      error facility.  It was first written by Stephen Moore
00315 **                      (smm@wuerl.wustl.edu) to support PACS development at
00316 **                      the Mallinckrodt Institute of Radiology.  The function
00317 **                      names have been modified to have a slightly more
00318 **                      generic name, but the basic model and concepts are
00319 **                      the same.
00320 **
00321 **                      The condition package maintains a stack of
00322 **                      <condition, message> pairs that callers can push or
00323 **                      pop.  When a routine returns an abnormal value, it
00324 **                      should push a condition onto the stack so that the
00325 **                      caller can examine the value at a later time.  Nested
00326 **                      routines may push a number of conditions onto the
00327 **                      stack providing more detailed information about why
00328 **                      a routine did not return normally.
00329 **
00330 **                      The stack is maintained as a simple stack array.  If
00331 **                      it overflows, we dump the stack to stdout and reset it.
00332 **
00333 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
00334 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
00335 ** Revision:            $Revision: 1.21 $
00336 ** Status:              $State: Exp $
00337 */
00338 
00339 
00340 /*
00341 **
00342 **  INCLUDE FILES
00343 **
00344 */
00345 
00346 
00347 typedef struct {
00348     CONDITION statusCode;
00349     char statusText[256];
00350 }   EDB;
00351 
00352 #define MAXEDB  100
00353 
00354 static int stackPtr = -1;
00355 static EDB EDBStack[MAXEDB];
00356 static void (*ErrorCallback) () = NULL;
00357 static void dumpstack(FILE * fp);
00358 
00359 
00360 /*
00361 **++
00362 **  FUNCTIONAL DESCRIPTION:
00363 **
00364 **      COND_PushCondition
00365 **      This routine is used to log a condition on the stack.  The user
00366 **      passes an error code (currently uninterpreted), a format string
00367 **      and optional format arguments.  We use the vsprintf routine to
00368 **      interpret the user's format string and arguments, and we place the
00369 **      error condition and resultant string on the stack.
00370 **
00371 **  FORMAL PARAMETERS:
00372 **
00373 **      code:
00374 **          The condition code of the error/warning.
00375 **
00376 **      controlString:
00377 **          format string for vsprintf statement
00378 **
00379 **      [varargs]:
00380 **          variable arguments to be used with controlString
00381 **
00382 **  RETURN VALUE:
00383 **
00384 **      code (as passed in by the user)
00385 **
00386 **  SIDE EFFECTS:
00387 **
00388 **      Places a new entry on the stack.  If the stack
00389 **      fills up, drop the last condition.
00390 **      Calls a user-established callback just before return.
00391 **
00392 */
00393 CONDITION
00394 COND_PushCondition(CONDITION cond, char *controlString,...)
00395 {
00396     va_list
00397         args;
00398     char
00399         buffer[1024];
00400 
00401 /*lint -e40 -e50 */
00402     va_start(args, controlString);
00403     if (controlString == NULL)
00404         controlString = "NULL Control string passedto PushCondition";
00405     (void) vsprintf(buffer, controlString, args);
00406     va_end(args);
00407 /*lint +e40 +e50 */
00408 
00409     stackPtr++;
00410     EDBStack[stackPtr].statusCode = cond;
00411     buffer[256] = '\0';
00412 
00413     (void) strcpy(EDBStack[stackPtr].statusText, buffer);
00414     if (ErrorCallback != NULL)
00415 #if 0
00416         ErrorCallback(EDBStack[stackPtr].statusCode,
00417                       EDBStack[stackPtr].statusText);
00418 #else
00419         AFNI_CALL_VOID_2ARG( ErrorCallback ,
00420                              CONDITION,EDBStack[stackPtr].statusCode ,
00421                              char *   ,EDBStack[stackPtr].statusText  ) ;
00422 #endif
00423 
00424     if (stackPtr >= MAXEDB - 2) {
00425         dumpstack(stderr);
00426         fprintf(stderr, "CONDITION Stack overflow\n");
00427         stackPtr = 0;
00428     }
00429 
00430     return cond;
00431 
00432 }
00433 
00434 
00435 /*
00436 **++
00437 **  FUNCTIONAL DESCRIPTION:
00438 **
00439 **  COND_ExtractConditions
00440 **      This routine walks through the stack and passes the condition
00441 **      codes and text back to the user.  The caller supplies a
00442 **      callback routine.  We start at the top of the stack and
00443 **      call the user's callback for each message on the stack.  The
00444 **      user can terminate the process at any time by returning
00445 **      a zero from his callback.
00446 **
00447 **  FORMAL PARAMETERS:
00448 **
00449 **      callback:
00450 **          User routine to call for each message on the stack.
00451 **
00452 **  RETURN VALUE:
00453 **
00454 **      1
00455 **
00456 **  SIDE EFFECTS:
00457 **
00458 **
00459 **  DESIGN:
00460 **
00461 **      None
00462 **--
00463 */
00464 
00465 CONDITION
00466 COND_ExtractConditions(CTNBOOLEAN(*callback) ())
00467 {
00468     int
00469         index,
00470         returnflag;
00471 
00472     for (index = stackPtr, returnflag = 1; index >= 0 && returnflag != 0;
00473          index--) {
00474 #if 0
00475         returnflag = callback(EDBStack[index].statusCode,
00476                               EDBStack[index].statusText);
00477 #else
00478         AFNI_CALL_VALU_2ARG( callback , int,returnflag            ,
00479                              CONDITION,EDBStack[index].statusCode ,
00480                              char *   ,EDBStack[index].statusText  ) ;
00481 #endif
00482     }
00483 
00484     return COND_NORMAL;
00485 }
00486 
00487 /*
00488 **++
00489 **  FUNCTIONAL DESCRIPTION:
00490 **
00491 **      COND_TopCondition
00492 **      This routine is used to look at the top condition message on
00493 **      the stack.  The user passes pointers to areas to place
00494 **      the error message.  The function also returns the code
00495 **      for the top error message.  If the stack is empty, the
00496 **      success code (0) is returned.
00497 **
00498 **  FORMAL PARAMETERS:
00499 **
00500 **      code:
00501 **          Pointer to the user's area to hold the error code
00502 **
00503 **      text
00504 **          Pointer to the user's area to hold the error text
00505 **
00506 **      maxlength
00507 **          Maximum buffer length in the user's text area
00508 **
00509 **  RETURN VALUE:
00510 **
00511 **      top error code on the stack
00512 **
00513 **  SIDE EFFECTS:
00514 **
00515 **
00516 */
00517 
00518 CONDITION
00519 COND_TopCondition(CONDITION * code, char *text, unsigned long maxlength)
00520 {
00521     CONDITION rtnValue;
00522 
00523     if (stackPtr >= 0) {
00524         *code = EDBStack[stackPtr].statusCode;
00525         (void) strncpy(text, EDBStack[stackPtr].statusText, maxlength - 1);
00526         text[maxlength - 1] = '\0';
00527         rtnValue = EDBStack[stackPtr].statusCode;
00528     } else {
00529         *code = COND_NORMAL;
00530         *text = '\0';
00531         rtnValue = COND_NORMAL;
00532     }
00533 
00534     return rtnValue;
00535 }
00536 
00537 /*
00538 **++
00539 **  FUNCTIONAL DESCRIPTION:
00540 **
00541 **      COND_PopCondition
00542 **      This routine pops one or all conditions off the stack.
00543 **      The user passes a flag which indicates the operation.
00544 **      After the clear, the current top error code is returned.
00545 **      If the stack is empty at this point, the success code (0)
00546 **      is returned.
00547 **
00548 **  FORMAL PARAMETERS:
00549 **
00550 **      clearstack:
00551 **          Flag which indicates if the entire stack is to be cleared.
00552 **              0           Just pop the top error
00553 **              non zero    Clear the entire stack
00554 **
00555 **  RETURN VALUE:
00556 **
00557 **      The new top error code.  0 if the stack is empty
00558 **
00559 **  SIDE EFFECTS:
00560 **
00561 **
00562 */
00563 
00564 CONDITION
00565 COND_PopCondition(CTNBOOLEAN clearstack)
00566 {
00567     CONDITION
00568         value;
00569 
00570     if (stackPtr >= 0)
00571         value = EDBStack[stackPtr].statusCode;
00572     else
00573         value = COND_NORMAL;
00574 
00575     if (clearstack) {
00576         stackPtr = -1;
00577     } else if (stackPtr <= 0) {
00578         stackPtr = -1;
00579     } else {
00580         stackPtr--;
00581     }
00582 
00583     return value;
00584 }
00585 
00586 /*
00587 **++
00588 **  FUNCTIONAL DESCRIPTION:
00589 **
00590 **      COND_EstablishCallback
00591 **      Establishes a callback routine to be called whenever a
00592 **      new condition is placed on the stack.  There is no stack
00593 **      mechanism for these callbacks, so each new callback routine
00594 **      completely supersedes the previous one.
00595 **
00596 **  FORMAL PARAMETERS:
00597 **
00598 **      callback:
00599 **          The new callback routine.  If NULL, this will
00600 **          disable callbacks.
00601 **
00602 **  RETURN VALUE:
00603 **
00604 **      0
00605 **
00606 **  SIDE EFFECTS:
00607 **
00608 **
00609 */
00610 
00611 CONDITION
00612 COND_EstablishCallback(void (*callback) ())
00613 {
00614 
00615     ErrorCallback = callback;
00616 
00617     return COND_NORMAL;
00618 }
00619 
00620 
00621 /* function name
00622 **
00623 ** Purpose:
00624 **      Describe the purpose of the function
00625 **
00626 ** Parameter Dictionary:
00627 **      Define the parameters to the function
00628 **
00629 ** Return Values:
00630 **
00631 ** Algorithm:
00632 **      Description of the algorithm (optional) and any other notes.
00633 */
00634 
00635 void
00636 COND_DumpConditions(void)
00637 {
00638 
00639     dumpstack(stderr);
00640     stackPtr = -1;
00641 }
00642 
00643 static void
00644 dumpstack(FILE * lfp)
00645 {
00646     int
00647         index;
00648 
00649     for (index = 0; index <= stackPtr; index++)
00650         fprintf(lfp, "%8x %s\n", (unsigned int)EDBStack[index].statusCode,
00651                 EDBStack[index].statusText);
00652 }
00653 
00654 /*
00655 **++
00656 **  FUNCTIONAL DESCRIPTION:
00657 **
00658 **      COND_CopyText
00659 **      This function copies as much text as possible from the
00660 **      condition stack and places it in the caller's buffer.
00661 **
00662 **  FORMAL PARAMETERS:
00663 **
00664 **      txt
00665 **          Pointer to the user's area to hold the error text
00666 **
00667 **      length
00668 **          Maximum buffer length in the user's text area
00669 **
00670 **  RETURN VALUE:
00671 **
00672 **      none
00673 **
00674 **  SIDE EFFECTS:
00675 **
00676 */
00677 
00678 void
00679 COND_CopyText(char *txt, size_t length)
00680 {
00681     size_t i;
00682     int j;
00683 
00684     txt[0] = '\0';
00685 
00686     j = stackPtr;
00687     while (length > 2 && j >= 0) {
00688         i = strlen(EDBStack[j].statusText);
00689         if (i > length)
00690             i = length - 2;
00691         strncpy(txt, EDBStack[j].statusText, i);
00692         txt[i++] = '\n';
00693         txt[i] = '\0';
00694         length -= i;
00695         txt += i;
00696         j--;
00697     }
00698 }
00699 
00700 /* COND_WriteConditions
00701 **
00702 ** Purpose:
00703 **      Write the condition stack to a file, ie stdout or stderr.
00704 **
00705 ** Parameter Dictionary:
00706 **      File * lfp, the file to which the stack is written.
00707 **
00708 ** Return Values:
00709 **
00710 ** Algorithm:
00711 **      A reiteration of the COND_DumpConditions except this takes an argument.
00712 */
00713 
00714 void
00715 COND_WriteConditions(FILE * lfp)
00716 {
00717     dumpstack(lfp);
00718     stackPtr = -1;
00719 }
00720 /*
00721           Copyright (C) 1995 - 1996, RSNA and Washington University
00722 
00723           The software and supporting documentation for the Radiological
00724           Society of North America (RSNA) 1993 - 1996 Digital Imaging and
00725           Communications in Medicine (DICOM) Demonstration were developed
00726           at the
00727                   Electronic Radiology Laboratory
00728                   Mallinckrodt Institute of Radiology
00729                   Washington University School of Medicine
00730                   510 S. Kingshighway Blvd.
00731                   St. Louis, MO 63110
00732           as part of the 1993 - 1996 DICOM Central Test Node project for, and
00733           under contract with, the Radiological Society of North America.
00734 
00735           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00736           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00737           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00738           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00739           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00740           THE SOFTWARE IS WITH THE USER.
00741 
00742           Copyright of the software and supporting documentation is
00743           jointly owned by RSNA and Washington University, and free access
00744           is hereby granted as a license to use this software, copy this
00745           software and prepare derivative works based upon this software.
00746           However, any distribution of this software source code or
00747           supporting documentation or derivative works (source code and
00748           supporting documentation) must include the three paragraphs of
00749           the copyright notice.
00750 */
00751 /*
00752 +-+-+-+-+-+-+-+-+-
00753 */
00754 /*
00755 **                   Electronic Radiology Laboratory
00756 **                 Mallinckrodt Institute of Radiology
00757 **              Washington University School of Medicine
00758 **
00759 ** Module Name(s):
00760 ** Author, Date:        Steve Moore, 30-Jun-96
00761 ** Intent:              Provide common abstractions needed for operations
00762 **                      in a multi-threaded environment.
00763 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
00764 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
00765 ** Revision:            $Revision: 1.21 $
00766 ** Status:              $State: Exp $
00767 */
00768 
00769 /*
00770           Copyright (C) 1993, 1994, RSNA and Washington University
00771 
00772           The software and supporting documentation for the Radiological
00773           Society of North America (RSNA) 1993, 1994 Digital Imaging and
00774           Communications in Medicine (DICOM) Demonstration were developed
00775           at the
00776                   Electronic Radiology Laboratory
00777                   Mallinckrodt Institute of Radiology
00778                   Washington University School of Medicine
00779                   510 S. Kingshighway Blvd.
00780                   St. Louis, MO 63110
00781           as part of the 1993, 1994 DICOM Central Test Node project for, and
00782           under contract with, the Radiological Society of North America.
00783 
00784           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00785           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00786           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00787           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00788           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00789           THE SOFTWARE IS WITH THE USER.
00790 
00791           Copyright of the software and supporting documentation is
00792           jointly owned by RSNA and Washington University, and free access
00793           is hereby granted as a license to use this software, copy this
00794           software and prepare derivative works based upon this software.
00795           However, any distribution of this software source code or
00796           supporting documentation or derivative works (source code and
00797           supporting documentation) must include the three paragraphs of
00798           the copyright notice.
00799 */
00800 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
00801 
00802 /*
00803 **                              DICOM 93
00804 **                   Electronic Radiology Laboratory
00805 **                 Mallinckrodt Institute of Radiology
00806 **              Washington University School of Medicine
00807 **
00808 ** Module Name(s):      DCM_OpenFile
00809 **                      DCM_CreateObject
00810 **                      DCM_CloseObject
00811 **                      DCM_AddElement
00812 **                      DCM_AddSequenceElement
00813 **                      DCM_RemoveElement
00814 **                      DCM_GetElementValue
00815 **                      DCM_GetElementSize
00816 **                      DCM_ScanParseObject
00817 **                      DCM_ImportStream
00818 **                      DCM_ExportStream
00819 **                      DCM_GetObjectSize
00820 **                      DCM_DumpElements
00821 **                      DCM_Debug
00822 **                      DCM_WriteFile
00823 **                      DCM_ModifyElements
00824 **                      DCM_ParseObject
00825 **                      DCM_RemoveGroup
00826 **                      DCM_GetSequenceList
00827 **                      DCM_ComputeExportSize
00828 **      private functions
00829 **                      newElementItem
00830 **                      findCreateGroup
00831 **                      insertNewElement
00832 **                      updateObjectType
00833 **                      updateSpecialElements
00834 **                      exportFixedFields
00835 **                      exportData
00836 **                      fileSize
00837 **                      swapInPlace
00838 **                      checkObject
00839 **                      writeFile
00840 **                      countBytes
00841 **                      exportStream
00842 **                      verifyFormat
00843 **                      readFile
00844 ** Author, Date:        Stephen M. Moore, 26-Apr-93
00845 ** Intent:
00846 **      This file contains the routines which implement a facility for
00847 **      manipulating DICOM V3 information objects.  These routines parse
00848 **      and construct NEMA objects (or streams).  Users are able to
00849 **      read/write/examine individual attributes.  The package uses those
00850 **      individual elements to construct an internal memory representation of
00851 **      an object.  This representation is a linked list of the individual
00852 **      attributes.  The user of the package can add attributes to an object,
00853 **      remove an element from an object, query the object about an attribute,
00854 **      and convert the object to and from its "stream" representation.
00855 **      In addition, the package can parse a file which contains a stream
00856 **      and create its internal object.
00857 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
00858 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
00859 ** Revision:            $Revision: 1.21 $
00860 ** Status:              $State: Exp $
00861 */
00862 
00863 
00864 static CTNBOOLEAN debug = FALSE;/* Flag for debugging messages to stdout */
00865 
00866 /* Prototypes for internal functions
00867 */
00868 static CONDITION
00869 newElementItem(DCM_ELEMENT * src, CTNBOOLEAN allocateData,
00870                PRV_ELEMENT_ITEM ** dst);
00871 static CONDITION
00872 findCreateGroup(PRIVATE_OBJECT ** object, unsigned short group,
00873                 PRV_GROUP_ITEM ** groupPtr);
00874 static CONDITION
00875 insertNewElement(PRIVATE_OBJECT ** object,
00876                  DCM_ELEMENT * element);
00877 static CONDITION
00878 updateObjectType(PRIVATE_OBJECT ** object,
00879                  DCM_ELEMENT * element);
00880 static CONDITION
00881 updateSpecialElements(PRIVATE_OBJECT ** object,
00882                       PRV_ELEMENT_ITEM * item);
00883 static void
00884 exportFixedFields(DCM_ELEMENT * element,
00885                   unsigned char *b, U32 length, int byteOrder,
00886                   CTNBOOLEAN explicitVR, U32 * rtnLength);
00887 static CONDITION
00888 exportData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
00889            unsigned char *src,
00890            unsigned char *dst, U32 length, int byteOrder,
00891            U32 * rtnLength);
00892 #ifdef MACOS
00893 static long fileSize(int fd);
00894 #else
00895 static int fileSize(int fd);
00896 #endif
00897 static void swapInPlace(PRIVATE_OBJECT ** object, DCM_ELEMENT * e);
00898 static CONDITION checkObject(PRIVATE_OBJECT ** object, char *caller);
00899 static CONDITION
00900     writeFile(void *buffer, U32 length, int flag, void /* int */ *fd);
00901 static CONDITION
00902 countBytes(void *buffer, U32 length, int flag,
00903            void /* unsigned long */ *sizePtr);
00904 static CONDITION
00905 exportStream(DCM_OBJECT ** callerObject, unsigned long opt,
00906              void *buffer, U32 bufferlength, CONDITION(*callback) (),
00907              void *ctx, int sequenceLevel);
00908 
00909 static CONDITION
00910     verifyFormat(PRV_ELEMENT_ITEM * item);
00911 static CONDITION
00912 readFile(char *name, unsigned char *callerBuf, int fd, long size,
00913          off_t fileOffset, int recursionLevel,
00914          unsigned long opt, DCM_OBJECT ** callerObject,
00915          U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
00916          void *ctx,
00917          CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
00918          CONDITION(*sk) (void *ctx, int offset, int flag));
00919 static CONDITION
00920 readFile1(const char *name, unsigned char *callerBuf, int fd, U32 size,
00921           off_t * fileOffset, int recursionLevel,
00922           unsigned long opt, PRIVATE_OBJECT ** parentObject,
00923           DCM_OBJECT ** callerObject,
00924           U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
00925           void *ctx,
00926           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
00927           CONDITION(*sk) (void *ctx, int offset, int flag));
00928 
00929 static PRV_ELEMENT_ITEM *locateElement(PRIVATE_OBJECT ** obj, DCM_TAG tag);
00930 static void computeVM(PRIVATE_OBJECT ** object, DCM_ELEMENT * element);
00931 static void ctxSensitiveLookup(PRIVATE_OBJECT ** object, DCM_ELEMENT * element);
00932 static CONDITION
00933 copyData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
00934          DCM_ELEMENT * to, U32 * rtnLength);
00935 static CONDITION
00936 readLengthToEnd(int fd, const char *fileName,
00937                 unsigned long opt, U32 * lengthToEnd);
00938 
00939 static void swapATGroupElement(DCM_ELEMENT * e);
00940 
00941 static void
00942 dumpBinaryData(void *d, DCM_VALUEREPRESENTATION vr,
00943                long vm, long vmLimit);
00944 static void
00945 compareGroup(PRV_GROUP_ITEM * g1, PRV_GROUP_ITEM * g2,
00946              void (*callback) (const DCM_ELEMENT * e1,
00947                                const DCM_ELEMENT * e2,
00948                                void *ctx),
00949              void *ctx);
00950 static void remapFileName(const char *name, char *mapName);
00951 
00952 
00953 /* DCM_OpenFile
00954 **
00955 ** Purpose:
00956 **  This function opens a file that conforms to the DICOM V3 standard.
00957 **  The file is parsed and an internal representation of the data is created.
00958 **  A handle is returned to the caller to allow access to the data.
00959 **
00960 ** Parameter Dictionary:
00961 **   name       ASCIZ string giving path name to file to be opened.
00962 **   opt        BITMASK giving options used when opening file and
00963 **              interpreting data.  Current options have to do with the
00964 **              byte order of the data in the file.  Legal masks for
00965 **              this field are:
00966 **                      DCM_ORDERNATIVE
00967 **                      DCM_ORDERLITTLEENDIAN
00968 **                      DCM_ORDERBIGENDIAN
00969 **   object     Pointer to handle to return to caller  giving caller
00970 **              future access to the data in the object.
00971 **
00972 ** Return Values:
00973 **
00974 **      DCM_ELEMENTCREATEFAILED
00975 **      DCM_ELEMENTLENGTHERROR
00976 **      DCM_ELEMENTOUTOFORDER
00977 **      DCM_FILEACCESSERROR
00978 **      DCM_FILEOPENFAILED
00979 **      DCM_ILLEGALOPTION
00980 **      DCM_ILLEGALSTREAMLENGTH
00981 **      DCM_LISTFAILURE
00982 **      DCM_NORMAL
00983 **      DCM_OBJECTCREATEFAILED
00984 **      DCM_UNEVENELEMENTLENGTH
00985 **
00986 ** Algorithm:
00987 **      Determine file byte order (per caller's options)
00988 **      Create new ACR object
00989 **      Open file read only.
00990 **      Determine size of file
00991 **      While you have not reached end of file
00992 **          Read next (group, element, length) triple
00993 **          Lookup data element in dictionary
00994 **          Read data value according to byte order and (group,element)
00995 **          Check to see that data element is in numerical order
00996 **          Add data element to linked list
00997 **      End while
00998 */
00999 
01000 CONDITION
01001 DCM_OpenFile(const char *name, unsigned long opt, DCM_OBJECT ** callerObject)
01002 {
01003     CONDITION cond;
01004     int fd;
01005     off_t fileOffset = 0;
01006     U32 lengthToEnd;
01007     U32 size;
01008     CTNBOOLEAN
01009         remainFileOpen = FALSE; /* Leave file open after parse ? */
01010 
01011 ENTRY("DCM_OpenFile") ;
01012 
01013     if ((opt & (DCM_ORDERMASK | DCM_FILEFORMATMASK)) == 0)
01014         RETURN(COND_PushCondition(DCM_ILLEGALOPTION,
01015                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
01016                                   "DCM_OpenFile"));
01017 
01018 #ifdef _MSC_VER
01019     fd = open(name, O_RDONLY | O_BINARY);
01020 #else
01021     rwc_fd = fd = open(name, O_RDONLY);
01022 #endif
01023     if ((fd < 0) && ((opt & DCM_FILENAMEMASK) == DCM_TRYFILENAMECHANGE)) {
01024         char mapName[1024];
01025         remapFileName(name, mapName);
01026 #ifdef _MSC_VER
01027         fd = open(mapName, O_RDONLY | O_BINARY);
01028 #else
01029         fd = open(mapName, O_RDONLY);
01030         if (fd < 0) {
01031             strcat(mapName, ".");
01032             fd = open(mapName, O_RDONLY);
01033         }
01034 #endif
01035     }
01036     if (fd < 0) {
01037         char msg[1024] ;
01038         sprintf(msg,"DCM_OpenFile open(%s) fails",name) ;
01039         perror(msg) ;
01040         RETURN(COND_PushCondition(DCM_FILEOPENFAILED,
01041                                   DCM_Message(DCM_FILEOPENFAILED), name,
01042                                   "DCM_OpenFile"));
01043     }
01044     size = fileSize(fd);
01045     if (size <= 0)
01046         RETURN(DCM_FILEACCESSERROR);
01047 
01048     if ((opt & DCM_LENGTHTOENDMASK) == DCM_USELENGTHTOEND) {
01049         cond = readLengthToEnd(fd, name,
01050                                opt & (~DCM_LENGTHTOENDMASK), &lengthToEnd);
01051         if (cond != DCM_NORMAL) {
01052             (void) close(fd); rwc_fd = -1 ;
01053             RETURN(COND_PushCondition(DCM_FILEOPENFAILED,
01054                      DCM_Message(DCM_FILEOPENFAILED), name, "DCM_OpenFile"));
01055         }
01056         size = lengthToEnd;
01057         fileOffset = 24;
01058         (void) lseek(fd, 24, SEEK_SET);
01059     }
01060 #ifdef OLDSMM
01061     cond = readFile(name, NULL, fd, size, 0, 0, opt, callerObject, NULL,
01062                     &remainFileOpen, NULL, NULL, NULL);
01063 #endif
01064     cond = readFile1(name, NULL, fd, size, &fileOffset, 0, opt, NULL,
01065                      callerObject, NULL, &remainFileOpen, NULL, NULL, NULL);
01066     if ((cond != DCM_NORMAL) || !remainFileOpen){
01067         (void) close(fd); rwc_fd = -1 ;
01068     }
01069     if (cond != DCM_NORMAL) {
01070         if (debug)
01071             DCM_DumpElements(callerObject, 1);
01072         RETURN(COND_PushCondition(DCM_FILEOPENFAILED,
01073                      DCM_Message(DCM_FILEOPENFAILED), name, "DCM_OpenFile"));
01074     } else
01075         RETURN(DCM_NORMAL);
01076 }
01077 
01078 CONDITION
01079 DCM_ReadStream(DCM_OBJECT ** callerObject, unsigned long opt, long size,
01080                void *ctx,
01081           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
01082                CONDITION(*sk) (void *ctx, int offset, int flag))
01083 {
01084     CONDITION cond;
01085     int fd = -1;
01086     CTNBOOLEAN
01087         remainFileOpen = FALSE; /* Leave file open after parse ? */
01088     off_t fileOffset = 0;
01089 
01090     if ((opt & (DCM_ORDERMASK | DCM_FILEFORMATMASK)) == 0)
01091         return COND_PushCondition(DCM_ILLEGALOPTION,
01092                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
01093                                   "DCM_ReadStream");
01094 
01095     cond = readFile1("", NULL, fd, size, &fileOffset, 0, opt, NULL,
01096                      callerObject, NULL, &remainFileOpen, ctx, rd, sk);
01097     if (cond != DCM_NORMAL)
01098         return COND_PushCondition(DCM_READSTREAMFAILED,
01099                        DCM_Message(DCM_READSTREAMFAILED), "DCM_ReadStream");
01100     else
01101         return DCM_NORMAL;
01102 }
01103 
01104 /* DCM_CreateObject
01105 **
01106 ** Purpose:
01107 **      This function creates a new object and initializes some
01108 **      of the fields in the object
01109 **
01110 ** Parameter Dictionary:
01111 **      object          Pointer to caller's handle for object to be created.
01112 **      opt             Flag with options used when creating object.
01113 **                      The only option that we use now is DCM_NOGROUPLENGTH.
01114 **
01115 ** Return Values:
01116 **      DCM_NORMAL
01117 **      DCM_OBJECTCREATEFAILED
01118 **      DCM_LISTFAILURE
01119 **
01120 ** Algorithm:
01121 **      Description of the algorithm (optional) and any other notes.
01122 */
01123 
01124 CONDITION
01125 DCM_CreateObject(DCM_OBJECT ** object, unsigned long opt)
01126 {
01127     PRIVATE_OBJECT
01128         * obj;
01129 
01130     if (object == NULL) {
01131         (void) COND_PushCondition(DCM_NULLADDRESS,
01132                           DCM_Message(DCM_NULLADDRESS), "DCM_CreateObject");
01133         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
01134                    DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CreateObject");
01135     }
01136     obj = (PRIVATE_OBJECT *) CTN_MALLOC(sizeof(PRIVATE_OBJECT));
01137     if (obj == NULL) {
01138         (void) COND_PushCondition(DCM_MALLOCFAILURE,
01139                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
01140                                   "DCM_CreateObject");
01141         *object = NULL;
01142         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
01143                    DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CreateObject");
01144     }
01145     (void) memset(obj, 0, sizeof(PRIVATE_OBJECT));
01146     (void) strcpy(obj->keyType, KEY_DCM_OBJECT);
01147 
01148 
01149     obj->objectType = DCM_OBJECTUNKNOWN;
01150     obj->accessMethod = DCM_MEMORY_ACCESS;
01151     obj->deleteFlag = FALSE;
01152     if ((opt & DCM_GROUPLENGTHMASK) == DCM_NOGROUPLENGTH)
01153         obj->groupLengthFlag = FALSE;
01154     else
01155         obj->groupLengthFlag = TRUE;
01156     obj->objectSize = 0;
01157     obj->offset = 0;
01158     obj->pixelSize = 0;
01159     obj->pixelOffset = 0;
01160     obj->pixelBitsAllocated = 0;
01161     obj->pixelRepresentation = 0xffff;
01162     obj->groupCtx = NULL;
01163     obj->elementCtx = NULL;
01164     obj->fd = -1;
01165     obj->fileName[0] = '\0';
01166     obj->preambleFlag = FALSE;
01167     obj->preamble[0] = '\0';
01168     obj->dataOptions = 0;
01169     obj->metaHeaderLength = 0xffffffff;
01170     obj->longVRAttributes = 0;
01171     obj->waveformDataVR[0] = '\0';
01172 
01173     obj->groupList = LST_Create();
01174     if (obj->groupList == NULL) {
01175         CTN_FREE(obj);
01176         *object = NULL;
01177         return COND_PushCondition(DCM_LISTFAILURE,
01178                                   DCM_Message(DCM_LISTFAILURE),
01179                                   "DCM_CreateObject");
01180     }
01181     *object = (DCM_OBJECT *) obj;
01182     return DCM_NORMAL;
01183 }
01184 
01185 
01186 /* DCM_CloseObject
01187 **
01188 ** Purpose:
01189 **      Close an information object by freeing memory allocated to it and
01190 **      destroying caller's reference to it.
01191 **
01192 ** Parameter Dictionary:
01193 **      callerObject    Address of caller's pointer to a DCM_OBJECT.
01194 **
01195 ** Return Values:
01196 **
01197 **      DCM_FILEDELETEFAILED
01198 **      DCM_ILLEGALOBJECT
01199 **      DCM_LISTFAILURE
01200 **      DCM_NORMAL
01201 **      DCM_NULLOBJECT
01202 **
01203 ** Algorithm:
01204 */
01205 
01206 CONDITION
01207 DCM_CloseObject(DCM_OBJECT ** callerObject)
01208 {
01209     CONDITION
01210         cond;
01211     PRV_GROUP_ITEM
01212         * group;
01213     PRV_ELEMENT_ITEM
01214         * element;
01215     PRIVATE_OBJECT
01216         ** object;
01217     DCM_SEQUENCE_ITEM
01218         * sequenceItem;
01219     DCM_FRAGMENT_ITEM* fragmentItem;
01220 
01221     if (debug)
01222         fprintf(stderr, "Starting DCM_CloseObject\n");
01223 
01224     object = (PRIVATE_OBJECT **) callerObject;
01225     cond = checkObject(object, "DCM_CloseObject");
01226     if (cond != DCM_NORMAL)
01227         return cond;
01228 
01229     if ((*object)->fd > 0)
01230         (void) close((*object)->fd);
01231 
01232     if (debug)
01233         fprintf(stderr, "DCM_CloseObject: Legal object and file closed\n");
01234 
01235     while ((group = (void *)LST_Pop(&(*object)->groupList)) != NULL) {
01236         if (debug)
01237             fprintf(stderr, "DCM_CloseObject: group %04x\n", group->group);
01238 
01239         while ((element = (void *)LST_Pop(&group->elementList)) != NULL) {
01240             if (debug)
01241                 fprintf(stderr, "DCM_CloseObject: Element %08x\n",
01242                         element->element.tag);
01243             if (element->element.representation == DCM_SQ) {
01244                 if (debug)
01245                     fprintf(stderr, "Sequence List Address: %p\n",
01246                             element->element.d.sq);
01247                 if (element->element.d.sq != NULL) {
01248                     while ((sequenceItem = (void *)LST_Pop(&element->element.d.sq)) != NULL) {
01249                         (void) DCM_CloseObject(&sequenceItem->object);
01250                         CTN_FREE(sequenceItem);
01251                     }
01252                     (void) LST_Destroy(&element->element.d.sq);
01253                 }
01254             } else if (element->fragmentFlag) {
01255                 if (debug)
01256                     fprintf(stderr, "Fragment List Address: %p\n",
01257                             element->element.d.fragments);
01258                 if (element->element.d.fragments != NULL) {
01259                     while ((fragmentItem = (void *)LST_Pop(&element->element.d.fragments)) != NULL) {
01260                         CTN_FREE(fragmentItem);
01261                     }
01262                     (void) LST_Destroy(&element->element.d.fragments);
01263                 }
01264             }
01265             if (debug)
01266                 fprintf(stderr, "DCM_CloseObject: free %8p\n", element);
01267 
01268             CTN_FREE(element);
01269         }
01270         cond = LST_Destroy(&group->elementList);
01271         if (cond != LST_NORMAL)
01272             return COND_PushCondition(DCM_LISTFAILURE,
01273                            DCM_Message(DCM_LISTFAILURE), "DCM_CloseObject");
01274         CTN_FREE(group);
01275     }
01276     cond = LST_Destroy(&(*object)->groupList);
01277     if (cond != LST_NORMAL)
01278         return COND_PushCondition(DCM_LISTFAILURE,
01279                            DCM_Message(DCM_LISTFAILURE), "DCM_CloseObject");
01280 
01281     cond = DCM_NORMAL;
01282     if ((*object)->deleteFlag) {
01283         if (unlink((*object)->fileName) != 0) {
01284 /****    (void) COND_PushCondition(DCM_FILEDELETEFAILED, strerror(errno));****/
01285             cond = COND_PushCondition(DCM_FILEDELETEFAILED,
01286                                       DCM_Message(DCM_FILEDELETEFAILED), (*object)->fileName, strerror(errno),
01287                                       "DCM_CloseObject");
01288 
01289         }
01290     }
01291     CTN_FREE(*object);
01292     *object = NULL;
01293     return cond;
01294 }
01295 
01296 /* DCM_AddElement
01297 **
01298 ** Purpose:
01299 **      Add an element to an existing DCM object
01300 **
01301 ** Parameter Dictionary:
01302 **      object          Pointer to caller's existing DCM object.
01303 **      element         Pointer to DCM element to be added to object
01304 **
01305 ** Return Values:
01306 **
01307 **      DCM_ILLEGALOBJECT
01308 **      DCM_ILLEGALREPRESENTATION
01309 **      DCM_INSERTFAILED
01310 **      DCM_NORMAL
01311 **      DCM_NULLOBJECT
01312 **
01313 ** Algorithm:
01314 **      Check caller's object to make certain it is a legal object
01315 **      Check element to see that caller is not trying to add
01316 **          group length or length to end data elements.
01317 **      Lookup element in the dictionary
01318 **      If element is not in the dictionary, use caller's definition
01319 **      If element is in the dictionary, make certain caller used
01320 **          proper definitions or left things undefined.
01321 **      Call findCreateGroup to
01322 **          - create new group if this group does not exist
01323 **          - create length to end element if necessary
01324 **          - update object size for this object
01325 **          - set CURRENT pointer in linked list to head of this group
01326 **      Call insertNewElement to
01327 **          - create a copy of the caller's element
01328 **          - insert copy into linked list
01329 **      Call updateObjectType to
01330 **          - update this object as type COMMAND, DATASET, MESSAGE
01331 */
01332 
01333 CONDITION
01334 DCM_AddElement(DCM_OBJECT ** callerObject, DCM_ELEMENT * element)
01335 {
01336     CONDITION
01337         cond;
01338     DCM_ELEMENT
01339         localElement;
01340     PRIVATE_OBJECT
01341         ** object;
01342     PRV_GROUP_ITEM
01343         * groupItem;
01344 
01345     object = (PRIVATE_OBJECT **) callerObject;
01346 
01347     cond = checkObject(object, "DCM_AddElement");
01348     if (cond != DCM_NORMAL)
01349         return cond;
01350 
01351     if ((DCM_TAG_ELEMENT(element->tag) == 0x0000))
01352         return COND_PushCondition(DCM_ILLEGALADD,
01353                    DCM_Message(DCM_ILLEGALADD), DCM_TAG_GROUP(element->tag),
01354                            DCM_TAG_ELEMENT(element->tag), "DCM_AddElement");
01355 
01356 
01357     localElement = *element;
01358 
01359     cond = DCM_LookupElement(&localElement);
01360     if (cond != DCM_NORMAL) {
01361         (void) COND_PopCondition(0);
01362         localElement = *element;
01363     } else {
01364         if (localElement.representation == DCM_OT ||
01365             localElement.representation == DCM_CTX)
01366             localElement.representation = element->representation;
01367         if (element->representation != DCM_UN &&
01368             element->representation != localElement.representation) {
01369             return COND_PushCondition(DCM_ILLEGALREPRESENTATION,
01370                                       DCM_Message(DCM_ILLEGALREPRESENTATION),
01371                                       DCM_TAG_GROUP(element->tag),
01372                                       DCM_TAG_ELEMENT(element->tag),
01373                                       "DCM_AddElement");
01374         }
01375     }
01376 
01377     cond = findCreateGroup(object, DCM_TAG_GROUP(localElement.tag), &groupItem);
01378     if (cond != DCM_NORMAL)
01379         return COND_PushCondition(DCM_INSERTFAILED,
01380                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01381                                   DCM_TAG_ELEMENT(element->tag),
01382                                   "DCM_AddElement");
01383 
01384     cond = insertNewElement(object, &localElement);
01385     if (cond != DCM_NORMAL)
01386         return COND_PushCondition(DCM_INSERTFAILED,
01387                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01388                                   DCM_TAG_ELEMENT(element->tag),
01389                                   "DCM_AddElement");
01390 
01391     cond = updateObjectType(object, &localElement);
01392     if (cond != DCM_NORMAL)
01393         return COND_PushCondition(DCM_INSERTFAILED,
01394                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01395                                   DCM_TAG_ELEMENT(element->tag),
01396                                   "DCM_AddElement");
01397 
01398     return DCM_NORMAL;
01399 }
01400 
01401 /* DCM_AddSequenceElement
01402 **
01403 ** Purpose:
01404 **      Add a sequence element to an existing DCM object.  This
01405 **      function takes ownership of the caller's sequence list
01406 **      when it adds the element to the object.  The caller's
01407 **      copy of the sequence list is removed.
01408 **
01409 ** Parameter Dictionary:
01410 **      object          Pointer to caller's existing DCM object.
01411 **      element         Pointer to DCM element to be added to object
01412 **
01413 ** Return Values:
01414 **
01415 **      DCM_ILLEGALOBJECT
01416 **      DCM_ILLEGALREPRESENTATION
01417 **      DCM_INSERTFAILED
01418 **      DCM_NORMAL
01419 **      DCM_NULLOBJECT
01420 **
01421 ** Algorithm:
01422 */
01423 
01424 CONDITION
01425 DCM_AddSequenceElement(DCM_OBJECT ** callerObject, DCM_ELEMENT * element)
01426 {
01427     CONDITION cond;
01428     DCM_ELEMENT localElement;
01429     PRIVATE_OBJECT **object;
01430     PRV_GROUP_ITEM *groupItem;
01431 
01432     object = (PRIVATE_OBJECT **) callerObject;
01433 
01434     cond = checkObject(object, "DCM_AddSequenceElement");
01435     if (cond != DCM_NORMAL)
01436         return cond;
01437 
01438     if ((DCM_TAG_ELEMENT(element->tag) == 0x0000))
01439         return COND_PushCondition(DCM_ILLEGALADD,
01440                    DCM_Message(DCM_ILLEGALADD), DCM_TAG_GROUP(element->tag),
01441                            DCM_TAG_ELEMENT(element->tag), "DCM_AddElement");
01442 
01443 
01444     localElement = *element;
01445 
01446     cond = DCM_LookupElement(&localElement);
01447     if (cond != DCM_NORMAL) {
01448         (void) COND_PopCondition(0);
01449         localElement = *element;
01450     } else {
01451         localElement.representation = element->representation;
01452     }
01453     if (localElement.representation != DCM_SQ) {
01454         return COND_PushCondition(DCM_NOTASEQUENCE,
01455                                   DCM_Message(DCM_NOTASEQUENCE),
01456                                   DCM_TAG_GROUP(localElement.tag),
01457                                   DCM_TAG_ELEMENT(localElement.tag),
01458                                   "DCM_AddSequenceElement");
01459     }
01460     cond = findCreateGroup(object, DCM_TAG_GROUP(localElement.tag), &groupItem);
01461     if (cond != DCM_NORMAL)
01462         return COND_PushCondition(DCM_INSERTFAILED,
01463                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01464                                   DCM_TAG_ELEMENT(element->tag),
01465                                   "DCM_AddSequenceElement");
01466 
01467     cond = insertNewElement(object, &localElement);
01468     if (cond != DCM_NORMAL)
01469         return COND_PushCondition(DCM_INSERTFAILED,
01470                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01471                                   DCM_TAG_ELEMENT(element->tag),
01472                                   "DCM_AddElement");
01473 
01474     cond = updateObjectType(object, &localElement);
01475     if (cond != DCM_NORMAL)
01476         return COND_PushCondition(DCM_INSERTFAILED,
01477                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01478                                   DCM_TAG_ELEMENT(element->tag),
01479                                   "DCM_AddSequenceElement");
01480 
01481     /*
01482      * We have taken ownership of the sequence list, so zero out caller's
01483      * copy
01484      */
01485     element->d.sq = NULL;
01486 
01487     return DCM_NORMAL;
01488 }
01489 
01490 /* DCM_RemoveElement
01491 **
01492 ** Purpose:
01493 **      This function removes a single element from an information object.
01494 **
01495 ** Parameter Dictionary:
01496 **      callerObject            Handle to the object
01497 **      tag                     The tag of the element to be removed
01498 **
01499 ** Return Values:
01500 **
01501 **      DCM_ELEMENTNOTFOUND
01502 **      DCM_ILLEGALOBJECT
01503 **      DCM_NORMAL
01504 **      DCM_NULLOBJECT
01505 **
01506 ** Algorithm:
01507 **      Description of the algorithm (optional) and any other notes.
01508 */
01509 
01510 CONDITION
01511 DCM_RemoveElement(DCM_OBJECT ** callerObject, DCM_TAG tag)
01512 {
01513     PRIVATE_OBJECT
01514         ** object;
01515     PRV_GROUP_ITEM
01516         * groupItem;
01517     PRV_ELEMENT_ITEM
01518         * elementItem,
01519         *groupLengthItem;
01520     CONDITION
01521         cond;
01522     CTNBOOLEAN
01523         flag;
01524     unsigned short
01525         group,
01526         element;
01527 
01528     object = (PRIVATE_OBJECT **) callerObject;
01529     cond = checkObject(object, "DCM_RemoveElement");
01530     if (cond != DCM_NORMAL)
01531         return cond;
01532 
01533     group = DCM_TAG_GROUP(tag);
01534     element = DCM_TAG_ELEMENT(tag);
01535 
01536     groupItem = (void *)LST_Head(&((*object)->groupList));
01537     if (groupItem == NULL)
01538         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01539                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01540                                   "DCM_RemoveElement");
01541 
01542     (void) LST_Position(&((*object)->groupList), (void *)groupItem);
01543 
01544     flag = FALSE;
01545     while ((groupItem != NULL) && (flag == FALSE)) {
01546         if (groupItem->group == group)
01547             flag = TRUE;
01548         else
01549             groupItem = (void *)LST_Next(&(*object)->groupList);
01550     }
01551     if (flag == FALSE)
01552         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01553                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01554                                   "DCM_RemoveElement");
01555 
01556     elementItem = (void *)LST_Head(&groupItem->elementList);
01557     if (elementItem == NULL)
01558         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01559                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01560                                   "DCM_RemoveElement");
01561 
01562     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
01563 
01564     groupLengthItem = elementItem;
01565     if (DCM_TAG_ELEMENT(groupLengthItem->element.tag) != 0x0000)
01566         groupLengthItem = NULL;
01567 
01568 
01569     flag = FALSE;
01570     while ((elementItem != NULL) && (flag == FALSE)) {
01571         if (DCM_TAG_ELEMENT(elementItem->element.tag) == element)
01572             flag = TRUE;
01573         else
01574             elementItem = (void *)LST_Next(&groupItem->elementList);
01575     }
01576 
01577     if (flag == FALSE)
01578         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01579                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01580                                   "DCM_RemoveElement");
01581 
01582     if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH) {
01583         groupItem->baseLength -= elementItem->paddedDataLength + 2 + 2 + 4;
01584         if (groupLengthItem != NULL) {
01585             *groupLengthItem->element.d.ul = groupItem->baseLength;
01586         }
01587     }
01588     if ((*object)->objectSize != DCM_UNSPECIFIEDLENGTH)
01589         (*object)->objectSize -= elementItem->paddedDataLength + 2 + 2 + 4;
01590     if (elementItem->element.representation == DCM_OW ||
01591         elementItem->element.representation == DCM_OB ||
01592         elementItem->element.representation == DCM_SQ) {
01593         groupItem->longVRAttributes--;
01594         (*object)->longVRAttributes--;
01595     }
01596     (void) LST_Remove(&(groupItem->elementList), LST_K_AFTER);
01597     CTN_FREE(elementItem);
01598     return DCM_NORMAL;
01599 }
01600 
01601 /* DCM_GetElementValue
01602 **
01603 ** Purpose:
01604 **      This function retrieves the data from one data element and
01605 **      returns it in a buffer allocated by the caller.  In the event
01606 **      the data is larger than the caller's buffer, multiple calls
01607 **      are used to retrieve the data.
01608 **
01609 ** Parameter Dictionary:
01610 **      object          Pointer to user's object containing desired element
01611 **      element         DCM_ELEMENT structure containing (group,element)
01612 **                      specification of desired data element
01613 **      rtnLength       Pointer to caller variable to hold length of
01614 **                      data returned by this call.
01615 **      ctx             Pointer to context variable used for multiple
01616 **                      calls to this function.  Caller should set the
01617 **                      pointer to NULL before the first call and not
01618 **                      touch the pointer again.
01619 **
01620 ** Return Values:
01621 **
01622 **      DCM_CANNOTGETSEQUENCEVALUE
01623 **      DCM_ELEMENTNOTFOUND
01624 **      DCM_GETINCOMPLETE
01625 **      DCM_ILLEGALCONTEXT
01626 **      DCM_ILLEGALOBJECT
01627 **      DCM_NORMAL
01628 **      DCM_NULLOBJECT
01629 **
01630 ** Algorithm:
01631 **      Check caller's object to make certain it is a legal DCM object.
01632 **      Find head of the object linked list.
01633 **      Search linked list sequentially until object is found or end
01634 **      of list reached.
01635 **      If end of list
01636 **              return DCM_ELEMENTNOTFOUND
01637 **      If CTX pointer containts NULL
01638 **          Begin copy from beginning of element
01639 **      else
01640 **          Begin copy from address in CTX pointer
01641 **      Copy data from element data area to user buffer
01642 **      If copy is incomplete (remaining data longer than caller's buffer)
01643 **          Update CTX pointer to point to next uncopied part of data
01644 **          Return DCM_GETINCOMPLETE
01645 **      else
01646 **          Update CTX pointer to point past data area.
01647 **          Return DCM_NORMAL
01648 */
01649 
01650 CONDITION
01651 DCM_GetElementValue(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
01652                     U32 * rtnLength, void **ctx)
01653 {
01654     PRIVATE_OBJECT
01655         ** object;
01656     PRV_GROUP_ITEM
01657         * groupItem;
01658     PRV_ELEMENT_ITEM
01659         * elementItem;
01660     int
01661         nBytes;
01662     CONDITION
01663         cond;
01664 
01665     object = (PRIVATE_OBJECT **) callerObject;
01666     cond = checkObject(object, "DCM_GetElementValue");
01667     if (cond != DCM_NORMAL)
01668         return cond;
01669 
01670     groupItem = (void *)LST_Head(&(*object)->groupList);
01671     if (groupItem == NULL)
01672         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01673               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01674                                   DCM_TAG_ELEMENT(element->tag),
01675                                   "DCM_GetElementValue");
01676 
01677     (void) LST_Position(&(*object)->groupList, (void *)groupItem);
01678     while (groupItem != NULL) {
01679         if (groupItem->group == DCM_TAG_GROUP(element->tag))
01680             break;
01681 
01682         groupItem = (void *)LST_Next(&(*object)->groupList);
01683     }
01684     if (groupItem == NULL)
01685         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01686               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01687                                   DCM_TAG_ELEMENT(element->tag),
01688                                   "DCM_GetElementValue");
01689 
01690     elementItem = (void *)LST_Head(&groupItem->elementList);
01691     if (elementItem == NULL)
01692         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01693               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01694                                   DCM_TAG_GROUP(element->tag),
01695                                   "DCM_GetElementValue");
01696 
01697     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
01698     while (elementItem != NULL) {
01699         if (elementItem->element.tag == element->tag) {
01700             unsigned char *p;
01701             U32 l;
01702 
01703             if (element->representation == DCM_SQ)
01704                 return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
01705                                     DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
01706                                        element->tag, "DCM_GetElementValue");
01707 
01708             p = *ctx;
01709             if ((U32) p > elementItem->element.length)
01710                 return COND_PushCondition(DCM_ILLEGALCONTEXT,
01711                                           DCM_Message(DCM_ILLEGALCONTEXT),
01712                                           "DCM_GetElementValue");
01713 
01714             l = MIN(element->length, (elementItem->element.length - (U32) p));
01715 
01716             *rtnLength = l;
01717             {
01718                 if (elementItem->element.d.ot == NULL) {
01719                     if ((*object)->fd != -1) {
01720                         (void) lseek((*object)->fd,
01721                              elementItem->dataOffset + (off_t) p, SEEK_SET);
01722                         nBytes = read((*object)->fd, element->d.ot, (int) l);
01723                     } else {
01724                         (*object)->sk((*object)->userCtx,
01725                                       (long) (elementItem->dataOffset + (off_t) p), SEEK_SET);
01726                         cond = (*object)->rd((*object)->userCtx, element->d.ot, l,
01727                                              &nBytes);
01728                     }
01729                     if ((unsigned) nBytes != l) {
01730                         return COND_PushCondition(DCM_FILEACCESSERROR,
01731                                            DCM_Message(DCM_FILEACCESSERROR),
01732                                                   (*object)->fileName,
01733                                                   "DCM_GetElementValue");
01734                     }
01735                     if( LITTLE_ENDIAN_ARCHITECTURE ){
01736                       if (elementItem->element.representation == DCM_AT) {
01737                           DCM_ELEMENT e;
01738                           e = elementItem->element;
01739                           e.length = l;
01740                           e.d.ot = element->d.ot;
01741                           swapATGroupElement(&e);
01742                       }
01743                     }
01744                     if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01745                         DCM_ELEMENT e;
01746                         e = elementItem->element;
01747                         e.length = l;
01748                         e.d.ot = element->d.ot;
01749                         swapInPlace(object, &e);
01750                     }
01751                 } else {
01752                     unsigned char *q;
01753                     q = (unsigned char *) elementItem->element.d.ot +
01754                         (U32) p;
01755                     (void) memcpy(element->d.ot, q, l);
01756                     if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01757                         DCM_ELEMENT e;
01758                         e = elementItem->element;
01759                         e.length = l;
01760                         e.d.ot = element->d.ot;
01761                         swapInPlace(object, &e);
01762                     }
01763                 }
01764                 p += l;
01765                 *ctx = (void *) p;
01766                 if ((unsigned) p == elementItem->element.length)
01767                     return DCM_NORMAL;
01768                 else
01769                     return DCM_GETINCOMPLETE;
01770             }
01771 
01772         }
01773         elementItem = (void *)LST_Next(&groupItem->elementList);
01774     }
01775     return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01776               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01777                               DCM_TAG_ELEMENT(element->tag),
01778                               "DCM_GetElementValue");
01779 }
01780 
01781 char*
01782 DCM_GetString(DCM_OBJECT** callerObject, DCM_TAG tag)
01783 {
01784   DCM_ELEMENT e;
01785   CONDITION cond;
01786   char* s;
01787   char tmp[64] = "";
01788   char b[64] = "";
01789 
01790   e.tag = tag;
01791   cond = DCM_GetElement(callerObject, tag, &e);
01792   if (cond != DCM_NORMAL) {
01793     COND_PopCondition(TRUE);
01794     return 0;
01795   }
01796 
01797   if (DCM_IsString(e.representation)) {
01798     s = AFMALL( char, e.length + 1);
01799     e.d.string = s;
01800     cond = DCM_ParseObject(callerObject, &e, 1, 0, 0, 0);
01801     if (cond != DCM_NORMAL) {
01802       free(s);
01803       s = 0;
01804     }
01805     return s;
01806   }
01807 
01808   if (e.representation == DCM_SQ) {
01809     return 0;
01810   }
01811 
01812   if (e.length > sizeof(b))
01813     return 0;
01814 
01815   e.d.ot = b;
01816   cond = DCM_ParseObject(callerObject, &e, 1, 0, 0, 0);
01817   if (cond != DCM_NORMAL) {
01818     COND_PopCondition(TRUE);
01819     return 0;
01820   }
01821 
01822   switch (e.representation) {
01823     case DCM_AT:
01824     case DCM_FD:
01825     case DCM_FL:
01826       strcpy(tmp, "<Unimplemented>");
01827       break;
01828     case DCM_SL:
01829       sprintf(tmp, "%d", *e.d.sl);
01830       break;
01831     case DCM_SQ:
01832       strcpy(tmp, "<Unimplemented>");
01833       break;
01834     case DCM_SS:
01835       sprintf(tmp, "%d", *e.d.ss);
01836       break;
01837     case DCM_UL:
01838       sprintf(tmp, "%d", *e.d.ul);
01839       break;
01840     case DCM_UN:
01841       strcpy(tmp, "<Unimplemented>");
01842       break;
01843     case DCM_US:
01844       sprintf(tmp, "%d", *e.d.us);
01845       break;
01846     /*case DCM_UNKNOWN:*/
01847     case DCM_RET:
01848     case DCM_CTX:
01849     case DCM_OB:
01850     case DCM_OW:
01851     case DCM_DLM:
01852     default:
01853       strcpy(tmp, "<Unimplemented>");
01854       break;
01855   }
01856 
01857   s = (char*) malloc(strlen(tmp) + 1);
01858   strcpy(s, tmp);
01859 
01860   return s;
01861 }
01862 
01863 
01864 
01865 CONDITION
01866 DCM_GetElementValueOffset(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
01867                           unsigned long offset)
01868 {
01869     PRIVATE_OBJECT **object;
01870     PRV_ELEMENT_ITEM *elementItem;
01871     int nBytes;
01872     CONDITION cond;
01873 
01874     object = (PRIVATE_OBJECT **) callerObject;
01875     cond = checkObject(object, "DCM_GetElementValue");
01876     if (cond != DCM_NORMAL)
01877         return cond;
01878 
01879     elementItem = locateElement(object, element->tag);
01880     if (elementItem == NULL)
01881         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01882               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01883                                   DCM_TAG_ELEMENT(element->tag),
01884                                   "DCM_GetElementValueOffset");
01885 
01886 
01887     {
01888         unsigned char *p;
01889         U32 l;
01890 
01891         if (element->representation == DCM_SQ)
01892             return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
01893                                     DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
01894                                  element->tag, "DCM_GetElementValueOffset");
01895 
01896         p = (unsigned char *) offset;;
01897         if ((U32) p > elementItem->element.length)
01898             return COND_PushCondition(DCM_BADOFFSET,
01899                                       DCM_Message(DCM_BADOFFSET),
01900                                       (int) offset,
01901                                       (int) elementItem->element.length,
01902                                       "DCM_GetElementValueLength");
01903 
01904         l = element->length;
01905         if (l + offset > elementItem->element.length) {
01906             return COND_PushCondition(DCM_BADLENGTH,
01907                                       DCM_Message(DCM_BADLENGTH),
01908                                       (int) offset, (int) l,
01909                                       (int) elementItem->element.length,
01910                                       "DCM_GetElementValueLength");
01911         } {
01912             if (elementItem->element.d.ot == NULL) {
01913                 if ((*object)->fd != -1) {
01914                     (void) lseek((*object)->fd,
01915                              elementItem->dataOffset + (off_t) p, SEEK_SET);
01916                     nBytes = read((*object)->fd, element->d.ot, (int) l);
01917                 } else {
01918                     (*object)->sk((*object)->userCtx,
01919                     (long) (elementItem->dataOffset + (off_t) p), SEEK_SET);
01920                     cond = (*object)->rd((*object)->userCtx, element->d.ot, l,
01921                                          &nBytes);
01922                 }
01923                 if ((unsigned) nBytes != l) {
01924                     return COND_PushCondition(DCM_FILEACCESSERROR,
01925                                            DCM_Message(DCM_FILEACCESSERROR),
01926                                               (*object)->fileName,
01927                                               "DCM_GetElementValueValue");
01928                 }
01929                 if( LITTLE_ENDIAN_ARCHITECTURE ){
01930                   if (elementItem->element.representation == DCM_AT) {
01931                       DCM_ELEMENT e;
01932                       e = elementItem->element;
01933                       e.length = l;
01934                       e.d.ot = element->d.ot;
01935                       swapATGroupElement(&e);
01936                   }
01937                 }
01938                 if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01939                     DCM_ELEMENT e;
01940                     e = elementItem->element;
01941                     e.length = l;
01942                     e.d.ot = element->d.ot;
01943                     swapInPlace(object, &e);
01944                 }
01945             } else {
01946                 unsigned char *q;
01947                 q = (unsigned char *) elementItem->element.d.ot +
01948                     (U32) p;
01949                 (void) memcpy(element->d.ot, q, l);
01950                 if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01951                     DCM_ELEMENT e;
01952                     e = elementItem->element;
01953                     e.length = l;
01954                     e.d.ot = element->d.ot;
01955                     swapInPlace(object, &e);
01956                 }
01957             }
01958             return DCM_NORMAL;
01959         }
01960 
01961     }
01962 }
01963 
01964 
01965 
01966 /* DCM_GetElementSize
01967 **
01968 ** Purpose:
01969 **      Return the size of one data element in an ACR object.
01970 **
01971 ** Parameter Dictionary:
01972 **      object          Pointer to caller's ACR object
01973 **      element         Pointer to ACR element that defines data element
01974 **                      of interest by specifying (group,element) pair
01975 **      rtnLength       Pointer to caller variable to hold returned
01976 **                      length of data element
01977 **
01978 ** Return Values:
01979 **
01980 **      DCM_NORMAL
01981 **      DCM_NULLOBJECT
01982 **      DCM_ILLEGALOBJECT
01983 **      DCM_ELEMENTNOTFOUND
01984 **
01985 ** Algorithm:
01986 **      Description of the algorithm (optional) and any other notes.
01987 */
01988 
01989 CONDITION
01990 DCM_GetElementSize(DCM_OBJECT ** callerObject, DCM_TAG tag,
01991                    U32 * rtnLength)
01992 {
01993     PRIVATE_OBJECT
01994         ** object;
01995     PRV_GROUP_ITEM
01996         * groupItem;
01997     PRV_ELEMENT_ITEM
01998         * elementItem;
01999     CONDITION
02000         cond;
02001     CTNBOOLEAN
02002         flag;
02003     unsigned short
02004         group,
02005         element;
02006 
02007     object = (PRIVATE_OBJECT **) callerObject;
02008     cond = checkObject(object, "DCM_GetElementSize");
02009     if (cond != DCM_NORMAL)
02010         return cond;
02011 
02012     group = DCM_TAG_GROUP(tag);
02013     element = DCM_TAG_ELEMENT(tag);
02014 
02015     groupItem = (void *)LST_Head(&((*object)->groupList));
02016     if (groupItem == NULL)
02017         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02018                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02019                                   "DCM_GetElementSize");
02020 
02021     (void) LST_Position(&((*object)->groupList), (void *)groupItem);
02022 
02023     flag = FALSE;
02024     while ((groupItem != NULL) && (flag == FALSE)) {
02025         if (groupItem->group == group)
02026             flag = TRUE;
02027         else
02028             groupItem = (void *)LST_Next(&(*object)->groupList);
02029     }
02030     if (flag == FALSE)
02031         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02032                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02033                                   "DCM_GetElementSize");
02034 
02035     elementItem = (void *)LST_Head(&groupItem->elementList);
02036     if (elementItem == NULL)
02037         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02038                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02039                                   "DCM_GetElementSize");
02040 
02041     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02042 
02043     flag = FALSE;
02044     while ((elementItem != NULL) && (flag == FALSE)) {
02045         if (elementItem->element.tag == tag)
02046             flag = TRUE;
02047         else
02048             elementItem = (void *)LST_Next(&groupItem->elementList);
02049     }
02050 
02051     if (flag == FALSE)
02052         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02053                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02054                                   "DCM_GetElementSize");
02055 
02056 
02057     *rtnLength = elementItem->element.length;
02058     return DCM_NORMAL;
02059 }
02060 
02061 
02062 /* DCM_ScanParseObject
02063 **
02064 ** Purpose:
02065 **      DCM_ScanParseObject is used to allow a caller to examine every
02066 **      element in a DICOM object and to parse the elements in the object.
02067 **      The caller passes a list of elements to be parsed from the object.
02068 **      This function examines each element in the object in order
02069 **      (ascending group/element).  If the element in the object is found
02070 **      in the caller's parse list, the element is parsed (and a value
02071 **      placed in storage allocated by the caller).  If the element is
02072 **      not found in the caller's list, a callback function is invoked
02073 **      to notify the caller of the element.  When the callback function
02074 **      is invoked, the arguments are:
02075 **              DCM_ELEMENT *e  Pointer to the individual element
02076 **              void *ctx       Caller's context information
02077 **
02078 **      This function is very useful for determining exactly which
02079 **      elements are present in an object without having to ask for
02080 **      each one individually.
02081 **
02082 ** Parameter Dictionary:
02083 **      callerObject    Pointer to caller's DICOM object
02084 **      buf             Unused
02085 **      bufferSizd      Unused
02086 **      vector          A vector of elements which are to be parsed.  An entry
02087 **                      in the vector gives the tag and describes where the
02088 **                      parsed data is to be stored.
02089 **      vectorLength    Number of entries in the vector.
02090 **      callback        Caller function invoked for an element that is in
02091 **                      the object but is not found in caller's list.
02092 **      ctx             Context information that is passed to callback function.
02093 **
02094 ** Return Values:
02095 **
02096 **      DCM_NORMAL
02097 **      DCM_NULLOBJECT
02098 **      DCM_ILLEGALOBJECT
02099 **
02100 ** Algorithm:
02101 */
02102 
02103 CONDITION
02104 DCM_ScanParseObject(DCM_OBJECT ** callerObject, void *buf, size_t bufferSize,
02105                     DCM_FLAGGED_ELEMENT * elementVector, int vectorLength,
02106                     CONDITION(*callback) (const DCM_ELEMENT* e, void* ctx),
02107                     void *ctx)
02108 {
02109     PRIVATE_OBJECT
02110         ** object;
02111     PRV_GROUP_ITEM
02112         * groupItem;
02113     PRV_ELEMENT_ITEM
02114         * elementItem;
02115     CONDITION
02116         cond;
02117     CTNBOOLEAN
02118         done = FALSE;
02119     DCM_ELEMENT
02120         e;
02121     int
02122         i;
02123     CTNBOOLEAN
02124         found;
02125     U32
02126         l;
02127     char
02128        *p;
02129 
02130     object = (PRIVATE_OBJECT **) callerObject;
02131     cond = checkObject(object, "DCM_ScanParseObject");
02132     if (cond != DCM_NORMAL)
02133         return cond;
02134 
02135     groupItem = (void *)LST_Head(&((*object)->groupList));
02136     (void) LST_Position(&((*object)->groupList), (void *)groupItem);
02137     while (groupItem != NULL && !done) {
02138         elementItem = (void *)LST_Head(&groupItem->elementList);
02139         (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02140         while (elementItem != NULL && !done) {
02141             for (found = FALSE, i = 0; !found && i < vectorLength; i++) {
02142                 if (elementItem->element.tag == elementVector[i].e.tag) {
02143                     found = TRUE;
02144                     (void)copyData(object,elementItem,&elementVector[i].e, &l);
02145                     *elementVector[i].flagAddress |= elementVector[i].flag;
02146 
02147                     if (DCM_IsString(elementVector[i].e.representation)) {
02148                         elementVector[i].e.d.string[l] = '\0';
02149                         p = elementVector[i].e.d.string + l - 1;
02150                         while (p >= elementVector[i].e.d.string && (*p == ' '))
02151                             *p-- = '\0';
02152                     }
02153                 }
02154             }
02155             if (!found) {
02156                 e = elementItem->element;
02157                 cond = callback(&e, ctx);
02158                 if (cond != DCM_NORMAL)
02159                     done = TRUE;
02160             }
02161             elementItem = (void *)LST_Next(&groupItem->elementList);
02162         }
02163         groupItem = (void *)LST_Next(&((*object)->groupList));
02164     }
02165     return DCM_NORMAL;
02166 }
02167 
02168 /* DCM_ImportStream
02169 **
02170 ** Purpose:
02171 **      Import data from memory in DCM stream format and create
02172 **      an internal memory representation of the object.
02173 **
02174 ** Parameter Dictionary:
02175 **      buf             Pointer to caller's buffer containing ACR NEMA data
02176 **      length          Length of input data in bytes
02177 **      opt             Bitmask giving options for interpreting data.
02178 **                      Legal values specify the order of the bytes in the data
02179 **                              ACR_ORDERNATIVE
02180 **                              ACR_ORDERLITTLEENDIAN
02181 **                              ACR_ORDERBIGENDIAN
02182 **      object          Pointer to object created and returned by this function
02183 **
02184 ** Return Values:
02185 **
02186 **      DCM_ELEMENTCREATEFAILED
02187 **      DCM_ELEMENTLENGTHERROR
02188 **      DCM_ELEMENTOUTOFORDER
02189 **      DCM_FILEACCESSERROR
02190 **      DCM_ILLEGALOPTION
02191 **      DCM_ILLEGALSTREAMLENGTH
02192 **      DCM_LISTFAILURE
02193 **      DCM_NORMAL
02194 **      DCM_OBJECTCREATEFAILED
02195 **      DCM_UNEVENELEMENTLENGTH
02196 **
02197 ** Algorithm:
02198 **      call private import stream function which handles recursion
02199 **
02200 */
02201 
02202 CONDITION
02203 DCM_ImportStream(unsigned char *buf, unsigned long length,
02204                  unsigned long opt, DCM_OBJECT ** callerObject)
02205 {
02206 #ifdef DEBUG
02207     if (debug)
02208         (void) fprintf(stderr, "DCM_ImportStream, %ld bytes\n", length);
02209 #endif
02210 
02211     if ((opt & DCM_ORDERMASK) == 0)
02212         return COND_PushCondition(DCM_ILLEGALOPTION,
02213                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
02214                                   "DCM_ImportStream");
02215 
02216     return readFile("", buf, -1, length, 0, 0, opt, callerObject, NULL, NULL,
02217                     NULL, NULL, NULL);
02218 }
02219 
02220 /* DCM_GetObjectSize
02221 **
02222 ** Purpose:
02223 **      Return the size of a DICOM object when it is represented in
02224 **      stream format.
02225 **
02226 ** Parameter Dictionary:
02227 **      object          Pointer to caller's DICOM object
02228 **      returnlength    Pointer to unsigned long variable to hold length of
02229 **                      object
02230 **
02231 ** Return Values:
02232 **
02233 **      DCM_ILLEGALOBJECT
02234 **      DCM_NORMAL
02235 **      DCM_NULLOBJECT
02236 **
02237 ** Algorithm:
02238 **      Description of the algorithm (optional) and any other notes.
02239 */
02240 
02241 CONDITION
02242 DCM_GetObjectSize(DCM_OBJECT ** callerObject, unsigned long *returnlength)
02243 {
02244     PRIVATE_OBJECT
02245         ** object;
02246     CONDITION
02247         cond;
02248 
02249     object = (PRIVATE_OBJECT **) callerObject;
02250     cond = checkObject(object, "DCM_GetObjectSize");
02251     if (cond != DCM_NORMAL)
02252         return cond;
02253 
02254     *returnlength = (*object)->objectSize;
02255     return DCM_NORMAL;
02256 }
02257 
02258 /* DCM_DumpElements
02259 **
02260 ** Purpose:
02261 **      Dump a short description of each data element in an object to
02262 **      stdout (for use as a debugging tool).
02263 **
02264 ** Parameter Dictionary:
02265 **      object          Pointer to caller's handle for DCM object to be dumped
02266 **      vm              Limit on the value multiplicity for printing
02267 **                      binary data.  Print no more than vm values.
02268 **
02269 ** Return Values:
02270 **
02271 **      DCM_ILLEGALOBJECT
02272 **      DCM_NORMAL
02273 **      DCM_NULLOBJECT
02274 **
02275 ** Algorithm:
02276 **      Check caller's handle to make certain it is a legal DCM object
02277 **      Print object type (COMMAND, DATASET, MESSAGE) and size in bytes
02278 **      For each GROUP in the object linked list
02279 **          For each ELEMENT ITEM in the group linked list
02280 **              print group, element, size, description
02281 **              print some or all of data based on data element representation
02282 **                      (ASCII number, ASCII text, binary)
02283 **          End for
02284 **      End for
02285 */
02286 CONDITION
02287 DCM_DumpElements(DCM_OBJECT ** callerObject, long vm)
02288 {
02289     PRV_GROUP_ITEM
02290         * groupItem;
02291     PRV_ELEMENT_ITEM
02292         * elementItem;
02293     PRIVATE_OBJECT
02294         ** object;
02295     CONDITION
02296         cond;
02297     DCM_SEQUENCE_ITEM
02298         * sq;
02299     char
02300         scratch[128];
02301     int
02302         stringLength;
02303 
02304     object = (PRIVATE_OBJECT **) callerObject;
02305 
02306     cond = checkObject(object, "DCM_DumpElements");
02307     if (cond != DCM_NORMAL)
02308         return cond;
02309 
02310     switch ((*object)->objectType) {
02311     case DCM_OBJECTUNKNOWN:
02312         RWC_printf("Object type: UNKNOWN\n");
02313         break;
02314     case DCM_OBJECTCOMMAND:
02315         RWC_printf("Object type: COMMAND\n");
02316         break;
02317     case DCM_OBJECTIMAGE:
02318         RWC_printf("Object type: IMAGE\n");
02319         break;
02320     case DCM_OBJECTELEMENTLIST:
02321         RWC_printf("Object type: ELEMENT LIST\n");
02322         break;
02323     default:
02324         RWC_printf("Object type: Unknown (error)\n");
02325         break;
02326     }
02327     RWC_printf("Object size: %ld\n", (*object)->objectSize);
02328 
02329     groupItem = (void *)LST_Head(&(*object)->groupList);
02330     if (groupItem != NULL)
02331         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
02332 
02333     while (groupItem != NULL) {
02334 #ifdef MACOS
02335         RWC_printf("Group: %04x, Length: %8ld\n", groupItem->group,
02336                groupItem->baseLength);
02337 #else
02338         RWC_printf("Group: %04x, Length: %8d\n", groupItem->group,
02339                groupItem->baseLength);
02340 #endif
02341         elementItem = (void *)LST_Head(&groupItem->elementList);
02342         if (elementItem != NULL)
02343             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02344         while (elementItem != NULL) {
02345 #ifdef MACOS
02346             (void) RWC_printf("%04x %04x %8ld [%-8lu] ",
02347                           DCM_TAG_GROUP(elementItem->element.tag),
02348                           DCM_TAG_ELEMENT(elementItem->element.tag),
02349                           elementItem->element.length ,
02350                           (unsigned long) elementItem->element.data_offset );
02351 #else
02352             (void) RWC_printf("%04x %04x %8d [%-8lu] ",
02353                           DCM_TAG_GROUP(elementItem->element.tag),
02354                           DCM_TAG_ELEMENT(elementItem->element.tag),
02355                           elementItem->element.length ,
02356                           (unsigned long) elementItem->element.data_offset );
02357 #endif
02358 
02359             if( (rwc_opt & RWC_NONAME_MASK) == 0 )
02360               (void) RWC_printf("//%31s//", elementItem->element.description);
02361             else
02362               (void) RWC_printf("//") ;
02363 
02364             if (elementItem->element.d.ot == NULL)
02365                 (void) RWC_printf("Data on disk\n");
02366             else {
02367                 switch (elementItem->element.representation) {
02368                 case DCM_AE:
02369                 case DCM_AS:
02370                 case DCM_CS:
02371                 case DCM_DA:
02372                 case DCM_DT:
02373                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02374                     strncpy(scratch, elementItem->element.d.string, stringLength);
02375                     scratch[stringLength] = '\0';
02376                     (void) RWC_printf("%s\n", scratch);
02377                     break;
02378                 case DCM_DD:
02379                 case DCM_FD:
02380                 case DCM_FL:
02381                     (void) RWC_printf("Unimplemented\n");
02382                     break;
02383                 case DCM_DS:
02384                 case DCM_IS:
02385                 case DCM_LO:
02386                 case DCM_LT:
02387                 case DCM_PN:
02388                 case DCM_SH:
02389                 case DCM_UT:
02390                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02391                     strncpy(scratch, elementItem->element.d.string, stringLength);
02392                     scratch[stringLength] = '\0';
02393                     (void) RWC_printf("%s\n", scratch);
02394                     break;
02395                 case DCM_SL:
02396 #ifdef MACOS
02397                     (void) RWC_printf("%8lx %ld\n", *elementItem->element.d.sl,
02398                                   *elementItem->element.d.sl);
02399 #else
02400                     if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02401                       (void) RWC_printf("%8x %d\n", *elementItem->element.d.sl,
02402                                         *elementItem->element.d.sl);
02403                     else
02404                       (void) RWC_printf(" %d\n", *elementItem->element.d.sl ) ;
02405 
02406                     if (vm > 1)
02407                         dumpBinaryData(elementItem->element.d.ot,
02408                                        elementItem->element.representation,
02409                              elementItem->element.length / sizeof(U32), vm);
02410 #endif
02411                     break;
02412                 case DCM_SS:
02413                     if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02414                       (void) RWC_printf("%4x %d\n", *elementItem->element.d.ss,
02415                                     *elementItem->element.d.ss);
02416                     else
02417                       (void) RWC_printf(" %d\n", *elementItem->element.d.ss ) ;
02418 
02419                     if (vm > 1)
02420                         dumpBinaryData(elementItem->element.d.ot,
02421                                        elementItem->element.representation,
02422                            elementItem->element.length / sizeof(short), vm);
02423                     break;
02424                 case DCM_SQ:
02425                     (void) RWC_printf("SEQUENCE\n");
02426                     sq = (void *)LST_Head(&elementItem->element.d.sq);
02427                     if (sq != NULL)
02428                         (void) LST_Position(&elementItem->element.d.sq, (void *)sq);
02429                     RWC_printf("DCM Dump SEQUENCE\n");
02430                     while (sq != NULL) {
02431                         (void) DCM_DumpElements(&sq->object, vm);
02432                         sq = (void *)LST_Next(&elementItem->element.d.sq);
02433                     }
02434                     RWC_printf("DCM Dump SEQUENCE Complete\n");
02435                     break;
02436                 case DCM_ST:
02437                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02438                     strncpy(scratch, elementItem->element.d.string, stringLength);
02439                     scratch[stringLength] = '\0';
02440                     (void) RWC_printf("%s\n", scratch);
02441                     break;
02442                 case DCM_TM:
02443                 case DCM_UI:
02444                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02445                     strncpy(scratch, elementItem->element.d.string, stringLength);
02446                     scratch[stringLength] = '\0';
02447                     (void) RWC_printf("%s\n", scratch);
02448                     break;
02449                 case DCM_AT:
02450                 case DCM_UL:
02451 #ifdef MACOS
02452                     (void) RWC_printf("%8lx %ld\n", *elementItem->element.d.ul,
02453                                   *elementItem->element.d.ul);
02454 #else
02455                     if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02456                       (void) RWC_printf("%8x %d\n", *elementItem->element.d.ul,
02457                                     *elementItem->element.d.ul);
02458                     else
02459                       (void) RWC_printf(" %d\n", *elementItem->element.d.ul ) ;
02460 
02461                     if (vm > 1)
02462                         dumpBinaryData(elementItem->element.d.ot,
02463                                        elementItem->element.representation,
02464                              elementItem->element.length / sizeof(U32), vm);
02465 #endif
02466                     break;
02467                 case DCM_US:{
02468                     int nel = elementItem->element.length / sizeof(unsigned short) , rr ;
02469                     for( rr=0 ; rr < nel ; rr++ ){
02470                      if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02471                        (void) RWC_printf("%4x %d", elementItem->element.d.us[rr],
02472                                                    elementItem->element.d.us[rr]);
02473                      else
02474                        (void) RWC_printf(" %d", elementItem->element.d.us[rr] ) ;
02475                     }
02476                     RWC_printf("\n") ;
02477 
02478                     if (vm > 1)
02479                         dumpBinaryData(elementItem->element.d.ot,
02480                                        elementItem->element.representation,
02481                                        elementItem->element.length / sizeof(unsigned short), vm);
02482                     }
02483                     break;
02484                 case DCM_OB:
02485                 case DCM_UN:
02486                     dumpBinaryData(elementItem->element.d.ot,
02487                                        elementItem->element.representation,
02488                                elementItem->element.length , MAX(rwc_vm,8));
02489                     break;
02490 
02491                 case DCM_OT:
02492                 case DCM_OW:
02493                 /*case DCM_UNKNOWN:*/
02494                 case DCM_RET:
02495                     (void) RWC_printf("Unimplemented\n");
02496                     break;
02497                 default:
02498                     (void) RWC_printf("Some unimplemented logic if here\n");
02499                     break;
02500                 }
02501             }
02502             elementItem = (void *)LST_Next(&groupItem->elementList);
02503         }
02504         groupItem = (void *)LST_Next(&(*object)->groupList);
02505     }
02506 
02507     RWC_printf("DCM Dump Elements Complete\n");
02508     return DCM_NORMAL;
02509 }
02510 
02511 CONDITION
02512 DCM_FormatElements(DCM_OBJECT ** callerObject, long vm, const char* prefix)
02513 {
02514     PRV_GROUP_ITEM
02515         * groupItem;
02516     PRV_ELEMENT_ITEM
02517         * elementItem;
02518     PRIVATE_OBJECT
02519         ** object;
02520     CONDITION
02521         cond;
02522     DCM_SEQUENCE_ITEM
02523         * sq;
02524     char
02525         scratch[128];
02526     int
02527         stringLength;
02528     char localPrefix[128];
02529 
02530     object = (PRIVATE_OBJECT **) callerObject;
02531 
02532     cond = checkObject(object, "DCM_DumpElements");
02533     if (cond != DCM_NORMAL)
02534         return cond;
02535 
02536     RWC_printf("\n%sDCM Dump Elements\n", prefix);
02537     switch ((*object)->objectType) {
02538     case DCM_OBJECTUNKNOWN:
02539         RWC_printf("%sObject type: UNKNOWN\n", prefix);
02540         break;
02541     case DCM_OBJECTCOMMAND:
02542         RWC_printf("%sObject type: COMMAND\n", prefix);
02543         break;
02544     case DCM_OBJECTIMAGE:
02545         RWC_printf("%sObject type: IMAGE\n", prefix);
02546         break;
02547     case DCM_OBJECTELEMENTLIST:
02548         RWC_printf("%sObject type: ELEMENT LIST\n", prefix);
02549         break;
02550     default:
02551         RWC_printf("%sObject type: Unknown (error)\n", prefix);
02552         break;
02553     }
02554     RWC_printf("%sObject size: %ld\n", prefix, (*object)->objectSize);
02555 
02556     groupItem = (void *)LST_Head(&(*object)->groupList);
02557     if (groupItem != NULL)
02558         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
02559 
02560     while (groupItem != NULL) {
02561         RWC_printf("%sGroup: %04x, Length: %8d\n", prefix, groupItem->group,
02562                groupItem->baseLength);
02563         elementItem = (void *)LST_Head(&groupItem->elementList);
02564         if (elementItem != NULL)
02565             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02566         while (elementItem != NULL) {
02567             (void) RWC_printf("%s%04x %04x %8d ",
02568                           prefix,
02569                           DCM_TAG_GROUP(elementItem->element.tag),
02570                           DCM_TAG_ELEMENT(elementItem->element.tag),
02571                           elementItem->element.length);
02572             (void) RWC_printf("//%31s//", elementItem->element.description);
02573             if (elementItem->element.d.ot == NULL)
02574                 (void) RWC_printf("Data on disk\n");
02575             else {
02576                 switch (elementItem->element.representation) {
02577                 case DCM_AE:
02578                 case DCM_AS:
02579                 case DCM_CS:
02580                 case DCM_DA:
02581                 case DCM_DT:
02582                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02583                     strncpy(scratch, elementItem->element.d.string, stringLength);
02584                     scratch[stringLength] = '\0';
02585                     (void) RWC_printf("%s\n", scratch);
02586                     break;
02587                 case DCM_DD:
02588                 case DCM_FD:
02589                 case DCM_FL:
02590                     (void) RWC_printf("Unimplemented\n");
02591                     break;
02592                 case DCM_DS:
02593                 case DCM_IS:
02594                 case DCM_LO:
02595                 case DCM_LT:
02596                 case DCM_PN:
02597                 case DCM_SH:
02598                 case DCM_UT:
02599                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02600                     strncpy(scratch, elementItem->element.d.string, stringLength);
02601                     scratch[stringLength] = '\0';
02602                     (void) RWC_printf("%s\n", scratch);
02603                     break;
02604                 case DCM_SL:
02605 #ifdef MACOS
02606                     (void) RWC_printf("%8lx %ld\n", *elementItem->element.d.sl,
02607                                   *elementItem->element.d.sl);
02608 #else
02609                     (void) RWC_printf("%8x %d\n", *elementItem->element.d.sl,
02610                                   *elementItem->element.d.sl);
02611                     if (vm > 1)
02612                         dumpBinaryData(elementItem->element.d.ot,
02613                                        elementItem->element.representation,
02614                              elementItem->element.length / sizeof(U32), vm);
02615 #endif
02616                     break;
02617                 case DCM_SS:
02618                     (void) RWC_printf("%4x %d\n", *elementItem->element.d.ss,
02619                                   *elementItem->element.d.ss);
02620                     if (vm > 1)
02621                         dumpBinaryData(elementItem->element.d.ot,
02622                                        elementItem->element.representation,
02623                            elementItem->element.length / sizeof(short), vm);
02624                     break;
02625                 case DCM_SQ:
02626                     (void) RWC_printf("SEQUENCE\n");
02627                     sq = (void *)LST_Head(&elementItem->element.d.sq);
02628                     if (sq != NULL)
02629                         (void) LST_Position(&elementItem->element.d.sq, (void *)sq);
02630                     RWC_printf("%sDCM Dump SEQUENCE\n", prefix);
02631                     strcpy(localPrefix, prefix);
02632                     strcat(localPrefix, " ");
02633                     while (sq != NULL) {
02634                         (void) DCM_FormatElements(&sq->object, vm, localPrefix);
02635                         sq = (void *)LST_Next(&elementItem->element.d.sq);
02636                     }
02637                     RWC_printf("%sDCM Dump SEQUENCE Complete\n", prefix);
02638                     break;
02639                 case DCM_ST:
02640                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02641                     strncpy(scratch, elementItem->element.d.string, stringLength);
02642                     scratch[stringLength] = '\0';
02643                     (void) RWC_printf("%s\n", scratch);
02644                     break;
02645                 case DCM_TM:
02646                 case DCM_UI:
02647                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02648                     strncpy(scratch, elementItem->element.d.string, stringLength);
02649                     scratch[stringLength] = '\0';
02650                     (void) RWC_printf("%s\n", scratch);
02651                     break;
02652                 case DCM_AT:
02653                 case DCM_UL:
02654                     (void) RWC_printf("%8x %d\n", *elementItem->element.d.ul,
02655                                   *elementItem->element.d.ul);
02656                     if (vm > 1)
02657                         dumpBinaryData(elementItem->element.d.ot,
02658                                        elementItem->element.representation,
02659                              elementItem->element.length / sizeof(U32), vm);
02660                     break;
02661                 case DCM_US:
02662                     (void) RWC_printf("%4x %d\n", *elementItem->element.d.us,
02663                                   *elementItem->element.d.us);
02664                     if (vm > 1)
02665                         dumpBinaryData(elementItem->element.d.ot,
02666                                        elementItem->element.representation,
02667                                        elementItem->element.length / sizeof(unsigned short), vm);
02668                     break;
02669                 case DCM_OT:
02670                 case DCM_OW:
02671                 case DCM_OB:
02672                 /*case DCM_UNKNOWN:*/
02673                 case DCM_RET:
02674                     (void) RWC_printf("Unimplemented\n");
02675                     break;
02676                 default:
02677                     (void) RWC_printf("Some unimplemented logic if here\n");
02678                     break;
02679                 }
02680             }
02681             elementItem = (void *)LST_Next(&groupItem->elementList);
02682         }
02683         groupItem = (void *)LST_Next(&(*object)->groupList);
02684     }
02685 
02686     RWC_printf("%sDCM Dump Elements Complete\n\n", prefix);
02687     return DCM_NORMAL;
02688 }
02689 
02690 /* DCM_Debug
02691 **
02692 ** Purpose:
02693 **      To enable the debugging facility
02694 **
02695 ** Parameter Dictionary:
02696 **      flag    CTNBOOLEAN variable TRUE if caller wants to turn on debugging
02697 **              info; FALSE otherwise
02698 **
02699 ** Return Values:
02700 **      None
02701 **
02702 ** Algorithm:
02703 **      Description of the algorithm (optional) and any other notes.
02704 */
02705 
02706 void
02707 DCM_Debug(CTNBOOLEAN flag)
02708 {
02709     debug = flag;
02710 }
02711 
02712 /* DCM_WriteFile
02713 **
02714 ** Purpose:
02715 **      Export an object from the internal representation and
02716 **      write the stream representation to a file.
02717 **
02718 ** Parameter Dictionary:
02719 **      object          DCM_OBJECT which is to be written to the file
02720 **      opt             Bitmask giving options for exporting data.  Legal
02721 **                      options give the byte order of exported data:
02722 **                              DCM_ORDERNATIVE
02723 **                              DCM_ORDERLITTLEENDIAN
02724 **                              DCM_ORDERBIGENDIAN
02725 **      file            ASCIIZ name of the file to be created.
02726 **
02727 ** Return Values:
02728 **
02729 **      DCM_FILEACCESSERROR
02730 **      DCM_FILECREATEFAILED
02731 **      DCM_ILLEGALOBJECT
02732 **      DCM_LISTFAILURE
02733 **      DCM_NORMAL
02734 **      DCM_NULLOBJECT
02735 **
02736 ** Algorithm:
02737 **      Description of the algorithm (optional) and any other notes.
02738 */
02739 
02740 CONDITION
02741 DCM_ExportStream(DCM_OBJECT ** callerObject, unsigned long opt,
02742                  void *buffer, unsigned long bufferlength,
02743                  DCM_EXPORT_STREAM_CALLBACK* callback,
02744                  void *ctx) ;
02745 
02746 CONDITION
02747 DCM_WriteFile(DCM_OBJECT ** callerObject, unsigned long opt, const char *file)
02748 {
02749     PRIVATE_OBJECT
02750         ** object;
02751     int
02752         fd;
02753     unsigned char
02754         buf[2048];
02755     CONDITION
02756         cond;
02757 
02758     object = (PRIVATE_OBJECT **) callerObject;
02759     cond = checkObject(object, "DCM_WriteFile");
02760     if (cond != DCM_NORMAL)
02761         return cond;
02762 #ifdef MACOS
02763     fd = open(file, O_WRONLY | O_CREAT | O_TRUNC);
02764 #elif _MSC_VER
02765     fd = _open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
02766                _S_IREAD | _S_IWRITE);
02767 #else
02768     fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
02769 #endif
02770     if (fd < 0) {
02771         return COND_PushCondition(DCM_FILECREATEFAILED,
02772                    DCM_Message(DCM_FILECREATEFAILED), file, strerror(errno),
02773                                   "DCM_WriteFile");
02774     }
02775     cond = DCM_ExportStream(callerObject, opt, buf,
02776                             (unsigned long) sizeof(buf), writeFile, &fd);
02777     if (cond != DCM_NORMAL)
02778         return cond;
02779 
02780     (void) close(fd);
02781     return DCM_NORMAL;
02782 }
02783 
02784 /* DCM_ModifyElements
02785 **
02786 ** Purpose:
02787 **
02788 ** Parameter Dictionary:
02789 **      callerObject            Handle to user's DICOM object to be modified
02790 **      vector                  Mandatory elements that need to be stored
02791 **                              in the object
02792 **      count                   Number of such mandatory elements
02793 **      flaggedVector           Optional elements
02794 **      flaggedCount            Number of such optional elements
02795 **      updateCount             Total number of elements updated (returned to
02796 **                              caller)
02797 **
02798 ** Return Values:
02799 **
02800 **      DCM_ILLEGALOBJECT
02801 **      DCM_ILLEGALREPRESENTATION
02802 **      DCM_INSERTFAILED
02803 **      DCM_NORMAL
02804 **      DCM_NULLOBJECT
02805 **
02806 ** Algorithm:
02807 **      Check caller's object to make certain it is a legal DCM object.
02808 **      Find head of the object linked list.
02809 **      Search linked list sequentially until object is found or end
02810 **      of list reached.
02811 **      If end of list
02812 **              return DCM_ELEMENTNOTFOUND
02813 **      If CTX pointer containts NULL
02814 **          Begin copy from beginning of element
02815 **      else
02816 **          Begin copy from address in CTX pointer
02817 **      Copy data from element data area to user buffer
02818 **      If copy is incomplete (remaining data longer than caller's buffer)
02819 **          Update CTX pointer to point to next uncopied part of data
02820 **          Return DCM_GETINCOMPLETE
02821 **      else
02822 **          Update CTX pointer to point past data area.
02823 **          Return DCM_NORMAL
02824 */
02825 
02826 CONDITION
02827 DCM_ModifyElements(DCM_OBJECT ** callerObject, DCM_ELEMENT * vector, int count,
02828                    DCM_FLAGGED_ELEMENT * flaggedVector, int flaggedCount,
02829                    int *updateCount)
02830 {
02831     PRIVATE_OBJECT
02832         ** object;
02833     CONDITION
02834         cond;
02835     DCM_ELEMENT
02836         e;
02837     int
02838         c = 0;
02839 
02840     object = (PRIVATE_OBJECT **) callerObject;
02841     cond = checkObject(object, "DCM_ModifyElement");
02842     if (cond != DCM_NORMAL)
02843         return cond;
02844 
02845     while (count-- > 0) {
02846         cond = DCM_RemoveElement(callerObject, vector->tag);
02847         if (cond != DCM_NORMAL)
02848             (void) COND_PopCondition(FALSE);
02849 
02850         e = *vector;
02851         if (DCM_IsString(e.representation))
02852             e.length = strlen(e.d.string);
02853 
02854         cond = DCM_AddElement(callerObject, &e);
02855         if (cond != DCM_NORMAL)
02856             return cond;
02857 
02858         c++;
02859         vector++;
02860     }
02861 
02862     while (flaggedCount-- > 0) {
02863         if ((*(flaggedVector->flagAddress) & flaggedVector->flag) != 0) {
02864             cond = DCM_RemoveElement(callerObject, flaggedVector->e.tag);
02865             if (cond != DCM_NORMAL)
02866                 (void) COND_PopCondition(FALSE);
02867 
02868             e = flaggedVector->e;
02869             if (DCM_IsString(e.representation))
02870                 e.length = strlen(e.d.string);
02871             cond = DCM_AddElement(callerObject, &e);
02872             if (cond != DCM_NORMAL)
02873                 return cond;
02874             c++;
02875         }
02876         flaggedVector++;
02877     }
02878 
02879     if (updateCount != NULL)
02880         *updateCount = c;
02881     return DCM_NORMAL;
02882 }
02883 
02884 
02885 /* DCM_ParseObject
02886 **
02887 ** Purpose:
02888 **      Parse the object and store the mandatory and optional elements in
02889 **      different vectors.
02890 **
02891 ** Parameter Dictionary:
02892 **      callerObject            Handle to user's DICOM object to be modified
02893 **      vector                  Mandatory elements that need to be stored
02894 **                              in the object
02895 **      count                   Number of such mandatory elements
02896 **      flaggedVector           Optional elements
02897 **      flaggedCount            Number of such optional elements
02898 **      parseCount              Total number of elements parsed (returned to
02899 **                              caller)
02900 **
02901 ** Return Values:
02902 **
02903 **      DCM_CANNOTGETSEQUENCEVALUE
02904 **      DCM_ELEMENTNOTFOUND
02905 **      DCM_GETINCOMPLETE
02906 **      DCM_ILLEGALCONTEXT
02907 **      DCM_ILLEGALOBJECT
02908 **      DCM_NORMAL
02909 **      DCM_NULLOBJECT
02910 **
02911 ** Notes:
02912 **
02913 ** Algorithm:
02914 **      Description of the algorithm (optional) and any other notes.
02915 */
02916 CONDITION
02917 DCM_ParseObject(DCM_OBJECT ** callerObject, DCM_ELEMENT * vector,
02918               int count, DCM_FLAGGED_ELEMENT * flaggedVector, int flagCount,
02919                 int *parseCount)
02920 {
02921     PRIVATE_OBJECT
02922         ** object;
02923     CONDITION
02924         cond;
02925     void
02926        *ctx;
02927     U32
02928         l;
02929     int
02930         c = 0;
02931     char
02932        *p;
02933 
02934     object = (PRIVATE_OBJECT **) callerObject;
02935     cond = checkObject(object, "DCM_ParseObject");
02936     if (cond != DCM_NORMAL)
02937         return cond;
02938 
02939     while (count-- > 0) {
02940         ctx = NULL;
02941         cond = DCM_GetElementValue(callerObject, vector, &l, &ctx);
02942         if (cond != DCM_NORMAL)
02943             return cond;
02944         if (DCM_IsString(vector->representation)) {
02945             vector->d.string[l] = '\0';
02946             p = vector->d.string + l - 1;
02947             while (p >= vector->d.string && (*p == ' '))
02948                 *p-- = '\0';
02949         }
02950         c++;
02951         vector++;
02952     }
02953 
02954     while (flagCount-- > 0) {
02955         ctx = NULL;
02956         cond = DCM_GetElementValue(callerObject, &flaggedVector->e, &l, &ctx);
02957         if (cond != DCM_NORMAL) {
02958             (void) COND_PopCondition(FALSE);
02959         } else {
02960             c++;
02961             if (DCM_IsString(flaggedVector->e.representation)) {
02962                 flaggedVector->e.d.string[l] = '\0';
02963                 p = flaggedVector->e.d.string + l - 1;
02964                 while (p >= flaggedVector->e.d.string && (*p == ' '))
02965                     *p-- = '\0';
02966             }
02967             *(flaggedVector->flagAddress) |= flaggedVector->flag;
02968         }
02969         flaggedVector++;
02970     }
02971 
02972     if (parseCount != NULL)
02973         *parseCount = c;
02974     return DCM_NORMAL;
02975 }
02976 
02977 
02978 /* DCM_RemoveGroup
02979 **
02980 ** Purpose:
02981 **      Remove an element with the given group number from the object
02982 **
02983 ** Parameter Dictionary:
02984 **      callerObject            Handle to caller's object
02985 **      group                   Group number of the element to be removed.
02986 **
02987 ** Return Values:
02988 **
02989 **      DCM_GROUPNOTFOUND
02990 **      DCM_ILLEGALOBJECT
02991 **      DCM_LISTFAILURE
02992 **      DCM_NORMAL
02993 **      DCM_NULLOBJECT
02994 **
02995 ** Notes:
02996 **
02997 ** Algorithm:
02998 **      Description of the algorithm (optional) and any other notes.
02999 */
03000 
03001 CONDITION
03002 DCM_RemoveGroup(DCM_OBJECT ** callerObject, unsigned short group)
03003 {
03004     PRIVATE_OBJECT
03005         ** object;
03006     CONDITION
03007         cond;
03008     PRV_GROUP_ITEM
03009         * groupItem;
03010     PRV_ELEMENT_ITEM
03011         * elementItem;
03012     CTNBOOLEAN
03013         found = FALSE;
03014 
03015     object = (PRIVATE_OBJECT **) callerObject;
03016     cond = checkObject(object, "DCM_RemoveGroup");
03017     if (cond != DCM_NORMAL)
03018         return cond;
03019 
03020     groupItem = (void *)LST_Head(&(*object)->groupList);
03021     if (groupItem == NULL)
03022         return COND_PushCondition(DCM_GROUPNOTFOUND,
03023             DCM_Message(DCM_GROUPNOTFOUND), (int) group, "DCM_RemoveGroup");
03024 
03025     (void) LST_Position(&(*object)->groupList, (void *)groupItem);
03026 
03027     while (!found && (groupItem != NULL)) {
03028         if (groupItem->group == group)
03029             found = TRUE;
03030         else
03031             groupItem = (void *)LST_Next(&(*object)->groupList);
03032     }
03033     if (groupItem == NULL)
03034         return COND_PushCondition(DCM_GROUPNOTFOUND,
03035             DCM_Message(DCM_GROUPNOTFOUND), (int) group, "DCM_RemoveGroup");
03036 
03037 
03038     while ((elementItem = (void *)LST_Pop(&groupItem->elementList)) != NULL)
03039         CTN_FREE(elementItem);
03040 
03041     groupItem = (void *)LST_Remove(&(*object)->groupList, LST_K_AFTER);
03042     cond = LST_Destroy(&groupItem->elementList);
03043     if (cond != LST_NORMAL)
03044         return COND_PushCondition(DCM_LISTFAILURE,
03045                            DCM_Message(DCM_LISTFAILURE), "DCM_RemoveGroup");
03046     CTN_FREE(groupItem);
03047     return DCM_NORMAL;
03048 }
03049 
03050 /* DCM_GetSequenceList
03051 **
03052 ** Purpose:
03053 **      Obtain the sequence list from the DICOM object corresponding to the
03054 **      tag value.
03055 **
03056 ** Parameter Dictionary:
03057 **      object          Handle to the DICOM object
03058 **      tag             Tag number of the sequence list element to be obtained
03059 **                      from the DICOM object
03060 **      list            Holds the sequence list. Returned to the caller.
03061 **
03062 ** Return Values:
03063 **
03064 **      DCM_ELEMENTNOTFOUND
03065 **      DCM_ILLEGALOBJECT
03066 **      DCM_NORMAL
03067 **      DCM_NULLOBJECT
03068 **
03069 ** Notes:
03070 **
03071 ** Algorithm:
03072 **      Description of the algorithm (optional) and any other notes.
03073 */
03074 
03075 CONDITION
03076 DCM_GetSequenceList(DCM_OBJECT ** object, DCM_TAG tag, LST_HEAD ** list)
03077 {
03078     PRIVATE_OBJECT
03079         ** obj;
03080     CONDITION
03081         cond;
03082     PRV_GROUP_ITEM
03083         * groupItem;
03084     PRV_ELEMENT_ITEM
03085         * elementItem;
03086     CTNBOOLEAN
03087         found = FALSE;
03088 
03089     obj = (PRIVATE_OBJECT **) object;
03090     cond = checkObject(obj, "DCM_GetSequenceList");
03091     if (cond != DCM_NORMAL)
03092         return cond;
03093 
03094     groupItem = (void *)LST_Head(&(*obj)->groupList);
03095     if (groupItem == NULL)
03096         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03097                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03098                                   DCM_TAG_ELEMENT(tag),
03099                                   "DCM_GetSequenceList");
03100 
03101     (void) LST_Position(&(*obj)->groupList, (void *)groupItem);
03102     while (groupItem != NULL) {
03103         if (groupItem->group == DCM_TAG_GROUP(tag))
03104             break;
03105 
03106         groupItem = (void *)LST_Next(&(*obj)->groupList);
03107     }
03108     if (groupItem == NULL)
03109         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03110                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03111                                   DCM_TAG_ELEMENT(tag),
03112                                   "DCM_GetSequenceList");
03113 
03114     elementItem = (void *)LST_Head(&groupItem->elementList);
03115     if (elementItem == NULL)
03116         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03117                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03118                                   DCM_TAG_GROUP(tag),
03119                                   "DCM_GetSequenceTag");
03120 
03121     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
03122     while (!found && (elementItem != NULL)) {
03123         if (elementItem->element.tag == tag) {
03124             *list = elementItem->element.d.sq;
03125             found = TRUE;
03126         }
03127         elementItem = (void *)LST_Next(&groupItem->elementList);
03128     }
03129     if (found)
03130         return DCM_NORMAL;
03131     else
03132         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03133                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03134                                   DCM_TAG_ELEMENT(tag),
03135                                   "DCM_GetSequenceList");
03136 }
03137 
03138 CONDITION
03139 DCM_GetSequenceElement(DCM_OBJECT ** object, DCM_TAG top, DCM_ELEMENT * e)
03140 {
03141     PRIVATE_OBJECT **obj;
03142     CONDITION cond;
03143     PRV_GROUP_ITEM *groupItem;
03144     PRV_ELEMENT_ITEM *elementItem;
03145     DCM_SEQUENCE_ITEM *seqItem;
03146 
03147     CTNBOOLEAN found = FALSE;
03148 
03149     obj = (PRIVATE_OBJECT **) object;
03150     cond = checkObject(obj, "DCM_GetSequenceElement");
03151     if (cond != DCM_NORMAL)
03152         return cond;
03153 
03154     elementItem = locateElement(obj, top);
03155     if (elementItem == NULL) {
03156         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03157                                   DCM_Message(DCM_ELEMENTNOTFOUND),
03158                                   DCM_TAG_GROUP(top),
03159                                   DCM_TAG_ELEMENT(top),
03160                                   "DCM_GetElementSequence");
03161     }
03162     if (elementItem->element.representation != DCM_SQ) {
03163         return COND_PushCondition(DCM_UNEXPECTEDREPRESENTATION,
03164                                   DCM_Message(DCM_UNEXPECTEDREPRESENTATION),
03165                                   "DCM_GetSequenceElement", "sequence");
03166     }
03167     seqItem = (void *)LST_Head(&elementItem->element.d.sq);
03168     cond = DCM_ParseObject(&seqItem->object, e, 1, NULL, 0, NULL);
03169     return cond;
03170 
03171 #if 0
03172     return DCM_NORMAL;
03173 #endif
03174 }
03175 
03176 /* DCM_GetElementValueList
03177 **
03178 ** Purpose:
03179 **
03180 ** Parameter Dictionary:
03181 **      Define the parameters to the function
03182 **
03183 ** Return Values:
03184 **
03185 **      DCM_ELEMENTNOTFOUND
03186 **      DCM_ILLEGALOBJECT
03187 **      DCM_LISTFAILURE
03188 **      DCM_MALLOCFAILURE
03189 **      DCM_NORMAL
03190 **      DCM_NULLOBJECT
03191 **
03192 ** Notes:
03193 **
03194 ** Algorithm:
03195 **      Description of the algorithm (optional) and any other notes.
03196 */
03197 CONDITION
03198 DCM_GetElementValueList(DCM_OBJECT ** object, DCM_TAG tag,
03199                   size_t structureSize, long stringOffset, LST_HEAD ** list)
03200 {
03201     PRIVATE_OBJECT
03202         ** obj;
03203     CONDITION
03204         cond;
03205     PRV_GROUP_ITEM
03206         * groupItem;
03207     PRV_ELEMENT_ITEM
03208         * elementItem;
03209     CTNBOOLEAN
03210         found = FALSE;
03211     char
03212        *src,
03213        *dst,
03214        *p;
03215     U32
03216         l;
03217 
03218     obj = (PRIVATE_OBJECT **) object;
03219     cond = checkObject(obj, "DCM_GetSequenceList");
03220     if (cond != DCM_NORMAL)
03221         return cond;
03222 
03223     groupItem = (void *)LST_Head(&(*obj)->groupList);
03224     if (groupItem == NULL)
03225         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03226                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03227                                   DCM_TAG_ELEMENT(tag),
03228                                   "DCM_GetSequenceList");
03229 
03230     (void) LST_Position(&(*obj)->groupList, (void *)groupItem);
03231     while (groupItem != NULL) {
03232         if (groupItem->group == DCM_TAG_GROUP(tag))
03233             break;
03234 
03235         groupItem = (void *)LST_Next(&(*obj)->groupList);
03236     }
03237     if (groupItem == NULL)
03238         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03239                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03240                                   DCM_TAG_ELEMENT(tag),
03241                                   "DCM_GetSequenceList");
03242 
03243     elementItem = (void *)LST_Head(&groupItem->elementList);
03244     if (elementItem == NULL)
03245         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03246                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03247                                   DCM_TAG_GROUP(tag),
03248                                   "DCM_GetSequenceTag");
03249 
03250     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
03251     while (!found && (elementItem != NULL)) {
03252         if (elementItem->element.tag == tag) {
03253             found = TRUE;
03254         } else
03255             elementItem = (void *)LST_Next(&groupItem->elementList);
03256     }
03257     if (!found)
03258         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03259                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03260                                   DCM_TAG_ELEMENT(tag),
03261                                   "DCM_GetElementValueList");
03262 
03263     if (!DCM_IsString(elementItem->element.representation)) {
03264         return COND_PushCondition(DCM_UNEXPECTEDREPRESENTATION,
03265         DCM_Message(DCM_UNEXPECTEDREPRESENTATION), "DCM_GetElementValueList",
03266                                   "string");
03267     }
03268     src = elementItem->element.d.string;
03269     l = elementItem->element.length;
03270     while (l > 0) {
03271         while (l > 1 && (*src == ' ' || *src == DCM_DELIMITOR)) {
03272             l--;
03273             src++;
03274         }
03275         if ((l == 1) && (*src == ' ' || *src == DCM_DELIMITOR))
03276             l--;
03277 
03278         if (l != 0) {
03279             p = CTN_MALLOC(structureSize);
03280             if (p == NULL)
03281                 return COND_PushCondition(DCM_MALLOCFAILURE,
03282                               DCM_Message(DCM_MALLOCFAILURE), structureSize,
03283                                           "DCM_GetElementValueList");
03284             dst = p + stringOffset;
03285             while ((l > 1) && (*src != DCM_DELIMITOR)) {
03286                 *dst++ = *src++;
03287                 l--;
03288             }
03289             if ((l == 1) && (*src != ' ')) {
03290                 *dst++ = *src++;
03291                 l--;
03292             }
03293             *dst = '\0';;
03294             cond = LST_Enqueue(list, (void *)p);
03295             if (cond != LST_NORMAL)
03296                 return COND_PushCondition(DCM_LISTFAILURE,
03297                    DCM_Message(DCM_LISTFAILURE), "DCM_GetElementValueList");
03298         }
03299     }
03300     return DCM_NORMAL;
03301 }
03302 
03303 /* DCM_AddElementList
03304 **
03305 ** Purpose:
03306 **      Add an element list to the DICOM object
03307 **
03308 ** Parameter Dictionary:
03309 **      callerObject            Handle to object to which the element is to be
03310 **                              added
03311 **      element                 The element in which the string obtained from
03312 **                              the list is to be stored. Finally the element
03313 **                              is added to the DICOM object.
03314 **      list                    List of structures , each containing a string
03315 **                              starting at some offset specified by the
03316 **                              parameter "offset"
03317 **      offset                  Offset in each individual structure (see
03318 **                              explanation for parameter list)
03319 **
03320 ** Return Values:
03321 **
03322 **      DCM_ILLEGALOBJECT
03323 **      DCM_ILLEGALREPRESENTATION
03324 **      DCM_INSERTFAILED
03325 **      DCM_NORMAL
03326 **      DCM_NULLOBJECT
03327 **
03328 ** Notes:
03329 **
03330 ** Algorithm:
03331 **      Description of the algorithm (optional) and any other notes.
03332 */
03333 CONDITION
03334 DCM_AddElementList(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
03335                    LST_HEAD * list, long offset)
03336 {
03337     DCM_ELEMENT
03338         e;                      /* Local copy of caller's element */
03339     CONDITION
03340         cond;
03341     char
03342        *s;
03343 
03344     e = *element;
03345     cond = DCM_ListToString(list, offset, &s);
03346     if (cond != DCM_NORMAL)
03347         return cond;
03348 
03349     e.d.string = s;
03350     e.length = strlen(s);
03351     cond = DCM_AddElement(callerObject, &e);
03352     CTN_FREE(s);
03353     return cond;
03354 }
03355 
03356 /* DCM_GetElement
03357 **
03358 ** Purpose:
03359 **      Get the element with the specified tag number from the given DICOM
03360 **      object
03361 **
03362 ** Parameter Dictionary:
03363 **      callerObject            Handle to the DICOM object
03364 **      tag                     Tag number of the element to be obtained
03365 **                              from the object
03366 **      element                 The element to be returned
03367 **
03368 ** Return Values:
03369 **
03370 **      DCM_ELEMENTNOTFOUND
03371 **      DCM_ILLEGALOBJECT
03372 **      DCM_NORMAL
03373 **      DCM_NULLOBJECT
03374 **
03375 ** Notes:
03376 **
03377 ** Algorithm:
03378 **      Description of the algorithm (optional) and any other notes.
03379 */
03380 CONDITION
03381 DCM_GetElement(DCM_OBJECT ** callerObject, DCM_TAG tag, DCM_ELEMENT * element)
03382 {
03383     PRIVATE_OBJECT
03384         ** obj;
03385     CONDITION
03386         cond;
03387     PRV_ELEMENT_ITEM
03388         * elementItem;
03389 
03390     obj = (PRIVATE_OBJECT **) callerObject;
03391     cond = checkObject(obj, "DCM_GetElementVM");
03392     if (cond != DCM_NORMAL)
03393         return cond;
03394 
03395     elementItem = locateElement(obj, tag);
03396     if (elementItem == NULL)
03397         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03398                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03399                                   DCM_TAG_ELEMENT(tag),
03400                                   "DCM_GetElementVM");
03401     *element = elementItem->element;
03402     element->d.ot = NULL;
03403     return DCM_NORMAL;
03404 }
03405 
03406 CONDITION
03407 DCM_ComputeExportLength(DCM_OBJECT ** callerObject, unsigned long opt,
03408                         unsigned long *length)
03409 {
03410     PRIVATE_OBJECT
03411         ** object;
03412     unsigned char
03413         buf[2048];
03414     CONDITION
03415         cond;
03416 
03417     object = (PRIVATE_OBJECT **) callerObject;
03418     cond = checkObject(object, "DCM_ComputeExportSize");
03419     if (cond != DCM_NORMAL)
03420         return cond;
03421 
03422     *length = 0;
03423     cond = DCM_ExportStream(callerObject, opt, buf,
03424                             (unsigned long) sizeof(buf), countBytes, length);
03425     if (cond != DCM_NORMAL)
03426         return cond;
03427 
03428     return DCM_NORMAL;
03429 }
03430 
03431 CONDITION
03432 DCM_CompareAttributes(DCM_OBJECT ** o1, DCM_OBJECT ** o2,
03433                       void (*callback) (const DCM_ELEMENT * e1,
03434                                         const DCM_ELEMENT * e2,
03435                                         void *ctx),
03436                       void *ctx)
03437 {
03438     PRIVATE_OBJECT **object1,
03439       **object2;
03440     PRV_GROUP_ITEM *groupItem1,
03441        *groupItem2;
03442     CONDITION cond;
03443 
03444     object1 = (PRIVATE_OBJECT **) o1;
03445     cond = checkObject(object1, "DCM_CompareAttributes");
03446     if (cond != DCM_NORMAL)
03447         return cond;
03448 
03449     object2 = (PRIVATE_OBJECT **) o2;
03450     cond = checkObject(object1, "DCM_CompareAttributes");
03451     if (cond != DCM_NORMAL)
03452         return cond;
03453 
03454     groupItem1 = (void *)LST_Head(&(*object1)->groupList);
03455     if (groupItem1 != NULL)
03456         (void) LST_Position(&(*object1)->groupList, (void *)groupItem1);
03457 
03458     groupItem2 = (void *)LST_Head(&(*object2)->groupList);
03459     if (groupItem2 != NULL)
03460         (void) LST_Position(&(*object2)->groupList, (void *)groupItem2);
03461 
03462 
03463     while (groupItem1 != NULL) {
03464         if (groupItem2 == NULL) {
03465             compareGroup(groupItem1, NULL, callback, ctx);
03466             groupItem1 = (void *)LST_Next(&(*object1)->groupList);
03467         } else if (groupItem1->group == groupItem2->group) {
03468             compareGroup(groupItem1, groupItem2, callback, ctx);
03469             groupItem1 = (void *)LST_Next(&(*object1)->groupList);
03470             groupItem2 = (void *)LST_Next(&(*object2)->groupList);
03471         } else if (groupItem1->group > groupItem2->group) {
03472             compareGroup(NULL, groupItem2, callback, ctx);
03473             groupItem2 = (void *)LST_Next(&(*object2)->groupList);
03474         } else {
03475             compareGroup(groupItem1, NULL, callback, ctx);
03476             groupItem1 = (void *)LST_Next(&(*object1)->groupList);
03477         }
03478     }
03479 
03480     while (groupItem2 != NULL) {
03481         compareGroup(NULL, groupItem2, callback, ctx);
03482         groupItem2 = (void *)LST_Next(&(*object2)->groupList);
03483     }
03484     return DCM_NORMAL;
03485 }
03486 
03487 CTNBOOLEAN
03488 DCM_GroupPresent(DCM_OBJECT ** o1, U16 group)
03489 {
03490     PRIVATE_OBJECT **object;
03491     PRV_GROUP_ITEM * item;
03492     CONDITION cond;
03493     CTNBOOLEAN tooFar = FALSE;
03494 
03495     object = (PRIVATE_OBJECT **) o1;
03496     cond = checkObject(object, "DCM_CompareAttributes");
03497     if (cond != DCM_NORMAL)
03498         return FALSE;
03499 
03500 
03501     item = (void *)LST_Head(&(*object)->groupList);
03502     if (item != NULL)
03503         (void) LST_Position(&(*object)->groupList, (void *)item);
03504 
03505     while (item != NULL && !tooFar) {
03506         if (item->group == group) {
03507             return TRUE;
03508         } else if (item->group > group) {
03509             tooFar = TRUE;
03510         } else {
03511             item = (void *)LST_Next(&(*object)->groupList);
03512         }
03513     }
03514     return FALSE;
03515 }
03516 
03517 /*     ------------------------------------------------------------
03518 **  Private functions below here
03519 */
03520 
03521 /* newElementItem
03522 **
03523 ** Purpose:
03524 **      Create a new element item suitable for placing in the linked
03525 **      list representation of an ACR object.  Copy data from an
03526 **      existing element, but skip the actual data field.
03527 **      Describe the purpose of the function
03528 **
03529 ** Parameter Dictionary:
03530 **      src     Pointer to source element that is to be copied
03531 **      dst     Pointer to pointer to destination element which is allocated
03532 **              by this routine and filled in appropriately.
03533 **
03534 ** Return Values:
03535 **      DCM_NORMAL
03536 **      DCM_ELEMENTCREATEFAILED
03537 **
03538 ** Algorithm:
03539 **      Allocate new element item of size:
03540 **              Size PRV_ELEMENT_ITEM + length of data value
03541 **      Copy data from caller's DCM_ELEMENT into newly created
03542 **              PRV_ELEMENT_ITEM.
03543 **      Point data value of newly created PRV_ELEMENT_ITEM to part of the
03544 **      allocated space (just past the end of the PRV_ELEMENT_ITEM).
03545 */
03546 static CONDITION
03547 newElementItem(DCM_ELEMENT * src, CTNBOOLEAN allocateData,
03548                PRV_ELEMENT_ITEM ** dst)
03549 {
03550     U32
03551     l;
03552 
03553     if (allocateData && (src->representation != DCM_SQ)) {
03554         l = src->length;
03555         if (l & 1)
03556             l++;
03557     } else
03558         l = 0;
03559 
03560     if (debug)
03561         fprintf(stderr, "newElementItem: CTN_MALLOC %8d %8d ", l,
03562                 (int)(sizeof(PRV_ELEMENT_ITEM) + l));
03563 
03564     *dst = (PRV_ELEMENT_ITEM *) CTN_MALLOC(sizeof(PRV_ELEMENT_ITEM) + l);
03565     if (debug)
03566         fprintf(stderr, "%8p\n", *dst);
03567 
03568     if (*dst == NULL) {
03569         return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
03570                      DCM_Message(DCM_ELEMENTCREATEFAILED), "newElementItem",
03571                                   DCM_TAG_GROUP(src->tag),
03572                                   DCM_TAG_ELEMENT(src->tag),
03573                                   l);
03574     }
03575     memset(*dst, 0, sizeof(PRV_ELEMENT_ITEM));
03576     (*dst)->element = *src;
03577     (*dst)->byteOrder = NATIVE_ORDER;
03578     (*dst)->allocatedDataLength = (size_t) l;
03579     (*dst)->originalDataLength = src->length;
03580     (*dst)->paddedDataLength = src->length;
03581     if (allocateData)
03582         (*dst)->element.d.ot = ((char *) (*dst)) + sizeof(PRV_ELEMENT_ITEM);
03583     else
03584         (*dst)->element.d.ot = NULL;
03585 
03586     (*dst)->fragmentFlag = 0;
03587     return DCM_NORMAL;
03588 }
03589 
03590 /* findCreateGroup
03591 **
03592 ** Purpose:
03593 **      Find the group in the DCM object corresponding to the group
03594 **      passed by the caller.  If the group does not yet exist, create
03595 **      a new group.  Set the CURRENT pointer in the linked list
03596 **      to point at that group.
03597 **
03598 ** Parameter Dictionary:
03599 **      object          Pointer to caller's DCM object
03600 **      group           Group number to locate/create
03601 **      groupPtr        Mechanism for returning pointer to located group
03602 **
03603 ** Return Values:
03604 **
03605 **      DCM_ELEMENTCREATEFAILED
03606 **      DCM_LISTFAILURE
03607 **      DCM_NORMAL
03608 **
03609 ** Algorithm:
03610 **      Set ITEM to head of linked list of ACR object
03611 **      Set CURRENT item in linked list to ITEM
03612 **      Search sequentially through linked list until:
03613 **          - Reach exisiting group that matches caller's group
03614 **          - Reach a group with larger group number than caller's group
03615 **          - Reach end of linked list
03616 **      Each time you move to a new item, update CURRENT to point to that item
03617 **      If reached existing group
03618 **          return
03619 **      If reached a group with larger group number than caller's group,
03620 **          Insert new group with Group Length Element (0000) just before
03621 **          the group with the larger group number.
03622 **          Set CURRENT pointer in linked list to point at new group
03623 **          If group is COMMAND or IDENTIFYING,
03624 **              Insert Length to End Element
03625 **          Return
03626 **      If reached end of the linked list
03627 **          Append new group with Group Length Element (0000) to the end
03628 **          of the linked list.
03629 **          Set CURRENT pointer in linked list to point at new group
03630 **          If group is COMMAND or IDENTIFYING,
03631 **              Insert Length to End Element
03632 **          Return
03633 **
03634 */
03635 
03636 static CONDITION
03637 findCreateGroup(PRIVATE_OBJECT ** object, unsigned short group,
03638                 PRV_GROUP_ITEM ** groupItem)
03639 {
03640     PRV_GROUP_ITEM
03641     * item;
03642     CONDITION
03643         cond;
03644     CTNBOOLEAN
03645         tooFar = FALSE;
03646 
03647     item = (void *)LST_Head(&(*object)->groupList);
03648     if (item != NULL)
03649         (void) LST_Position(&(*object)->groupList, (void *)item);
03650 
03651     while (item != NULL && !tooFar) {
03652         if (item->group == group) {
03653             *groupItem = item;
03654             return DCM_NORMAL;
03655         } else if (item->group > group) {
03656             tooFar = TRUE;
03657         } else {
03658             item = (void *)LST_Next(&(*object)->groupList);
03659         }
03660     }
03661 
03662     {
03663         U32 l;
03664         PRV_GROUP_ITEM *newGroupItem;
03665         DCM_ELEMENT groupLength = {0, DCM_UL, "", 1, sizeof(l), NULL};
03666         PRV_ELEMENT_ITEM *groupLengthItem;
03667 
03668         newGroupItem = CTN_MALLOC(sizeof(*newGroupItem));
03669         if (newGroupItem == NULL)
03670             return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
03671                                       DCM_Message(DCM_ELEMENTCREATEFAILED),
03672                                       "findCreateGroup",
03673                                       group, 0xffff, sizeof(*newGroupItem));
03674 
03675 
03676         *groupItem = newGroupItem;
03677         newGroupItem->group = group;
03678         newGroupItem->baseLength = 0;
03679         newGroupItem->longVRAttributes = 0;
03680         newGroupItem->elementList = LST_Create();
03681         if (newGroupItem->elementList == NULL)
03682             return COND_PushCondition(DCM_LISTFAILURE,
03683                                       DCM_Message(DCM_LISTFAILURE),
03684                                       "findCreateGroup");
03685 
03686         if (tooFar)
03687             cond = LST_Insert(&(*object)->groupList, (void *)newGroupItem, LST_K_BEFORE);
03688         else
03689             cond = LST_Enqueue(&(*object)->groupList, (void *)newGroupItem);
03690         if (cond != LST_NORMAL)
03691             return COND_PushCondition(DCM_LISTFAILURE,
03692                                       DCM_Message(DCM_LISTFAILURE),
03693                                       "findCreateGroup");
03694         (void) LST_Position(&(*object)->groupList, (void *)newGroupItem);
03695         if (cond != LST_NORMAL)
03696             return COND_PushCondition(DCM_LISTFAILURE,
03697                                       DCM_Message(DCM_LISTFAILURE),
03698                                       "findCreateGroup");
03699 
03700         groupLength.d.ul = &l;
03701         l = 0;
03702         if ((*object)->groupLengthFlag) {
03703             groupLength.tag = DCM_MAKETAG(group, 0);
03704             cond = newElementItem(&groupLength, TRUE, &groupLengthItem);
03705             (void) memcpy(groupLengthItem->element.d.ot, &l, sizeof(l));
03706 
03707             if (LST_Insert(&newGroupItem->elementList, (void *)groupLengthItem, LST_K_AFTER) !=
03708                 LST_NORMAL)
03709                 return COND_PushCondition(DCM_LISTFAILURE,
03710                                           DCM_Message(DCM_LISTFAILURE),
03711                                           "findCreateGroup");
03712 
03713             (*object)->objectSize += 8 + groupLengthItem->element.length;
03714         }
03715     }
03716     return DCM_NORMAL;
03717 }
03718 
03719 /* insertNewElement
03720 **
03721 ** Purpose:
03722 **      Create a new DCM_ELEMENT item using a copy of the caller's
03723 **      DCM_ELEMENT and insert it into the ACR object's linked list.
03724 **
03725 ** Parameter Dictionary:
03726 **      object          Pointer to caller's ACR_OBJECT
03727 **      element         Pointer to caller's ACR_ELEMENT to be copied
03728 **                      and inserted into linked list.
03729 **
03730 ** Return Values:
03731 **
03732 **      DCM_ELEMENTCREATEFAILED
03733 **      DCM_LISTFAILURE
03734 **      DCM_NORMAL
03735 **      DCM_UNEVENELEMENTLENGTH
03736 **      DCM_BADELEMENTINGROUP
03737 **
03738 ** Algorithm:
03739 **      Call newElementItem to create a copy of the DCM_ELEMENT
03740 **      Copy caller's data into data area allocated by newElementItem
03741 **      Increment object's OBJECTSIZE field by size of new element
03742 **      Use CURRENT pointer in DCM object linked list to get pointer
03743 **      to the group where we insert this element
03744 **      Update Group Length by adding size of new element
03745 **      Search sequentially through linked list until we reach:
03746 **          - End of linked list
03747 **          - A different group
03748 **          - An element in the same group with a larger element number
03749 **      If reached end of linked list
03750 **          Append new ACR_ELEMENTITEM to end of linked list
03751 **      If reached a different group
03752 **          Insert new ACR_ELEMENTITEM just before new group
03753 **      If reached an element in the same group with a larger element number
03754 **          Insert new ACR_ELEMENTITEM just before the "larger" element
03755 */
03756 static CONDITION
03757 insertNewElement(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
03758 {
03759     PRV_ELEMENT_ITEM
03760     * nextItem,
03761     *newItem;
03762     PRV_GROUP_ITEM
03763         * groupItem;
03764     CONDITION
03765         cond;
03766     char
03767        *p;
03768 
03769     cond = newElementItem(element, TRUE, &newItem);
03770     if (cond != DCM_NORMAL) {
03771         return cond;
03772     }
03773     newItem->byteOrder = DCM_ORDERNATIVE;
03774     if ((newItem->element.length & 1) != 0) {
03775         if (newItem->element.representation == DCM_AE) {
03776             p = newItem->element.d.string;      /* repair, check for 16 */
03777             p[newItem->element.length] = ' ';
03778             newItem->paddedDataLength = element->length + 1;
03779             (void) memcpy(p, element->d.string, element->length);
03780         } else if (newItem->element.representation == DCM_AS) {
03781             p = newItem->element.d.string;
03782             p[newItem->element.length] = ' ';
03783             newItem->paddedDataLength = element->length + 1;
03784             (void) memcpy(p, element->d.string, element->length);
03785         } else if (newItem->element.representation == DCM_CS) {
03786             p = newItem->element.d.string;
03787             p[newItem->element.length] = ' ';
03788             newItem->paddedDataLength = element->length + 1;
03789             (void) memcpy(p, element->d.string, element->length);
03790         } else if (newItem->element.representation == DCM_DA) {
03791             p = newItem->element.d.string;
03792             p[newItem->element.length] = ' ';
03793             newItem->paddedDataLength = element->length + 1;
03794             (void) memcpy(p, element->d.string, element->length);
03795         } else if (newItem->element.representation == DCM_DS) {
03796             p = newItem->element.d.string;
03797             p[newItem->element.length] = ' ';
03798             newItem->paddedDataLength = element->length + 1;
03799             (void) memcpy(p, element->d.string, element->length);
03800         } else if (newItem->element.representation == DCM_IS) {
03801             p = newItem->element.d.string;
03802             p[newItem->element.length] = ' ';
03803             newItem->paddedDataLength = element->length + 1;
03804             (void) memcpy(p, element->d.string, element->length);
03805         } else if (newItem->element.representation == DCM_LT) {
03806             p = newItem->element.d.string;
03807             p[newItem->element.length] = ' ';
03808             newItem->paddedDataLength = element->length + 1;
03809             (void) memcpy(p, element->d.string, element->length);
03810         } else if (newItem->element.representation == DCM_LO) {
03811             p = newItem->element.d.string;
03812             p[newItem->element.length] = ' ';
03813             newItem->paddedDataLength = element->length + 1;
03814             (void) memcpy(p, element->d.string, element->length);
03815         } else if (newItem->element.representation == DCM_PN) {
03816             p = newItem->element.d.string;
03817             p[newItem->element.length] = ' ';
03818             newItem->paddedDataLength = element->length + 1;
03819             (void) memcpy(p, element->d.string, element->length);
03820         } else if (newItem->element.representation == DCM_SH) {
03821             p = newItem->element.d.string;
03822             p[newItem->element.length] = ' ';
03823             newItem->paddedDataLength = element->length + 1;
03824             (void) memcpy(p, element->d.string, element->length);
03825         } else if (newItem->element.representation == DCM_ST) {
03826             p = newItem->element.d.string;
03827             p[newItem->element.length] = ' ';
03828             newItem->paddedDataLength = element->length + 1;
03829             (void) memcpy(p, element->d.string, element->length);
03830         } else if (newItem->element.representation == DCM_TM) {
03831             p = newItem->element.d.string;
03832             p[newItem->element.length] = ' ';
03833             newItem->paddedDataLength = element->length + 1;
03834             (void) memcpy(p, element->d.string, element->length);
03835         } else if (newItem->element.representation == DCM_UI) {
03836             p = newItem->element.d.string;
03837             p[newItem->element.length] = '\0';
03838             newItem->paddedDataLength = element->length + 1;
03839             (void) memcpy(p, element->d.string, element->length);
03840         } else if (newItem->element.representation == DCM_UT) {
03841             p = newItem->element.d.string;
03842             p[newItem->element.length] = ' ';
03843             newItem->paddedDataLength = element->length + 1;
03844             (void) memcpy(p, element->d.string, element->length);
03845         } else if (newItem->element.representation == DCM_SQ) {
03846 /*          newItem->element.length = 0xffffffff; */
03847             newItem->element.d.sq = element->d.sq;
03848         } else {
03849             CTN_FREE(newItem);
03850             return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
03851                                       DCM_Message(DCM_UNEVENELEMENTLENGTH),
03852                                       DCM_TAG_GROUP(element->tag),
03853                              DCM_TAG_ELEMENT(element->tag), element->length,
03854                                       "insertNewElement");
03855         }
03856     } else if (newItem->element.representation != DCM_SQ) {
03857         (void) memcpy(newItem->element.d.ot, element->d.ot, element->length);
03858     } else {
03859 /*      newItem->element.length = 0xffffffff; */
03860         newItem->element.d.sq = element->d.sq;
03861     }
03862     if ((*object)->objectSize != DCM_UNSPECIFIEDLENGTH)
03863         (*object)->objectSize += 8 + newItem->paddedDataLength;
03864 
03865 /* repair */
03866     cond = updateSpecialElements(object, newItem);
03867     if (cond != DCM_NORMAL)
03868         return cond;
03869 
03870     groupItem = (void *)LST_Current(&(*object)->groupList);
03871     if (groupItem == NULL)
03872         return COND_PushCondition(DCM_LISTFAILURE,
03873                           DCM_Message(DCM_LISTFAILURE), "insertNewElement");
03874 
03875     if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH)
03876         groupItem->baseLength += 2 + 2 + 4 + newItem->paddedDataLength;
03877 
03878     if (newItem->element.representation == DCM_OW ||
03879         newItem->element.representation == DCM_OB ||
03880         newItem->element.representation == DCM_SQ) {
03881         groupItem->longVRAttributes++;
03882         (*object)->longVRAttributes++;
03883     }
03884     if ((nextItem = (void *)LST_Head(&groupItem->elementList)) == NULL) {
03885         cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
03886         if (cond != LST_NORMAL)
03887             return COND_PushCondition(DCM_LISTFAILURE,
03888                                       DCM_Message(DCM_LISTFAILURE),
03889                                       "insertNewElement");
03890         else
03891             return DCM_NORMAL;
03892     }
03893     (void) LST_Position(&groupItem->elementList, (void *)nextItem);
03894     if (DCM_TAG_ELEMENT(nextItem->element.tag) == 0x0000)
03895         (void) memcpy(nextItem->element.d.ot, &groupItem->baseLength,
03896                       sizeof(groupItem->baseLength));
03897 
03898 /*  Now, search through the linked list for a place to insert/append
03899 **  this new item.
03900 */
03901 
03902     while (nextItem != NULL) {
03903         if (DCM_TAG_GROUP(element->tag) !=
03904             DCM_TAG_GROUP(nextItem->element.tag)) {
03905             return COND_PushCondition(DCM_BADELEMENTINGROUP,
03906                                       DCM_Message(DCM_BADELEMENTINGROUP),
03907                                       DCM_TAG_GROUP(nextItem->element.tag),
03908                                       DCM_TAG_ELEMENT(nextItem->element.tag),
03909                                       groupItem->group, "insertNewElement");
03910         } else if (DCM_TAG_ELEMENT(element->tag) <
03911                    DCM_TAG_ELEMENT(nextItem->element.tag)) {
03912             cond = LST_Insert(&groupItem->elementList, (void *)newItem, LST_K_BEFORE);
03913             if (cond != LST_NORMAL)
03914                 return COND_PushCondition(DCM_LISTFAILURE,
03915                                           DCM_Message(DCM_LISTFAILURE),
03916                                           "insertNewElement");
03917             else
03918                 return DCM_NORMAL;
03919         }
03920         nextItem = (void *)LST_Next(&groupItem->elementList);
03921     }
03922 
03923 /*  If we fall out of the loop, we must have reached the end of
03924 **  the group.  Add the element to the end of the list of elements
03925 **  in this group.
03926 */
03927 
03928     cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
03929     if (cond != LST_NORMAL)
03930         return COND_PushCondition(DCM_LISTFAILURE,
03931                                   DCM_Message(DCM_LISTFAILURE),
03932                                   "insertNewElement");
03933     else
03934         return DCM_NORMAL;
03935 }
03936 
03937 static CONDITION
03938 insertThisElementItem(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM* newItem)
03939 {
03940   PRV_ELEMENT_ITEM * nextItem;
03941   PRV_GROUP_ITEM * groupItem = 0;
03942   CONDITION cond;
03943 
03944 /* repair */
03945   cond = updateSpecialElements(object, newItem);
03946   if (cond != DCM_NORMAL)
03947     return cond;
03948 
03949   cond = findCreateGroup(object, DCM_TAG_GROUP(newItem->element.tag),
03950         &groupItem);
03951 
03952   if (groupItem == NULL)
03953     return COND_PushCondition(DCM_LISTFAILURE,
03954                           DCM_Message(DCM_LISTFAILURE), "insertThisElementItem");
03955 
03956   if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH)
03957     groupItem->baseLength += 2 + 2 + 4 + newItem->paddedDataLength;
03958 
03959   if (newItem->element.representation == DCM_OW ||
03960         newItem->element.representation == DCM_OB ||
03961         newItem->element.representation == DCM_SQ) {
03962         groupItem->longVRAttributes++;
03963         (*object)->longVRAttributes++;
03964   }
03965 
03966   if ((nextItem = (void *)LST_Head(&groupItem->elementList)) == NULL) {
03967     cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
03968     if (cond != LST_NORMAL)
03969       return COND_PushCondition(DCM_LISTFAILURE,
03970                                       DCM_Message(DCM_LISTFAILURE),
03971                                       "insertThisElementItem");
03972     else
03973       return DCM_NORMAL;
03974   }
03975 
03976   (void) LST_Position(&groupItem->elementList, (void *)nextItem);
03977   if (DCM_TAG_ELEMENT(nextItem->element.tag) == 0x0000)
03978     (void) memcpy(nextItem->element.d.ot, &groupItem->baseLength,
03979                       sizeof(groupItem->baseLength));
03980 
03981 /*  Now, search through the linked list for a place to insert/append
03982 **  this new item.
03983 */
03984 
03985   while (nextItem != NULL) {
03986     if (DCM_TAG_GROUP(newItem->element.tag) !=
03987             DCM_TAG_GROUP(nextItem->element.tag)) {
03988       return COND_PushCondition(DCM_BADELEMENTINGROUP,
03989                                       DCM_Message(DCM_BADELEMENTINGROUP),
03990                                       DCM_TAG_GROUP(nextItem->element.tag),
03991                                       DCM_TAG_ELEMENT(nextItem->element.tag),
03992                                       groupItem->group, "insertThisElementItem");
03993     } else if (DCM_TAG_ELEMENT(newItem->element.tag) <
03994                    DCM_TAG_ELEMENT(nextItem->element.tag)) {
03995       cond = LST_Insert(&groupItem->elementList, (void *)newItem, LST_K_BEFORE);
03996       if (cond != LST_NORMAL)
03997         return COND_PushCondition(DCM_LISTFAILURE,
03998                                           DCM_Message(DCM_LISTFAILURE),
03999                                           "insertThisElementItem");
04000       else
04001         return DCM_NORMAL;
04002       }
04003       nextItem = (void *)LST_Next(&groupItem->elementList);
04004   }
04005 
04006 /*  If we fall out of the loop, we must have reached the end of
04007 **  the group.  Add the element to the end of the list of elements
04008 **  in this group.
04009 */
04010 
04011   cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
04012   if (cond != LST_NORMAL)
04013     return COND_PushCondition(DCM_LISTFAILURE,
04014                                   DCM_Message(DCM_LISTFAILURE),
04015                                   "insertThisElementItem");
04016   else
04017     return DCM_NORMAL;
04018 }
04019 
04020 /* updateObjectType
04021 **
04022 ** Purpose:
04023 **      Possibly modify the objectType field of an DCM object to identify
04024 **      the object as COMMAND, DATASET or MESSAGE.
04025 **
04026 ** Parameter Dictionary:
04027 **      object          Pointer to caller's PRIVATE object to be updated
04028 **      element         Pointer to DCM_ELEMENT which will be added to
04029 **                      the object and possibly cause a change in the
04030 **                      type of the object.
04031 **
04032 ** Return Values:
04033 **      DCM_NORMAL
04034 **
04035 ** Algorithm:
04036 **      Description of the algorithm (optional) and any other notes.
04037 */
04038 
04039 static CONDITION
04040 updateObjectType(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
04041 {
04042     switch ((*object)->objectType) {
04043         case DCM_OBJECTUNKNOWN:
04044         if (DCM_TAG_GROUP(element->tag) == DCM_GROUPCOMMAND)
04045             (*object)->objectType = DCM_OBJECTCOMMAND;
04046         else
04047             (*object)->objectType = DCM_OBJECTELEMENTLIST;
04048         break;
04049     case DCM_OBJECTCOMMAND:
04050         if (DCM_TAG_GROUP(element->tag) != DCM_GROUPCOMMAND)
04051             (*object)->objectType = DCM_OBJECTELEMENTLIST;
04052         break;
04053     case DCM_OBJECTELEMENTLIST:
04054     case DCM_OBJECTIMAGE:
04055         break;
04056     default:
04057         break;
04058     }
04059     return DCM_NORMAL;
04060 }
04061 
04062 /* updateSpecialElements
04063 **
04064 ** Purpose:
04065 **      Update special elements in a DICOM object when a new data element
04066 **      is added to the object.  These special fields are used by other
04067 **      parts of the package which have to refer to those fields and wish
04068 **      to do so without searching through the entire list.  This could
04069 **      get messy and is a candidate for redesign.
04070 **
04071 ** Parameter Dictionary:
04072 **      object          Pointer to caller's PRIVATE DICOM object
04073 **      element         Pointer to DCM_ELEMENT that is being added to
04074 **                      the DICOM object
04075 **
04076 ** Return Values:
04077 **      DCM_NORMAL
04078 **
04079 ** Algorithm:
04080 **      Description of the algorithm (optional) and any other notes.
04081 */
04082 static CONDITION
04083 updateSpecialElements(PRIVATE_OBJECT ** object,
04084                       PRV_ELEMENT_ITEM * item)
04085 {
04086     int idx;
04087 
04088     switch (item->element.tag) {
04089     case DCM_IMGBITSALLOCATED:
04090         (*object)->pixelBitsAllocated = *item->element.d.us;
04091         break;
04092     case DCM_IMGPIXELREPRESENTATION:
04093         (*object)->pixelRepresentation = *item->element.d.us;
04094         break;
04095     case DCM_METAGROUPLENGTH:
04096         (*object)->metaHeaderLength = *item->element.d.ul;
04097         break;
04098     case DCM_METATRANSFERSYNTAX:
04099         if (strcmp(item->element.d.string, DICOM_TRANSFERLITTLEENDIAN) == 0) {
04100             (*object)->dataOptions = DCM_ORDERLITTLEENDIAN;
04101         } else if (strcmp(item->element.d.string, DICOM_TRANSFERLITTLEENDIANEXPLICIT) == 0) {
04102             (*object)->dataOptions = DCM_EXPLICITLITTLEENDIAN;
04103         } else if (strcmp(item->element.d.string, DICOM_TRANSFERBIGENDIANEXPLICIT) == 0) {
04104             (*object)->dataOptions = DCM_EXPLICITBIGENDIAN;
04105         } else {        /* Must be an encapsulated transfer syntax */
04106             (*object)->dataOptions = DCM_EXPLICITLITTLEENDIAN;
04107         }
04108         break;
04109     case DCM_MAKETAG(0x003a, 0x0103):
04110         strncpy((*object)->waveformDataVR, item->element.d.string,
04111                 item->element.length);
04112         (*object)->waveformDataVR[item->element.length] = '\0';
04113         idx = item->element.length - 1;
04114         while (idx >= 0 && (*object)->waveformDataVR[idx] == ' ') {
04115             (*object)->waveformDataVR[idx] = '\0';
04116             idx--;
04117         }
04118         break;
04119     default:
04120         break;
04121     }
04122     return DCM_NORMAL;
04123 }
04124 
04125 typedef struct {
04126     DCM_VALUEREPRESENTATION representation;
04127     char code[3];
04128 }   VRMAP;
04129 
04130 static VRMAP vrMap[] = {
04131     {DCM_AE, "AE"},
04132     {DCM_AS, "AS"},
04133     {DCM_AT, "AT"},
04134     {DCM_CS, "CS"},
04135     {DCM_DA, "DA"},
04136     {DCM_DD, "DD"},
04137     {DCM_DS, "DS"},
04138     {DCM_FD, "FD"},
04139     {DCM_FL, "FL"},
04140     {DCM_IS, "IS"},
04141     {DCM_LO, "LO"},
04142     {DCM_LT, "LT"},
04143     {DCM_OT, "OT"},
04144     {DCM_SH, "SH"},
04145     {DCM_SL, "SL"},
04146     {DCM_SQ, "SQ"},
04147     {DCM_SS, "SS"},
04148     {DCM_ST, "ST"},
04149     {DCM_TM, "TM"},
04150     {DCM_UI, "UI"},
04151     {DCM_UL, "UL"},
04152     {DCM_UN, "UN"},
04153     {DCM_US, "US"},
04154     {DCM_UT, "UT"},
04155     /*{DCM_UNKNOWN, "UK"},*/
04156     {DCM_RET, "RT"},
04157     {DCM_CTX, "  "},
04158     {DCM_PN, "PN"},
04159     {DCM_OB, "OB"},
04160     {DCM_OW, "OW"},
04161     {DCM_DT, "DT"},
04162     {DCM_DLM, ""}
04163 };
04164 
04165 static VRMAP *
04166 lookupVRCode(const char *code)
04167 {
04168     int i;
04169 
04170     for (i = 0; i < (int) DIM_OF(vrMap); i++) {
04171         if (strcmp(code, vrMap[i].code) == 0)
04172             return &vrMap[i];
04173     }
04174 
04175     return NULL;
04176 }
04177 
04178 static void
04179 mapVRtoASCII(DCM_VALUEREPRESENTATION vr, char *s)
04180 {
04181     int i;
04182 
04183     for (i = 0; i < (int) DIM_OF(vrMap); i++) {
04184         if (vr == vrMap[i].representation) {
04185             strcpy(s, vrMap[i].code);
04186             return;
04187         }
04188     }
04189 
04190     strcpy(s, "");
04191     return;
04192 }
04193 
04194 static void
04195 exportVRLength(DCM_ELEMENT * e, unsigned char *b, int byteOrder,
04196                U32 * rtnLength)
04197 {
04198     int i;
04199     char *c = "xx";
04200     unsigned char *p;
04201     U16 shortLength;
04202     DCM_VALUEREPRESENTATION vr;
04203 
04204     vr = e->representation;
04205     if (e->tag == DCM_MAKETAG(0x003a, 0x1000))
04206         vr = DCM_OB;
04207 
04208     for (i = 0; i < DIM_OF(vrMap); i++) {
04209         if (vr == vrMap[i].representation) {
04210             c = vrMap[i].code;
04211             break;
04212         }
04213     }
04214 
04215     *b++ = *c++;
04216     *b++ = *c++;
04217     *rtnLength += 2;
04218 
04219     if (vr == DCM_OB || vr == DCM_OW || vr == DCM_SQ || vr == DCM_UN) {
04220         *b++ = 0x00;
04221         *b++ = 0x00;
04222         if (byteOrder == BYTEORDER_SAME) {
04223             p = (unsigned char *) &e->length;
04224             *b++ = *p++;
04225             *b++ = *p++;
04226             *b++ = *p++;
04227             *b++ = *p++;
04228         } else {
04229             p = (unsigned char *) &e->length;
04230             *b++ = p[3];
04231             *b++ = p[2];
04232             *b++ = p[1];
04233             *b++ = p[0];
04234         }
04235         *rtnLength += 6;
04236     } else {
04237         shortLength = (U16) e->length;
04238         if (byteOrder == BYTEORDER_SAME) {
04239             p = (unsigned char *) &shortLength;
04240             *b++ = *p++;
04241             *b++ = *p++;
04242         } else {
04243             p = (unsigned char *) &shortLength;
04244             *b++ = p[1];
04245             *b++ = p[0];
04246         }
04247         *rtnLength += 2;
04248     }
04249 }
04250 
04251 static CONDITION
04252 exportPreamble(PRIVATE_OBJECT ** obj, unsigned char *dst,
04253                U32 bufferLength, U32 * rtnLength)
04254 {
04255     *rtnLength = 0;
04256     if (bufferLength < (DCM_PREAMBLELENGTH + 4))
04257         return COND_PushCondition(DCM_EXPORTBUFFERTOOSMALL,
04258                   DCM_Message(DCM_EXPORTBUFFERTOOSMALL), (int) bufferLength,
04259                                   "exportPreamble");
04260 
04261     (void) memcpy(dst, (*obj)->preamble, DCM_PREAMBLELENGTH);
04262     dst += DCM_PREAMBLELENGTH;
04263     (void) memcpy(dst, "DICM", 4);
04264     *rtnLength += DCM_PREAMBLELENGTH + 4;
04265 
04266     return DCM_NORMAL;
04267 }
04268 
04269 /* exportFixedFields
04270 **
04271 ** Purpose:
04272 **      This function exports the fixed length fields of an DCM_ELEMENT
04273 **      to the caller's buffer if there is sufficient space in the
04274 **      caller's buffer.
04275 **
04276 ** Parameter Dictionary:
04277 **      element         Pointer to the actual data element to be exported
04278 **      b               Pointer to the caller's buffer to hold exported data
04279 **      length          Length of the remaining space in the caller's
04280 **                      buffer
04281 **      byteOrder       flag giving the order of the bytes as they are
04282 **                      exported.  Should be one of:
04283 **                              BYTEORDER_SAME
04284 **                              BYTEORDER_REVERSE
04285 **      rtnLength       Pointer to caller variable to hold the length
04286 **                      of the data exported.  The length of the data
04287 **                      exported will be 0 if the caller's buffer is
04288 **                      too small to hold the fixed length fields.
04289 **
04290 ** Return Values:
04291 **      None
04292 **
04293 ** Algorithm:
04294 **      If caller buffer is too small to hold all fixed length fields
04295 **          Place 0 in caller's rtnLength variable
04296 **          return
04297 **      Else
04298 **          If byteOrder is the same
04299 **              Copy fixed length fields in same byte order
04300 **          Else
04301 **              Copy fixed length fields in reverse byte order
04302 **          Set caller's rtnLength variable to 8 (short, short, long)
04303 */
04304 
04305 static void
04306 exportFixedFields(DCM_ELEMENT * e,
04307                   unsigned char *b, U32 length, int byteOrder,
04308                   CTNBOOLEAN explicitVR, U32 * rtnLength)
04309 {
04310     unsigned char
04311        *p;
04312     unsigned short
04313         group,
04314         element;
04315     U32
04316         minimumLength;
04317 
04318     group = DCM_TAG_GROUP(e->tag);
04319     element = DCM_TAG_ELEMENT(e->tag);
04320     if (e->representation == DCM_DLM)
04321         explicitVR = FALSE;
04322 
04323     minimumLength = sizeof(group) + sizeof(element) + sizeof(e->length);
04324     if (explicitVR)
04325         minimumLength += 4;
04326 
04327     *rtnLength = 0;
04328     if (length >= minimumLength) {
04329         if (byteOrder == BYTEORDER_SAME) {
04330             p = (unsigned char *) &group;
04331             *b++ = *p++;
04332             *b++ = *p++;
04333             p = (unsigned char *) &element;
04334             *b++ = *p++;
04335             *b++ = *p++;
04336             *rtnLength += 4;
04337             if (explicitVR) {
04338                 exportVRLength(e, b, byteOrder, rtnLength);
04339             } else {
04340                 p = (unsigned char *) &e->length;
04341                 *b++ = *p++;
04342                 *b++ = *p++;
04343                 *b++ = *p++;
04344                 *b++ = *p++;
04345                 *rtnLength += 4;
04346             }
04347         } else {
04348             p = (unsigned char *) &group;
04349             *b++ = p[1];
04350             *b++ = p[0];
04351             p = (unsigned char *) &element;
04352             *b++ = p[1];
04353             *b++ = p[0];
04354             *rtnLength += 4;
04355             if (explicitVR) {
04356                 exportVRLength(e, b, byteOrder, rtnLength);
04357             } else {
04358                 p = (unsigned char *) &e->length;
04359                 *b++ = p[3];
04360                 *b++ = p[2];
04361                 *b++ = p[1];
04362                 *b++ = p[0];
04363                 *rtnLength += 4;
04364             }
04365         }
04366     }
04367 }
04368 
04369 /* exportData
04370 **
04371 ** Purpose:
04372 **      Export the data part of a DCM_ELEMENT.  This function exports
04373 **      all or part of the data portion of an DCM_ELEMENT in the byte order
04374 **      requested by the caller.  The caller specifies the byte order
04375 **      in a formal argument.  The function uses context information to
04376 **      know where to start the export in one data element.  The function
04377 **      does not update the context information but does return the
04378 **      number of bytes exported.
04379 **
04380 ** Parameter Dictionary:
04381 **      object          Pointer to the caller's ACR object which is
04382 **                      being exported.
04383 **      element         Pointer to the ACR_ELEMENT that is being exported
04384 **      b               Pointer to the caller's buffer to hold the
04385 **                      exported data.
04386 **      length          Length of the caller's buffer to hold the data.
04387 **      byteOrder       Flag giving the order of the bytes in the exported
04388 **                      stream.  Flag should be one of:
04389 **                          BYTEORDER_SAME
04390 **                          BYTEORDER_REVERSE
04391 **      rtnLength       Pointer to caller variable to hold number of bytes
04392 **                      that are actually exported.
04393 **
04394 ** Return Values:
04395 **
04396 **      DCM_FILEACCESSERROR
04397 **      DCM_NORMAL
04398 **
04399 ** Algorithm
04400 **
04401 **      Set caller's rtnLength variable to 0
04402 **      Export data based on representation of data element
04403 **      CASE 16 bit binary:
04404 **          While (length >= 2)
04405 **              If (byte order is same OR element is 8 bit pixel data)
04406 **                  Copy 2 bytes to output area
04407 **                  Increment input/output pointers by 2
04408 **              Else
04409 **                  Copy and swap 2 bytes to output area
04410 **                  Increment input/output pointers by 2
04411 **              Endif
04412 **              Decrement length by 2
04413 **              Increment caller's rtnLength by 2
04414 **          End while
04415 **
04416 **      CASE 32 bit binary:
04417 **          While (length >= 4)
04418 **              If (byte order is same)
04419 **                  Copy 4 bytes to output area
04420 **                  Increment input/output pointers by 4
04421 **              Else
04422 **                  Copy and swap 4 bytes to output area
04423 **                  Increment input/output pointers by 4
04424 **              Endif
04425 **              Decrement length by 4
04426 **              Increment caller's rtnLength by 4
04427 **
04428 **      CASE ascii text, ascii numeric, or unknown:
04429 **          Use memcpy to copy as of the remaining data as will fit
04430 **              in the caller's buffer.
04431 **          Set caller's rtnLength to the amount of data copied.
04432 **
04433 */
04434 union {
04435     unsigned short sh[2];
04436     unsigned char ch[4];
04437 }   groupElement;
04438 
04439 static CONDITION
04440 exportData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
04441            unsigned char *src,
04442            unsigned char *b, U32 length, int byteOrder,
04443            U32 * rtnLength)
04444 {
04445 /* repair OT for pixel data*/
04446     unsigned char
04447        *p;
04448     DCM_TAG
04449         * tag;
04450     DCM_ELEMENT
04451         * element;
04452     int nBytes;
04453     CONDITION cond;
04454 
04455     element = &item->element;
04456 
04457     *rtnLength = 0;
04458     if (element->d.ot == NULL) {
04459         if ((*object)->fd != -1) {
04460             (void) lseek((*object)->fd, item->currentOffset, SEEK_SET);
04461             nBytes = read((*object)->fd, b, (int) length);
04462         } else {
04463             (*object)->sk((*object)->userCtx, item->currentOffset, SEEK_SET);
04464             cond = (*object)->rd((*object)->userCtx, b, (long) length, &nBytes);
04465         }
04466         if ((U32) nBytes != length) {
04467             char b[512];
04468             sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
04469             (void) COND_PushCondition(DCM_GENERALWARNING,
04470                           DCM_Message(DCM_GENERALWARNING), "exportData", b);
04471             return COND_PushCondition(DCM_FILEACCESSERROR,
04472                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
04473                                       "exportData");
04474         }
04475         if( LITTLE_ENDIAN_ARCHITECTURE ){
04476           if (item->element.representation == DCM_AT) {
04477               DCM_ELEMENT e;
04478               e = *element;
04479               e.length = length;
04480               e.d.ot = b;
04481               swapATGroupElement(&e);
04482           }
04483         }
04484         if (byteOrder != item->byteOrder) {
04485             DCM_ELEMENT e;
04486             e = *element;
04487             e.length = length;
04488             e.d.ot = b;
04489             swapInPlace(object, &e);
04490         }
04491         *rtnLength = (U32) nBytes;
04492         item->currentOffset += nBytes;
04493     } else {
04494         p = src;
04495         switch (element->representation) {
04496         case DCM_AE:
04497         case DCM_AS:
04498         case DCM_CS:
04499         case DCM_DA:
04500         case DCM_DT:
04501         case DCM_DD:
04502         case DCM_DS:
04503         case DCM_FD:
04504         case DCM_IS:
04505         case DCM_LO:
04506         case DCM_LT:
04507         case DCM_OB:
04508         case DCM_OT:
04509         case DCM_PN:
04510         case DCM_SH:
04511         case DCM_SQ:
04512         case DCM_ST:
04513         case DCM_TM:
04514         case DCM_UI:
04515         case DCM_UT:
04516             (void) memcpy(b, p, length);
04517             *rtnLength = length;
04518             break;
04519         case DCM_AT:
04520             tag = (DCM_TAG *) p;
04521             while (length >= 4) {
04522                 groupElement.sh[0] = DCM_TAG_GROUP(*tag);
04523                 groupElement.sh[1] = DCM_TAG_ELEMENT(*tag);
04524                 if (byteOrder == BYTEORDER_SAME) {
04525                     *b++ = groupElement.ch[0];  /* Copy the group */
04526                     *b++ = groupElement.ch[1];
04527                     *b++ = groupElement.ch[2];  /* Now, the element */
04528                     *b++ = groupElement.ch[3];
04529                 } else {
04530                     *b++ = groupElement.ch[1];  /* Copy the group */
04531                     *b++ = groupElement.ch[0];
04532                     *b++ = groupElement.ch[3];  /* Now, the element */
04533                     *b++ = groupElement.ch[2];
04534                 }
04535                 tag++;
04536                 length -= 4;
04537                 *rtnLength += 4;
04538             }
04539             break;
04540         case DCM_SL:
04541         case DCM_UL:
04542         case DCM_FL:
04543             while (length >= 4) {
04544                 if (byteOrder == BYTEORDER_SAME) {
04545                     *b++ = *p++;
04546                     *b++ = *p++;
04547                     *b++ = *p++;
04548                     *b++ = *p++;
04549                 } else {
04550                     *b++ = p[3];
04551                     *b++ = p[2];
04552                     *b++ = p[1];
04553                     *b++ = p[0];
04554                     p += 4;
04555                 }
04556                 length -= 4;
04557                 *rtnLength += 4;
04558             }
04559             break;
04560         case DCM_SS:
04561         case DCM_US:
04562         case DCM_OW:
04563             /*
04564              * Temorary hack by Nilesh to support memory mapping for testing
04565              * purposes.
04566              */
04567             length &= ~1;
04568             *rtnLength += length;
04569             if (element->tag == DCM_PXLPIXELDATA) {
04570                 if (byteOrder == item->byteOrder)
04571                     (void) memcpy(b, p, length);
04572                 else
04573 #ifdef SOLARIS
04574                     swab((char *) p, (char *) b, length);
04575 #elif defined AIXV3
04576                 swab((short *) p, (short *) b, length);
04577 #elif defined MACOS
04578                 /* Not Yet Defined */
04579 #else
04580                     swab(p, b, length);
04581 #endif
04582             } else {
04583                 if (byteOrder == BYTEORDER_SAME)
04584                     (void) memcpy(b, p, length);
04585                 else
04586 #ifdef SOLARIS
04587                     swab((char *) p, (char *) b, length);
04588 #elif defined AIXV3
04589                 swab((short *) p, (short *) b, length);
04590 #elif defined MACOS
04591                 /* Not Yet Defined */
04592 #else
04593                     swab(p, b, length);
04594 #endif
04595             }
04596             break;
04597         /*case DCM_UNKNOWN:*/
04598         case DCM_UN:
04599         default:
04600 #if 0
04601             fprintf(stderr, "Should not get to default in exportData: %08x\n",
04602                     element->tag);
04603 #endif
04604             (void) memcpy(b, p, length);
04605             *rtnLength = length;
04606             break;
04607         }
04608     }
04609     return DCM_NORMAL;
04610 }
04611 
04612 static CONDITION
04613 exportEncapsulatedPixels(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
04614         unsigned char* buffer, U32 bufferlength, DCM_EXPORT_STREAM_CALLBACK* callback,
04615         void* ctx)
04616 {
04617   DCM_ELEMENT * element;
04618   int nBytes;
04619   CONDITION cond;
04620   U32 toExport;
04621   int length;
04622   DCM_FRAGMENT_ITEM* fragmentItem = 0;
04623   DCM_ELEMENT e;
04624   U32 rtnLength = 0;
04625 
04626   element = &item->element;
04627   if (element->d.ot == NULL) {
04628     if ((*object)->fd != -1) {
04629       /* Seek to the beginning of the data. Have to back up 12 bytes to
04630       ** get the pixel tag, VR, etc
04631       */
04632       (void) lseek((*object)->fd, item->dataOffset-12, SEEK_SET);
04633     } else {
04634       (*object)->sk((*object)->userCtx, item->dataOffset-12, SEEK_SET);
04635     }
04636 
04637     toExport = item->originalDataLength + 12;
04638     while(toExport > 0) {
04639       length = (toExport < bufferlength) ? toExport : bufferlength;
04640 
04641       if ((*object)->fd != -1) {
04642         nBytes = read((*object)->fd, buffer, length);
04643       } else {
04644         cond = (*object)->rd((*object)->userCtx, buffer, (long) length, &nBytes);
04645       }
04646       if ((U32) nBytes != length) {
04647         char b[512];
04648         sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
04649         (void) COND_PushCondition(DCM_GENERALWARNING,
04650                           DCM_Message(DCM_GENERALWARNING), "exportEncapsualtedPixels", b);
04651         return COND_PushCondition(DCM_FILEACCESSERROR,
04652                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
04653                                       "exportEncapsualtedPixels");
04654       }
04655       cond = callback(buffer, length, 0, ctx);
04656       if (cond != DCM_NORMAL) {
04657         return COND_PushCondition(DCM_CALLBACKABORTED,
04658               DCM_Message(DCM_CALLBACKABORTED), "exportStream");
04659       }
04660       toExport -= length;
04661     }
04662   } else {
04663     if (item->fragmentFlag != 1) {
04664       return COND_PushCondition(DCM_NOFRAGMENTSINOBJECT,
04665         "DCM Exporting pixels but did not find expected fragments in object");
04666     }
04667     e.tag = DCM_PXLPIXELDATA;
04668     e.d.ot = 0;
04669     e.representation = DCM_OB;
04670     e.length = 0xffffffff;
04671     exportFixedFields(&e, buffer, bufferlength,
04672                         LITTLE_ORDER /*byteOrder*/,
04673                         1 /* explicitV*/,
04674                         &rtnLength);
04675     toExport = rtnLength;
04676     e.tag = 0xfffee000;
04677     e.length = 0;
04678     e.representation = DCM_DLM;
04679     e.d.ot = 0;
04680     exportFixedFields(&e, buffer+toExport, bufferlength,
04681                         LITTLE_ORDER /*byteOrder*/,
04682                         1 /* explicitV*/,
04683                         &rtnLength);
04684     toExport += rtnLength;
04685 
04686     cond = callback(buffer, toExport, 0, ctx);
04687     if (cond != DCM_NORMAL) {
04688       return COND_PushCondition(DCM_CALLBACKABORTED,
04689               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04690     }
04691 
04692     fragmentItem = (DCM_FRAGMENT_ITEM*)LST_Head(&item->element.d.fragments);
04693     (void)LST_Position(&item->element.d.fragments, (void *)fragmentItem);
04694     while (fragmentItem != NULL) {
04695       RWC_printf("Fragment size: %6d\n", fragmentItem->length);
04696       e.tag = 0xfffee000;
04697       e.length = fragmentItem->length;
04698       e.representation = DCM_DLM;
04699       exportFixedFields(&e, buffer, bufferlength,
04700                         LITTLE_ORDER /*byteOrder*/,
04701                         1 /* explicitV*/,
04702                         &rtnLength);
04703       cond = callback(buffer, rtnLength, 0, ctx);
04704       if (cond != DCM_NORMAL) {
04705         return COND_PushCondition(DCM_CALLBACKABORTED,
04706               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04707       }
04708       cond = callback(fragmentItem->fragment, fragmentItem->length, 0, ctx);
04709       if (cond != DCM_NORMAL) {
04710         return COND_PushCondition(DCM_CALLBACKABORTED,
04711               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04712       }
04713 
04714       fragmentItem = (void *)LST_Next(&item->element.d.fragments);
04715     }
04716     e.tag = 0xfffee0dd;
04717     e.length = 0;
04718     e.representation = DCM_DLM;
04719     e.d.ot = 0;
04720     exportFixedFields(&e, buffer, bufferlength,
04721                         LITTLE_ORDER /*byteOrder*/,
04722                         1 /* explicitV*/,
04723                         &rtnLength);
04724     cond = callback(buffer, rtnLength, 0, ctx);
04725     if (cond != DCM_NORMAL) {
04726       return COND_PushCondition(DCM_CALLBACKABORTED,
04727               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04728     }
04729   }
04730   return DCM_NORMAL;
04731 }
04732 
04733 static CONDITION
04734 exportPixels(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
04735         int encapsulatedPixels,
04736         unsigned char* buffer, U32 bufferlength, DCM_EXPORT_STREAM_CALLBACK* callback,
04737         void* ctx,
04738         int byteOrder, int explicitVR)
04739 {
04740   DCM_ELEMENT * element;
04741   int nBytes;
04742   CONDITION cond;
04743   U32 toExport;
04744   U32 bytesExported = 0;
04745   U32 exportLength = 0;
04746   int length;
04747   U32 rtnLength;
04748   U32 remainingData;
04749   unsigned char* dst;
04750   unsigned char* src;
04751   int c;
04752 
04753   if (encapsulatedPixels) {
04754     return exportEncapsulatedPixels(object, item, buffer,
04755         bufferlength, callback, ctx);
04756   }
04757 
04758   element = &item->element;
04759   rtnLength = 0;
04760   dst = buffer;
04761   c = bufferlength;
04762   exportFixedFields(element, dst, bufferlength, byteOrder,
04763                                   explicitVR, &rtnLength);
04764   dst += rtnLength;
04765   c -= rtnLength;
04766   bytesExported = rtnLength;
04767 
04768   remainingData = element->length;
04769   src = element->d.ot;
04770   item->currentOffset = item->dataOffset;
04771 
04772   while (remainingData > 0) {
04773     if (debug) {
04774       fprintf(stderr, "Export: (%08x) %d\n", element->tag, element->length);
04775     }
04776 
04777     if (element->d.ot != NULL) {
04778       remainingData = element->length -
04779                             (src - ((unsigned char *) element->d.ot));
04780     } else {
04781       remainingData = element->length -
04782                             (item->currentOffset - item->dataOffset);
04783     }
04784 
04785     exportLength = (remainingData < c) ? remainingData : c;
04786     cond = exportData(object, item, src, dst,
04787                       exportLength, byteOrder, &rtnLength);
04788     if (cond != DCM_NORMAL)
04789       return cond;
04790 
04791     src += rtnLength;
04792     dst += rtnLength;
04793     bytesExported += rtnLength;
04794     c -= rtnLength;
04795 
04796     if (c <= 20) {
04797       cond = callback(buffer, bytesExported, 0, ctx);
04798       if (cond != DCM_NORMAL) {
04799         return COND_PushCondition(DCM_CALLBACKABORTED,
04800               DCM_Message(DCM_CALLBACKABORTED), "exportPixels");
04801       }
04802       bytesExported = 0;
04803       c = bufferlength;
04804       dst = (unsigned char *) buffer;
04805     }
04806   }
04807   if (bytesExported > 0) {
04808     cond = callback(buffer, bytesExported, 0, ctx);
04809     if (cond != DCM_NORMAL) {
04810       return COND_PushCondition(DCM_CALLBACKABORTED,
04811               DCM_Message(DCM_CALLBACKABORTED), "exportPixels");
04812     }
04813   }
04814 
04815   return DCM_NORMAL;
04816 
04817 #if 0
04818   if (element->d.ot == NULL) {
04819     if ((*object)->fd != -1) {
04820       /* Seek to the beginning of the data. Have to back up 12 bytes to
04821       ** get the pixel tag, VR, etc
04822       */
04823       (void) lseek((*object)->fd, item->dataOffset-12, SEEK_SET);
04824     } else {
04825       (*object)->sk((*object)->userCtx, item->dataOffset-12, SEEK_SET);
04826     }
04827 
04828     toExport = item->originalDataLength + 12;
04829     while(toExport > 0) {
04830       length = (toExport < bufferlength) ? toExport : bufferlength;
04831 
04832       if ((*object)->fd != -1) {
04833         nBytes = read((*object)->fd, buffer, length);
04834       } else {
04835         cond = (*object)->rd((*object)->userCtx, buffer, (long) length, &nBytes);
04836       }
04837       if ((U32) nBytes != length) {
04838         char b[512];
04839         sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
04840         (void) COND_PushCondition(DCM_GENERALWARNING,
04841                           DCM_Message(DCM_GENERALWARNING), "exportPixels", b);
04842         return COND_PushCondition(DCM_FILEACCESSERROR,
04843                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
04844                                       "exportPixels");
04845       }
04846       cond = callback(buffer, length, 0, ctx);
04847       if (cond != DCM_NORMAL) {
04848         return COND_PushCondition(DCM_CALLBACKABORTED,
04849               DCM_Message(DCM_CALLBACKABORTED), "exportStream");
04850       }
04851       toExport -= length;
04852     }
04853   } else {
04854   }
04855   return DCM_NORMAL;
04856 #endif
04857 
04858 }
04859 
04860 /* fileSize
04861 **
04862 ** Purpose:
04863 **      Determine the file size of a file on an open descriptor.
04864 **
04865 ** Parameter Dictionary:
04866 **      fd      File descriptor for an open file.
04867 **
04868 ** Return Values:
04869 **      the size of the open file in bytes (nonnegative)
04870 **      a negative status value returned by fstat
04871 **
04872 ** Algorithm:
04873 **      call unix fstat system call to get file size.
04874 **      if successful call
04875 **          return file size
04876 **      else
04877 **          return status returned by fstat call (-1)
04878 */
04879 #ifdef MACOS
04880 static long
04881 #else
04882 static int
04883 #endif
04884 fileSize(int fd)
04885 {
04886     int
04887         status;
04888     struct stat
04889         im_stat;
04890 
04891     status = fstat(fd, &im_stat);
04892     if (status < 0) {
04893         return status;
04894     } else
04895         return im_stat.st_size;
04896 }
04897 
04898 /* swapInPlace
04899 **
04900 ** Purpose:
04901 **      Swap data in place for byte order adjustment.  Bytes are swapped
04902 **      for data with representations of DCM_US and DCM_UL (binary values).
04903 **      Special care is taken with pixel data which may be 8 bits.
04904 **
04905 ** Parameter Dictionary:
04906 **      object          Pointer to caller's DCM object containing the
04907 **                      element with the data to be swapped
04908 **      element         Pointer to DCM_ELEMENT that contains the data to be
04909 **                      swapped.
04910 **
04911 ** Return Values:
04912 **      None
04913 **
04914 ** Algorithm:
04915 **      If (element->representation is 16 bit binary)
04916 **          If (element is pixel data and pixel data is not 16 bits)
04917 **              return
04918 **          Swap in place short integers for this element.
04919 **      Else if (element->representation is 32 bit binary)
04920 **          Swap in place long integers for this element
04921 */
04922 
04923 static void
04924 swapInPlace(PRIVATE_OBJECT ** object, DCM_ELEMENT * e)
04925 {
04926     U32
04927     length;
04928     unsigned char
04929         tmp,
04930        *p1;
04931 
04932     length = e->length;
04933     p1 = e->d.ot;
04934     if (e->representation == DCM_US || e->representation == DCM_SS ||
04935         e->representation == DCM_OW || e->representation == DCM_AT) {
04936         if (e->tag == DCM_PXLPIXELDATA &&
04937             (*object)->pixelBitsAllocated != 16)
04938             return;
04939 
04940         while (length > 0) {
04941             tmp = p1[0];
04942             p1[0] = p1[1];
04943             p1[1] = tmp;
04944             p1 += 2;
04945             length -= 2;
04946         }
04947     } else if (e->representation == DCM_UL || e->representation == DCM_SL) {
04948         while (length > 0) {
04949             tmp = p1[0];
04950             p1[0] = p1[3];
04951             p1[3] = tmp;
04952             tmp = p1[1];
04953             p1[1] = p1[2];
04954             p1[2] = tmp;
04955             length -= 4;
04956             p1 += 4;
04957         }
04958     }
04959 }
04960 
04961 
04962 /* checkObject
04963 **
04964 ** Purpose:
04965 **      Examine a PRIVATE OBJECT to see if it looks like is has the proper
04966 **      fields defined.  This function is used to try to make certain that
04967 **      users call the DCM routines with the proper objects.  If the object
04968 **      is legal, the function returns DCM_NORMAL.  If the object is not
04969 **      legal, the function will return an error.
04970 **
04971 ** Parameter Dictionary:
04972 **      object          PRIVATE_OBJECT to be examined by this function
04973 **      caller          Name of the function (ASCIZ) that called this
04974 **                      function.  In case of failure, this becomes part of
04975 **                      the error message that is pushed on the stack.
04976 **
04977 ** Return Values:
04978 **      DCM_NORMAL
04979 **      DCM_NULLOBJECT
04980 **      DCM_ILLEGALOBJECT
04981 **
04982 ** Algorithm:
04983 **      Description of the algorithm (optional) and any other notes.
04984 */
04985 
04986 static CONDITION
04987 checkObject(PRIVATE_OBJECT ** object, char *caller)
04988 {
04989     if (object == NULL)
04990         return COND_PushCondition(DCM_NULLOBJECT, DCM_Message(DCM_NULLOBJECT),
04991                                   caller);
04992     if (*object == NULL)
04993         return COND_PushCondition(DCM_NULLOBJECT, DCM_Message(DCM_NULLOBJECT),
04994                                   caller);
04995 
04996     if (strcmp((*object)->keyType, KEY_DCM_OBJECT) != 0)
04997         return COND_PushCondition(DCM_ILLEGALOBJECT,
04998                                   DCM_Message(DCM_ILLEGALOBJECT), caller);
04999     return DCM_NORMAL;
05000 }
05001 
05002 
05003 /* writeFile
05004 **
05005 ** Purpose:
05006 **      Write the data in the buffer into the file specified by the file
05007 **      descriptor
05008 **
05009 ** Parameter Dictionary:
05010 **      buffer          Buffer holding the information to be written
05011 **      length          Length of the buffer
05012 **      flag            Unused
05013 **      fd              File descriptor
05014 **
05015 ** Return Values:
05016 **
05017 **      DCM_FILEIOERROR
05018 **      DCM_NORMAL
05019 **
05020 ** Notes:
05021 **
05022 ** Algorithm:
05023 **      Description of the algorithm (optional) and any other notes.
05024 */
05025 
05026 static CONDITION
05027 writeFile(void *buffer, U32 length, int flag,
05028           void /* int */ *fdPtr)
05029 {
05030     int
05031         bytesWritten;
05032     int *fd;
05033 
05034     fd = (int *) fdPtr;
05035 
05036     bytesWritten = write(*fd, buffer, (int) length);
05037     if (bytesWritten != (int) length)
05038         return COND_PushCondition(DCM_FILEIOERROR,
05039                           DCM_Message(DCM_FILEIOERROR), "", strerror(errno),
05040                                   "writeFile");
05041     else
05042         return DCM_NORMAL;
05043 }
05044 
05045 static CONDITION
05046 countBytes(void *buffer, U32 length, int flag,
05047            void /* unsigned long */ *sizePtr)
05048 {
05049     unsigned long *size;
05050 
05051     size = (unsigned long *) sizePtr;
05052 
05053     *size += length;
05054 
05055     return DCM_NORMAL;
05056 }
05057 
05058 static CONDITION
05059 setFileOptions(DCM_OBJECT ** obj, unsigned long *opt)
05060 {
05061     CONDITION cond;
05062     char xferSyntax[DICOM_UI_LENGTH + 1];
05063     DCM_ELEMENT e = {DCM_METATRANSFERSYNTAX, DCM_UI, "", 1, sizeof(xferSyntax),
05064     NULL};
05065 
05066     e.d.string = xferSyntax;
05067     cond = DCM_ParseObject(obj, &e, 1, NULL, 0, NULL);
05068     if (cond != DCM_NORMAL)
05069         return cond;
05070 
05071     *opt = 0;
05072     if (strcmp(xferSyntax, DICOM_TRANSFERLITTLEENDIAN) == 0) {
05073         *opt = DCM_ORDERLITTLEENDIAN;
05074     } else if (strcmp(xferSyntax, DICOM_TRANSFERLITTLEENDIANEXPLICIT) == 0) {
05075         *opt = DCM_EXPLICITLITTLEENDIAN;
05076     } else if (strcmp(xferSyntax, DICOM_TRANSFERBIGENDIANEXPLICIT) == 0) {
05077         *opt = DCM_EXPLICITBIGENDIAN;
05078     } else {    /* Must be an encapsulated xfer syntax */
05079         *opt = DCM_ENCAPSULATEDPIXELS;
05080     }
05081 
05082     return DCM_NORMAL;
05083 }
05084 
05085 static CONDITION
05086 extractFileOptions(unsigned long opt, CTNBOOLEAN * part10File,
05087                    CTNBOOLEAN * explicitVR, int *byteOrder,
05088                    CTNBOOLEAN* encapsulatedPixels)
05089 {
05090     *part10File = *explicitVR = FALSE;
05091 
05092     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
05093         *part10File = TRUE;
05094         opt &= ~DCM_ORDERMASK;
05095         opt |= DCM_EXPLICITLITTLEENDIAN;
05096     }
05097     if ((opt & DCM_ORDERMASK) == 0)
05098         return COND_PushCondition(DCM_ILLEGALOPTION,
05099                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
05100                                   "extractFileOptions");
05101 
05102     switch (opt & DCM_ORDERMASK) {
05103     case DCM_ORDERNATIVE:
05104         *byteOrder = NATIVE_ORDER;
05105         *encapsulatedPixels = FALSE;
05106         break;
05107     case DCM_ORDERLITTLEENDIAN:
05108         *byteOrder = LITTLE_ORDER;
05109         *encapsulatedPixels = FALSE;
05110         break;
05111     case DCM_EXPLICITLITTLEENDIAN:
05112         *byteOrder = LITTLE_ORDER;
05113         *explicitVR = TRUE;
05114         *encapsulatedPixels = FALSE;
05115         break;
05116     case DCM_ORDERBIGENDIAN:
05117         *byteOrder = BIG_ORDER;
05118         *encapsulatedPixels = FALSE;
05119         break;
05120     case DCM_EXPLICITBIGENDIAN:
05121         *byteOrder = BIG_ORDER;
05122         *explicitVR = TRUE;
05123         *encapsulatedPixels = FALSE;
05124         break;
05125     case DCM_ENCAPSULATEDPIXELS:
05126         *byteOrder = LITTLE_ORDER;
05127         *explicitVR = TRUE;
05128         *encapsulatedPixels = TRUE;
05129         break;
05130     default:
05131         *byteOrder = LITTLE_ORDER;
05132         *encapsulatedPixels = FALSE;
05133         break;
05134     }
05135 
05136     return DCM_NORMAL;
05137 }
05138 
05139 static U32
05140 computeGroupLength(PRV_GROUP_ITEM * groupItem,
05141                    CTNBOOLEAN explicitVR)
05142 {
05143     return (explicitVR) ?
05144     groupItem->baseLength + 4 * groupItem->longVRAttributes :
05145     groupItem->baseLength;
05146 
05147 }
05148 
05149 /* exportStream
05150 **
05151 ** Purpose:
05152 **      Export a DICOM object into the stream format suitable
05153 **      for network transmission or disk storage.
05154 **
05155 ** Parameter Dictionary:
05156 **      callerObject            Handle to caller's DICOM object
05157 **      opt                     Bit mask giving options for exporting data
05158 **      buffer                  Pointer to caller's buffer to hold next chunk
05159 **                              of DCM stream data
05160 **      bufferlength            Length of caller's buffer to hold stream data
05161 **      callback                Callback routine to be called.
05162 **      ctx                     Pointer to context variable we maintain to keep
05163 **                              track of our location in export process.
05164 **      sequenceLevel           Current level in the sequence hierarchy
05165 **
05166 ** Return Values:
05167 **
05168 **      DCM_FILEACCESSERROR
05169 **      DCM_ILLEGALOBJECT
05170 **      DCM_LISTFAILURE
05171 **      DCM_NORMAL
05172 **      DCM_NULLOBJECT
05173 **      DCM_CALLBACKABORTED
05174 **
05175 ** Notes:
05176 **
05177 ** Algorithm:
05178 **      Description of the algorithm (optional) and any other notes.
05179 */
05180 
05181 static CONDITION
05182 exportStream(DCM_OBJECT ** callerObject, unsigned long opt,
05183              void *buffer, U32 bufferlength, DCM_EXPORT_STREAM_CALLBACK* callback,
05184              void *ctx, int sequenceLevel)
05185 {
05186     PRIVATE_OBJECT
05187     ** object;
05188     PRV_GROUP_ITEM
05189         * groupItem;
05190     PRV_ELEMENT_ITEM
05191         * elementItem;
05192     DCM_ELEMENT
05193         element;
05194     int
05195         byteOrder;
05196     int
05197         lastFlag = 0;
05198     unsigned char
05199        *src,
05200        *dst;
05201     U32
05202         c,
05203         bytesExported = 0,
05204         rtnLength,
05205         remainingData,
05206         exportLength;
05207     CONDITION
05208         cond;
05209     DCM_SEQUENCE_ITEM
05210         * sequenceItem;
05211     DCM_ELEMENT
05212         itemMarker = {
05213         DCM_DLMITEM, DCM_DLM, "", 1, DCM_UNSPECIFIEDLENGTH, NULL
05214     },
05215         itemDelimiter = {
05216         DCM_DLMITEMDELIMITATIONITEM, DCM_DLM, "", 1, 0, NULL
05217     },
05218         sequenceDelimiter = {
05219         DCM_DLMSEQUENCEDELIMITATIONITEM, DCM_DLM, "", 1, 0, NULL
05220     };
05221     CTNBOOLEAN
05222         unspecifiedSQLength = FALSE,
05223         explicitVR = FALSE,
05224         part10File = FALSE,
05225         encapsulatedPixels = FALSE;
05226     unsigned long fileOptions = 0;
05227 
05228     object = (PRIVATE_OBJECT **) callerObject;
05229     cond = checkObject(object, "exportStream");
05230     if (cond != DCM_NORMAL)
05231         return cond;
05232 
05233     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
05234         part10File = TRUE;
05235         opt &= ~DCM_ORDERMASK;
05236         opt |= DCM_EXPLICITLITTLEENDIAN;
05237         cond = setFileOptions(callerObject, &fileOptions);
05238         if (cond != DCM_NORMAL)
05239             return cond;
05240     }
05241     if ((opt & DCM_ORDERMASK) == 0)
05242         return COND_PushCondition(DCM_ILLEGALOPTION,
05243                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
05244                                   "exportStream");
05245 
05246     switch (opt & DCM_ORDERMASK) {
05247     case DCM_ORDERNATIVE:
05248         byteOrder = NATIVE_ORDER;
05249         break;
05250     case DCM_ORDERLITTLEENDIAN:
05251         byteOrder = LITTLE_ORDER;
05252         break;
05253     case DCM_EXPLICITLITTLEENDIAN:
05254         byteOrder = LITTLE_ORDER;
05255         explicitVR = TRUE;
05256         break;
05257     case DCM_ORDERBIGENDIAN:
05258         byteOrder = BIG_ORDER;
05259         break;
05260     case DCM_EXPLICITBIGENDIAN:
05261         byteOrder = BIG_ORDER;
05262         explicitVR = TRUE;
05263         break;
05264     case DCM_ENCAPSULATEDPIXELS:
05265         byteOrder = LITTLE_ORDER;
05266         explicitVR = TRUE;
05267         encapsulatedPixels = TRUE;
05268         break;
05269     default:
05270         byteOrder = LITTLE_ORDER;
05271         break;
05272     }
05273 
05274 /*  We are making this step mandatory for now (smm)*/
05275 
05276     opt &= ~DCM_SEQUENCELENGTHMASK;
05277     opt |= DCM_UNSPECIFIEDLENGTHFLAG;
05278 
05279 /*  End of something that is out of place */
05280 
05281     if ((opt & DCM_SEQUENCELENGTHMASK) == DCM_UNSPECIFIEDLENGTHFLAG)
05282         unspecifiedSQLength = TRUE;
05283 
05284     dst = (unsigned char *) buffer;
05285     c = bufferlength;
05286 
05287     if (part10File) {
05288         cond = exportPreamble(object, dst, c, &rtnLength);
05289         if (cond != DCM_NORMAL)
05290             return cond;
05291 
05292         dst += rtnLength;
05293         c -= rtnLength;
05294         bytesExported += rtnLength;
05295     }
05296     if (sequenceLevel != 0) {
05297         if (!unspecifiedSQLength)
05298             itemMarker.length = (*object)->objectSize;
05299         exportFixedFields(&itemMarker, dst, bufferlength, byteOrder,
05300                           explicitVR, &rtnLength);
05301         dst += rtnLength;
05302         c -= rtnLength;
05303         bytesExported += rtnLength;
05304     }
05305     groupItem = (void *)LST_Head(&(*object)->groupList);
05306 
05307 /*  Take this code out to allow empty groups. */
05308 #if 0
05309     if (groupItem == NULL)
05310         return COND_PushCondition(DCM_LISTFAILURE,
05311                               DCM_Message(DCM_LISTFAILURE), "exportStream");
05312 #endif
05313     if (groupItem != NULL)
05314         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
05315 
05316     while (groupItem != NULL) {
05317         if (part10File && groupItem->group != DCM_GROUPFILEMETA) {
05318             if (opt != fileOptions) {
05319                 opt = fileOptions;
05320                 cond = extractFileOptions(opt, &part10File,
05321                                           &explicitVR, &byteOrder,
05322                                           &encapsulatedPixels);
05323                 if (cond != DCM_NORMAL)
05324                     return cond;
05325             }
05326         }
05327         elementItem = (void *)LST_Head(&groupItem->elementList);
05328         if (elementItem != NULL)
05329             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
05330         if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
05331             U32 l;
05332             l = computeGroupLength(groupItem, explicitVR);
05333             *elementItem->element.d.ul = l;
05334 
05335 /* We have some problems computing group length for groups with sequences.
05336 ** For now, just remove this attribute, except for group 0000 and 0002.
05337 */
05338             if (groupItem->group != 0x0000 && groupItem->group != 0x0002)
05339                 elementItem = (void *)LST_Next(&groupItem->elementList);
05340         }
05341         while (elementItem != NULL) {
05342             if (c <= 20) {
05343                 cond = callback(buffer, bytesExported, 0, ctx);
05344                 if (cond != DCM_NORMAL)
05345                     return COND_PushCondition(DCM_CALLBACKABORTED,
05346                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05347 
05348                 bytesExported = 0;
05349                 c = bufferlength;
05350                 dst = (unsigned char *) buffer;
05351             }
05352             element = elementItem->element;
05353 
05354             if (element.tag == DCM_PXLPIXELDATA) {
05355                 /* Lots of special rules for pixel data. Handle separately */
05356                 /* First, dump the current buffer */
05357                 cond = callback(buffer, bytesExported, 0, ctx);
05358                 if (cond != DCM_NORMAL)
05359                     return COND_PushCondition(DCM_CALLBACKABORTED,
05360                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05361 
05362                 cond = exportPixels(object, elementItem, encapsulatedPixels,
05363                         buffer, bufferlength, callback, ctx, byteOrder, explicitVR);
05364                 if (cond != DCM_NORMAL)
05365                     return cond;
05366 
05367                 bytesExported = 0;
05368                 c = bufferlength;
05369                 dst = (unsigned char *) buffer;
05370                 rtnLength = 0;
05371             } else if (element.representation == DCM_SQ) {
05372                 if (unspecifiedSQLength)
05373                     element.length = DCM_UNSPECIFIEDLENGTH;
05374 
05375                 exportFixedFields(&element, dst, bufferlength, byteOrder,
05376                                   explicitVR, &rtnLength);
05377             } else {
05378                 element.length = elementItem->paddedDataLength;
05379                 exportFixedFields(&element, dst, bufferlength, byteOrder,
05380                                   explicitVR, &rtnLength);
05381             }
05382             dst += rtnLength;
05383             c -= rtnLength;
05384             bytesExported += rtnLength;
05385 
05386             remainingData = element.length;
05387             src = element.d.ot;
05388             elementItem->currentOffset = elementItem->dataOffset;
05389 
05390             if (element.tag == DCM_PXLPIXELDATA) {
05391                 /* Then, we did that above */
05392                 ;
05393             } else if (element.representation == DCM_SQ) {
05394 
05395                 cond = callback(buffer, bytesExported, 0, ctx);
05396                 if (cond != DCM_NORMAL)
05397                     return COND_PushCondition(DCM_CALLBACKABORTED,
05398                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05399 
05400                 bytesExported = 0;
05401                 c = bufferlength;
05402                 dst = (unsigned char *) buffer;
05403 
05404                 if (element.d.sq != NULL) {
05405                     sequenceItem = (void *)LST_Head(&element.d.sq);
05406                     if (sequenceItem != NULL)
05407                         (void) LST_Position(&element.d.sq, (void *)sequenceItem);
05408                     while (sequenceItem != NULL) {
05409                         cond = exportStream(&sequenceItem->object, opt,
05410                                         buffer, bufferlength, callback, ctx,
05411                                             sequenceLevel + 1);
05412                         if (cond != DCM_NORMAL)
05413                             return cond;
05414                         sequenceItem = (void *)LST_Next(&element.d.sq);
05415                     }
05416                 }
05417                 if (element.length == DCM_UNSPECIFIEDLENGTH) {
05418                     sequenceDelimiter.length = 0;
05419                     exportFixedFields(&sequenceDelimiter, dst, bufferlength,
05420                                       byteOrder, explicitVR, &rtnLength);
05421                     dst += rtnLength;
05422                     c -= rtnLength;
05423                     bytesExported += rtnLength;
05424                 }
05425             } else {
05426                 while (remainingData > 0) {
05427                     if (debug)
05428                         fprintf(stderr, "Export: (%08x) %d\n",
05429                                 element.tag, element.length);
05430                     if (element.d.ot != NULL)
05431                         remainingData = element.length -
05432                             (src - ((unsigned char *) element.d.ot));
05433                     else
05434                         remainingData = element.length -
05435                             (elementItem->currentOffset - elementItem->dataOffset);
05436 
05437                     exportLength = (remainingData < c) ? remainingData : c;
05438                     cond = exportData(object, elementItem, src, dst,
05439                                       exportLength, byteOrder, &rtnLength);
05440                     if (cond != DCM_NORMAL)
05441                         return cond;
05442 
05443                     src += rtnLength;
05444                     dst += rtnLength;
05445                     bytesExported += rtnLength;
05446                     c -= rtnLength;
05447 
05448                     if (c <= 20) {
05449                         cond = callback(buffer, bytesExported, 0, ctx);
05450                         if (cond != DCM_NORMAL)
05451                             return COND_PushCondition(DCM_CALLBACKABORTED,
05452                                                       DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05453 
05454                         bytesExported = 0;
05455                         c = bufferlength;
05456                         dst = (unsigned char *) buffer;
05457                     }
05458                 }
05459             }
05460             elementItem = (void *)LST_Next(&groupItem->elementList);
05461         }
05462         groupItem = (void *)LST_Next(&(*object)->groupList);
05463     }
05464     if ((sequenceLevel != 0) && unspecifiedSQLength) {
05465         if (c <= 20) {
05466             cond = callback(buffer, bytesExported, 0, ctx);
05467             if (cond != DCM_NORMAL)
05468                 return COND_PushCondition(DCM_CALLBACKABORTED,
05469                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05470 
05471             bytesExported = 0;
05472             c = bufferlength;
05473             dst = (unsigned char *) buffer;
05474         }
05475         exportFixedFields(&itemDelimiter, dst, bufferlength, byteOrder,
05476                           explicitVR, &rtnLength);
05477         dst += rtnLength;
05478         c -= rtnLength;
05479         bytesExported += rtnLength;
05480     }
05481     lastFlag = (sequenceLevel == 0) ? 1 : 0;
05482     cond = callback(buffer, bytesExported, lastFlag, ctx);
05483     if (cond != DCM_NORMAL)
05484         return COND_PushCondition(DCM_CALLBACKABORTED,
05485                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05486 
05487     return DCM_NORMAL;
05488 }
05489 
05490 /* verifyFormat
05491 **
05492 ** Purpose:
05493 **  This routine verifies the format of the data value of attributes according to
05494 **  the DICOM v3 standard.
05495 **
05496 ** Parameter Dictionary:
05497 **   element    Pointer to the DCM_ELEMENT containing the element to be examined.
05498 **
05499 ** Return Values:
05500 **      DCM_NORMAL
05501 **
05502 ** Algorithm:
05503 **      switch(representation) {
05504 **      case DCM_DA:
05505 **          Retain all characters that are digits, '-', or '\'
05506 **          If the resulting string is of odd length
05507 **              Pad the string with ' '
05508 **          break;
05509 **      case DCM_TM:
05510 **          Retain all characters that are digits, '.', '-', or '\'
05511 **          If the resulting string is of odd length
05512 **              Pad the string with ' '
05513 **          break;
05514 **      case DCM_CS, DCM_AS, DCM_DS, DCM_IS, DCM_LO, DCM_SH, DCM_UT:
05515 **          Delete all the leading and trailing spaces.
05516 **          If the resulting string is of odd length
05517 **              Pad the string with ' '
05518 **          break;
05519 **      case DCM_LT, DCM_ST, DCM_PN:
05520 **          Delete all the trailing spaces.
05521 **          If the resulting string is of odd length
05522 **              Pad the string with ' '
05523 **          break;
05524 **      }
05525 */
05526 
05527 static CONDITION
05528 verifyFormat(PRV_ELEMENT_ITEM * item)
05529 {
05530     int
05531         i,
05532         l;
05533     char
05534        *src,
05535        *dst,
05536        *p;
05537     DCM_ELEMENT
05538         * element;
05539     CTNBOOLEAN
05540         stopFlag = FALSE;
05541 
05542     element = &item->element;
05543     if (element->length > 0) {
05544         switch (element->representation) {
05545         case DCM_DA:
05546             src = dst = element->d.string;
05547             l = (int) element->length;
05548             for (i = 0; i < l; i++) {
05549                 if (isdigit(*src) || (*src == '-') || (*src == '\\')) {
05550                     *dst++ = *src++;
05551                 } else {
05552                     src++;
05553                     element->length--;
05554                 }
05555             }
05556             item->paddedDataLength = element->length;
05557             if (element->length & 1) {
05558                 *dst = ' ';
05559                 item->paddedDataLength++;
05560             }
05561             break;
05562         case DCM_TM:
05563             l = (int) element->length;
05564             src = dst = element->d.string;
05565             for (i = 0; i < l; i++) {
05566                 if (isdigit(*src) || (*src == '.') || (*src == '-') || (*src == '\\')) {
05567                     *dst++ = *src++;
05568                 } else {
05569                     src++;
05570                     element->length--;
05571                 }
05572             }
05573             item->paddedDataLength = element->length;
05574             if (element->length & 1) {
05575                 *dst = ' ';
05576                 item->paddedDataLength++;
05577             }
05578             break;
05579             /*
05580              * Both the leading and trailing spaces are non-significant.
05581              */
05582         case DCM_CS:
05583         case DCM_AS:
05584         case DCM_DS:
05585         case DCM_IS:
05586         case DCM_LO:
05587         case DCM_SH:
05588         case DCM_UT:
05589             l = (int) element->length;
05590             src = dst = element->d.string;
05591             for (i = 0; i < l; i++) {
05592                 if ((*src == ' ') && !stopFlag) {
05593                     src++;
05594                     element->length--;
05595                 } else {
05596                     stopFlag = TRUE;
05597                     *dst++ = *src++;
05598                 }
05599             }
05600             /*
05601              * Right now, dst points to the char follows the last char in the
05602              * string.
05603              */
05604             stopFlag = FALSE;
05605             l = (int) element->length;
05606             p = dst - 1;
05607             for (i = l; (i > 0) && !stopFlag; i--) {
05608                 if ((*p == ' ') && !stopFlag) {
05609                     p--;
05610                     dst--;
05611                     element->length--;
05612                 } else
05613                     stopFlag = TRUE;
05614             }
05615             item->paddedDataLength = element->length;
05616             if (element->length & 1) {
05617                 *dst = ' ';
05618                 item->paddedDataLength++;
05619             }
05620             break;
05621             /*
05622              * The trailing spaces are non-significant.
05623              */
05624         case DCM_LT:
05625         case DCM_ST:
05626             l = (int) element->length;
05627             src = element->d.string + l - 1;
05628             for (i = l; (i > 0) && !stopFlag; i--) {
05629                 if ((*src == ' ') && !stopFlag) {
05630                     src--;
05631                     element->length--;
05632                 } else
05633                     stopFlag = TRUE;
05634             }
05635             item->paddedDataLength = element->length;
05636             if (element->length & 1) {
05637                 *++src = ' ';
05638                 item->paddedDataLength++;
05639             }
05640             break;
05641         case DCM_PN:
05642             /*
05643              * Strip off the trailing spaces.
05644              */
05645             l = (int) element->length;
05646             src = element->d.string + l - 1;
05647             for (i = l; (i > 0) && !stopFlag; i--) {
05648                 if ((*src == ' ') && !stopFlag) {
05649                     src--;
05650                     element->length--;
05651                 } else
05652                     stopFlag = TRUE;
05653             }
05654             /*
05655              * Convert the name to the standard V3 format.
05656              */
05657             src = dst = element->d.string;
05658             l = element->length;
05659             for (i = 0; i < l;) {
05660                 if ((src[i] == ',') || (src[i] == '^')) {
05661                     *dst++ = '^';
05662                     i++;
05663                     while ((i < l) && (src[i] == ' ')) {
05664                         element->length--;
05665                         i++;
05666                     }
05667                 } else {
05668                     *dst++ = src[i++];
05669                 }
05670             }
05671 
05672             item->paddedDataLength = element->length;
05673             if (element->length & 1) {
05674                 *dst = ' ';
05675                 item->paddedDataLength++;
05676             }
05677             break;
05678         case DCM_UI:
05679             if (element->d.string[element->length - 1] == '\0')
05680                 element->length--;
05681             if (element->d.string[element->length - 1] == ' ') {
05682                 element->d.string[element->length - 1] = '\0';
05683                 element->length--;
05684             }
05685             break;
05686         default:
05687             break;
05688         }
05689     }
05690     return DCM_NORMAL;
05691 }
05692 
05693 /* readFile
05694 **
05695 ** Purpose:
05696 **      Read DICOM object from a file
05697 **
05698 ** Parameter Dictionary:
05699 **      name                    Name of the file
05700 **      callerBuf               Buffer from which to read the object
05701 **      fd                      File descriptor
05702 **      size                    Size of the file
05703 **      fileOffset              Offset in the file from which point read starts
05704 **      recursionLevel          Level of recursion
05705 **      opt                     Indicates in what byte order to read
05706 **      callerObject            The object into which the contents are stored
05707 **      scannedLength           Length of data scanned
05708 **      remainOpenFlag          Indicates whether the file remains open
05709 **
05710 ** Return Values:
05711 **
05712 **      DCM_ELEMENTCREATEFAILED
05713 **      DCM_ELEMENTLENGTHERROR
05714 **      DCM_ELEMENTOUTOFORDER
05715 **      DCM_FILEACCESSERROR
05716 **      DCM_ILLEGALSTREAMLENGTH
05717 **      DCM_LISTFAILURE
05718 **      DCM_NORMAL
05719 **      DCM_OBJECTCREATEFAILED
05720 **      DCM_UNEVENELEMENTLENGTH
05721 **
05722 ** Notes:
05723 **
05724 ** Algorithm:
05725 **      Description of the algorithm (optional) and any other notes.
05726 */
05727 static CONDITION
05728 readFile(char *name, unsigned char *callerBuf, int fd, long size,
05729          off_t fileOffset, int recursionLevel,
05730          unsigned long opt, DCM_OBJECT ** callerObject,
05731          U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
05732          void *ctx,
05733          CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
05734          CONDITION(*sk) (void *ctx, int offset, int flag))
05735 {
05736     CONDITION
05737     cond;
05738     int
05739         byteOrder;
05740     long
05741         lastGroup = -1,
05742         lastElement = -1;
05743     U32
05744         sequenceLength,
05745         localLength;
05746     PRIVATE_OBJECT
05747         ** object;
05748     PRV_GROUP_ITEM
05749         * groupItem = NULL;
05750     unsigned short
05751         group,
05752         element,
05753         tagGroup,
05754         tagElement;
05755     DCM_ELEMENT
05756         e,
05757         tagE;
05758     CTNBOOLEAN
05759         pixelFlag,
05760         convertFlag = FALSE,
05761         done = FALSE,
05762         knownLength = TRUE,
05763         sequenceDone = FALSE,
05764         createGroupFlag,
05765         explicitVR = FALSE;
05766     unsigned char
05767         buf[8],
05768        *ptr;
05769     int
05770         nBytes;
05771     PRV_ELEMENT_ITEM
05772         * elementItem = NULL;
05773     DCM_OBJECT
05774         * sequenceObject;
05775     DCM_SEQUENCE_ITEM
05776         * sequenceItem;
05777     CTNBOOLEAN
05778         fileFlag = TRUE;
05779 
05780     if (callerBuf != NULL) {
05781         ptr = callerBuf;
05782         fileFlag = FALSE;
05783     } else
05784         ptr = buf;
05785 
05786     switch (opt & DCM_ORDERMASK) {
05787     case DCM_ORDERNATIVE:
05788         byteOrder = NATIVE_ORDER;
05789         break;
05790     case DCM_ORDERLITTLEENDIAN:
05791         byteOrder = LITTLE_ORDER;
05792         break;
05793     case DCM_EXPLICITLITTLEENDIAN:
05794         byteOrder = LITTLE_ORDER;
05795         explicitVR = TRUE;
05796         break;
05797     case DCM_ORDERBIGENDIAN:
05798         byteOrder = BIG_ORDER;
05799         break;
05800     case DCM_EXPLICITBIGENDIAN:
05801         byteOrder = BIG_ORDER;
05802         explicitVR = TRUE;
05803         break;
05804     default:
05805         byteOrder = NATIVE_ORDER;
05806         break;
05807     }
05808     if ((opt & DCM_CONVERTMASK) == DCM_FORMATCONVERSION)
05809         convertFlag = TRUE;
05810 
05811     if (scannedLength != NULL)
05812         *scannedLength = 0;
05813 
05814     cond = DCM_CreateObject(callerObject, opt);
05815     if (cond != DCM_NORMAL)
05816         return cond;
05817 
05818     object = (PRIVATE_OBJECT **) callerObject;
05819     if (fileFlag)
05820         strcpy((*object)->fileName, name);
05821 
05822     (*object)->fd = -1;
05823     (*object)->rd = rd;
05824     (*object)->sk = sk;
05825     (*object)->userCtx = ctx;
05826     if (size == (long) DCM_UNSPECIFIEDLENGTH)
05827         knownLength = FALSE;
05828 
05829     if ((fileFlag) && ((opt & DCM_DELETEMASK) == DCM_DELETEONCLOSE) && (recursionLevel == 0))
05830         (*object)->deleteFlag = TRUE;
05831 
05832     if (knownLength && (size == 0))
05833         done = TRUE;
05834 
05835     while (!done) {
05836 
05837         if ((size < 8) && knownLength) {
05838             if (debug)
05839                 (void) DCM_DumpElements(callerObject, 0);
05840             (void) DCM_CloseObject(callerObject);
05841             return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
05842                                  DCM_Message(DCM_ILLEGALSTREAMLENGTH), size,
05843                                       "readFile");
05844         }
05845         if (fileFlag) {
05846             if (fd != -1) {
05847                 nBytes = read(fd, buf, 4);
05848             } else {
05849                 cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
05850             }
05851 
05852             if (nBytes != 4)
05853                 return COND_PushCondition(DCM_FILEACCESSERROR,
05854                                      DCM_Message(DCM_FILEACCESSERROR), name,
05855                                           "readFile");
05856             ptr = buf;
05857         }
05858         if (knownLength)
05859             size -= 4;
05860         fileOffset += (off_t) 4;
05861         if (scannedLength != NULL)
05862             (*scannedLength) += 4;
05863         (*object)->objectSize += 4;
05864 
05865         if (byteOrder == BYTEORDER_SAME) {
05866             GET_SHORT_SAME_ORDER(ptr, group);
05867             GET_SHORT_SAME_ORDER(ptr + 2, element);
05868             e.tag = DCM_MAKETAG(group, element);
05869         } else {
05870             GET_SHORT_REVERSE_ORDER(ptr, group);
05871             GET_SHORT_REVERSE_ORDER(ptr + 2, element);
05872             e.tag = DCM_MAKETAG(group, element);
05873         }
05874         ptr += 4;
05875 
05876         if (explicitVR) {
05877             if (fileFlag) {
05878                 if (fd != -1) {
05879                     nBytes = read(fd, buf, 4);
05880                 } else {
05881                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
05882                 }
05883 
05884                 if (nBytes != 4)
05885                     return COND_PushCondition(DCM_FILEACCESSERROR,
05886                                      DCM_Message(DCM_FILEACCESSERROR), name,
05887                                               "readFile");
05888                 ptr = buf;
05889             }
05890             if (knownLength)
05891                 size -= 4;
05892             fileOffset += (off_t) 4;
05893             if (scannedLength != NULL)
05894                 (*scannedLength) += 4;
05895             (*object)->objectSize += 4;
05896             if ((strncmp((char *) ptr, "OB", 2) == 0) ||
05897                 (strncmp((char *) ptr, "OW", 2) == 0) ||
05898                 (strncmp((char *) ptr, "SQ", 2) == 0)) {
05899             } else {
05900             }
05901         } else {
05902 
05903             if (fileFlag) {
05904                 if (fd != -1) {
05905                     nBytes = read(fd, buf, 4);
05906                 } else {
05907                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
05908                 }
05909 
05910                 if (nBytes != 4)
05911                     return COND_PushCondition(DCM_FILEACCESSERROR,
05912                                      DCM_Message(DCM_FILEACCESSERROR), name,
05913                                               "readFile");
05914                 ptr = buf;
05915             }
05916             if (knownLength)
05917                 size -= 4;
05918             fileOffset += (off_t) 4;
05919             if (scannedLength != NULL)
05920                 (*scannedLength) += 4;
05921             (*object)->objectSize += 4;
05922 
05923 
05924             if (byteOrder == BYTEORDER_SAME) {
05925                 GET_LONG_SAME_ORDER(ptr, e.length);
05926             } else {
05927                 GET_LONG_REVERSE_ORDER(ptr, e.length);
05928             }
05929             ptr += 4;
05930         }
05931 
05932         if (((e.length & 1) != 0) && (e.length != DCM_UNSPECIFIEDLENGTH)) {
05933             if (debug)
05934                 (void) DCM_DumpElements(callerObject, 0);
05935             (void) DCM_CloseObject(callerObject);
05936             return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
05937                                       DCM_Message(DCM_UNEVENELEMENTLENGTH),
05938                                       group, element, e.length,
05939                                       "readFile");
05940         }
05941         if ((e.length != (U32) DCM_UNSPECIFIEDLENGTH) && (e.length > (U32) size)) {
05942             if (debug)
05943                 (void) DCM_DumpElements(callerObject, 0);
05944             (void) DCM_CloseObject(callerObject);
05945             return COND_PushCondition(DCM_ELEMENTLENGTHERROR,
05946                                       DCM_Message(DCM_ELEMENTLENGTHERROR),
05947                                 group, element, e.length, size, "readFile");
05948         }
05949         if ((e.tag == DCM_DLMITEMDELIMITATIONITEM) ||
05950             (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)) {
05951             return DCM_NORMAL;
05952         }
05953         cond = DCM_LookupElement(&e);
05954         if (cond != DCM_NORMAL)
05955             (void) COND_PopCondition(0);
05956         if (e.representation == DCM_CTX)
05957             ctxSensitiveLookup(object, &e);
05958 
05959         if (e.representation == DCM_SQ) {
05960             cond = newElementItem(&e, FALSE, &elementItem);
05961             if (cond != DCM_NORMAL)
05962                 return cond;
05963             elementItem->element.d.sq = LST_Create();
05964             if (elementItem->element.d.sq == NULL)
05965                 return COND_PushCondition(DCM_LISTFAILURE,
05966                                   DCM_Message(DCM_LISTFAILURE), "readFile");
05967 
05968             localLength = elementItem->element.length;
05969             sequenceDone = (localLength == 0);
05970 
05971             while (!sequenceDone) {
05972                 if (debug)
05973                     fprintf(stderr, "Sequence Length: %d %x\n", localLength,
05974                             localLength);
05975                 if (fileFlag) {
05976                     if (fd != -1) {
05977                         nBytes = read(fd, buf, 8);
05978                     } else {
05979                         cond = (*object)->rd((*object)->userCtx, buf, 8, &nBytes);
05980                     }
05981                     if (nBytes != 8)
05982                         return COND_PushCondition(DCM_FILEACCESSERROR,
05983                                      DCM_Message(DCM_FILEACCESSERROR), name,
05984                                                   "readFile");
05985                     ptr = buf;
05986                 }
05987                 if (size != (long) DCM_UNSPECIFIEDLENGTH)
05988                     size -= 8;
05989                 fileOffset += (off_t) 8;
05990                 if (scannedLength != NULL)
05991                     (*scannedLength) += 8;
05992                 (*object)->objectSize += 8;
05993                 if (localLength != DCM_UNSPECIFIEDLENGTH)
05994                     localLength -= 8;
05995 
05996                 if (byteOrder == BYTEORDER_SAME) {
05997                     GET_SHORT_SAME_ORDER(ptr, tagGroup);
05998                     GET_SHORT_SAME_ORDER(ptr + 2, tagElement);
05999                     tagE.tag = DCM_MAKETAG(tagGroup, tagElement);
06000                     GET_LONG_SAME_ORDER(ptr + 4, tagE.length);
06001                 } else {
06002                     GET_SHORT_REVERSE_ORDER(ptr, tagGroup);
06003                     GET_SHORT_REVERSE_ORDER(ptr + 2, tagElement);
06004                     tagE.tag = DCM_MAKETAG(tagGroup, tagElement);
06005                     GET_LONG_REVERSE_ORDER(ptr + 4, tagE.length);
06006                 }
06007                 ptr += 8;
06008                 if (debug)
06009                     fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
06010                             tagGroup, tagElement, tagE.length, tagE.length);
06011                 if (tagE.tag == DCM_DLMITEM) {
06012 /*                  if (size != DCM_UNSPECIFIEDLENGTH)
06013                         size -= 8;
06014 */
06015 /*                  fileOffset += 8;
06016 */
06017                     cond = readFile(name,
06018                                     (fileFlag) ? NULL : ptr,
06019                                     fd, tagE.length,
06020                                     fileOffset, recursionLevel + 1, opt,
06021                                     &sequenceObject, &sequenceLength,
06022                                     remainOpenFlag, ctx, rd, sk);
06023                     if (cond == DCM_NORMAL) {
06024                         sequenceItem = CTN_MALLOC(sizeof(*sequenceItem));
06025                         if (sequenceItem == NULL)
06026                             return COND_PushCondition(DCM_MALLOCFAILURE,
06027                                              DCM_Message(DCM_MALLOCFAILURE),
06028                                          sizeof(*sequenceItem), "readFile");
06029 
06030                         sequenceItem->object = sequenceObject;
06031                         cond = LST_Enqueue(&elementItem->element.d.sq,
06032                                            (void *)sequenceItem);
06033                         if (cond != LST_NORMAL)
06034                             return COND_PushCondition(DCM_LISTFAILURE,
06035                                   DCM_Message(DCM_LISTFAILURE), "readFile");
06036                         if (size != (long) DCM_UNSPECIFIEDLENGTH)
06037                             size -= sequenceLength;
06038                         fileOffset += (off_t) sequenceLength;
06039                         if (scannedLength != NULL)
06040                             *scannedLength += sequenceLength;
06041                         (*object)->objectSize += sequenceLength;
06042                         if (localLength != DCM_UNSPECIFIEDLENGTH)
06043                             localLength -= sequenceLength;
06044                         ptr += sequenceLength;
06045                     } else
06046                         return cond;
06047                 } else {
06048                     sequenceDone = TRUE;
06049                 }
06050                 if (localLength == 0)
06051                     sequenceDone = TRUE;
06052             }
06053         } else {
06054             pixelFlag = (e.tag == DCM_PXLPIXELDATA);
06055             cond = newElementItem(&e, (pixelFlag == FALSE), &elementItem);
06056             if (cond != DCM_NORMAL) {
06057                 (void) DCM_CloseObject(callerObject);
06058                 return cond;
06059             }
06060             if (pixelFlag) {
06061                 if (fileFlag)
06062                     *remainOpenFlag = TRUE;
06063                 elementItem->byteOrder = byteOrder;
06064                 elementItem->dataOffset = fileOffset;
06065                 elementItem->currentOffset = 0;
06066                 if (fileFlag)
06067                     elementItem->element.d.ot = NULL;
06068                 else
06069                     elementItem->element.d.ot = (void *) ptr;
06070                 if ((*object)->pixelBitsAllocated == 8)
06071                     elementItem->element.representation = DCM_OB;
06072                 else
06073                     elementItem->element.representation = DCM_OW;
06074                 if (fileFlag) {
06075                     if (fd != -1) {
06076                         (void) lseek(fd, (off_t) elementItem->element.length, SEEK_CUR);
06077                     } else {
06078                         (*object)->sk((*object)->userCtx,
06079                                       elementItem->element.length, SEEK_CUR);
06080                     }
06081                     (*object)->fd = fd;
06082                 }
06083             } else {
06084                 if (fileFlag) {
06085                     if (fd != -1) {
06086                         nBytes = read(fd, elementItem->element.d.ot,
06087                                       (int) elementItem->element.length);
06088                     } else {
06089                         cond = (*object)->rd((*object)->userCtx,
06090                                              elementItem->element.d.ot,
06091                                (long) elementItem->element.length, &nBytes);
06092                     }
06093                     if (nBytes != (int) elementItem->element.length) {
06094                         (void) DCM_CloseObject(callerObject);
06095                         return COND_PushCondition(DCM_FILEACCESSERROR,
06096                         DCM_Message(DCM_FILEACCESSERROR), name, "readFile");
06097                     }
06098                 } else {
06099                     (void) memcpy(elementItem->element.d.ot, ptr,
06100                                   elementItem->element.length);
06101                     ptr += elementItem->originalDataLength;
06102                 }
06103 
06104                 if( LITTLE_ENDIAN_ARCHITECTURE ){
06105                   if (elementItem->element.representation == DCM_AT)
06106                     swapATGroupElement(&elementItem->element);
06107                 }
06108                 if (byteOrder != BYTEORDER_SAME)
06109                     swapInPlace(object, &elementItem->element);
06110                 if (convertFlag) {
06111                     cond = verifyFormat(elementItem);
06112                     if (cond != DCM_NORMAL)
06113                         return cond;
06114                 }
06115             }
06116             if (size != (long) DCM_UNSPECIFIEDLENGTH)
06117                 size -= elementItem->originalDataLength;
06118             fileOffset += (off_t) elementItem->originalDataLength;
06119             if (scannedLength != NULL)
06120                 (*scannedLength) += elementItem->originalDataLength;
06121 
06122             elementItem->paddedDataLength = elementItem->element.length;
06123             if (elementItem->paddedDataLength & 1)
06124                 elementItem->paddedDataLength += 1;
06125             (*object)->objectSize += elementItem->paddedDataLength;
06126         }
06127 
06128         computeVM(object, &elementItem->element);
06129 
06130         if ((long) DCM_TAG_GROUP(e.tag) == lastGroup) {
06131             if ((long) DCM_TAG_ELEMENT(e.tag) <= lastElement)
06132                 return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06133                                           DCM_Message(DCM_ELEMENTOUTOFORDER),
06134                                           group, element, "readFile");
06135         } else if ((long) DCM_TAG_GROUP(e.tag) > lastGroup) {
06136         } else {
06137             return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06138                          DCM_Message(DCM_ELEMENTOUTOFORDER), group, element,
06139                                       "readFile");
06140         }
06141         lastGroup = (long) group;
06142         lastElement = (long) element;
06143 
06144         if (groupItem == NULL)
06145             createGroupFlag = TRUE;
06146         else if (groupItem->group != group)
06147             createGroupFlag = TRUE;
06148         else
06149             createGroupFlag = FALSE;
06150 
06151         if (createGroupFlag == TRUE) {
06152             groupItem = CTN_MALLOC(sizeof(*groupItem));
06153             if (groupItem == NULL) {
06154                 (void) DCM_CloseObject(callerObject);
06155                 return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
06156                                        DCM_Message(DCM_ELEMENTCREATEFAILED),
06157                                           "readFile",
06158                                           group, 0xffff, sizeof(*groupItem));
06159             }
06160             groupItem->group = group;
06161             groupItem->baseLength = 0;
06162             groupItem->longVRAttributes = 0;
06163             groupItem->elementList = LST_Create();
06164             if (groupItem->elementList == NULL) {
06165                 (void) DCM_CloseObject(callerObject);
06166                 return COND_PushCondition(DCM_LISTFAILURE,
06167                                           DCM_Message(DCM_LISTFAILURE),
06168                                           "readFile");
06169             }
06170             if (LST_Enqueue(&(*object)->groupList, (void *)groupItem) != LST_NORMAL) {
06171                 (void) DCM_CloseObject(callerObject);
06172                 return COND_PushCondition(DCM_LISTFAILURE,
06173                                           DCM_Message(DCM_LISTFAILURE),
06174                                           "readFile");
06175             }
06176         }
06177         if (element != 0x0000)
06178             groupItem->baseLength += 8 + elementItem->paddedDataLength;
06179         if ((element == 0x0000) && ((*object)->groupLengthFlag == FALSE)) {
06180             CTN_FREE(elementItem);
06181         } else {
06182             cond = LST_Enqueue(&groupItem->elementList, (void *)elementItem);
06183             if (cond != LST_NORMAL) {
06184                 (void) DCM_CloseObject(callerObject);
06185                 return COND_PushCondition(DCM_LISTFAILURE,
06186                                           DCM_Message(DCM_LISTFAILURE),
06187                                           "readFile");
06188             }
06189             cond = updateObjectType(object, &elementItem->element);     /* repair */
06190 
06191             cond = updateSpecialElements(object, elementItem);  /* repair */
06192         }
06193 
06194         if (size == 0)
06195             done = TRUE;
06196 
06197 #ifdef DEBUG
06198         if (debug) {
06199 /*lint -e644 */
06200             (void) fprintf(stderr, "Address: %px Group %2x, element %2x, length %ld ",
06201                            elementItem,
06202                            DCM_TAG_GROUP(elementItem->element.tag),
06203                            DCM_TAG_ELEMENT(elementItem->element.tag),
06204                            elementItem->element.length);
06205 /*lint +e644 */
06206             (void) fprintf(stderr, "Object size: %d\n", (*object)->objectSize);
06207         }
06208 #endif
06209     }
06210 
06211     groupItem = (void *)LST_Head(&(*object)->groupList);
06212     if (groupItem != NULL) {
06213         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
06214         while (groupItem != NULL) {
06215             elementItem = (void *)LST_Head(&groupItem->elementList);
06216             if (elementItem != NULL) {
06217                 if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
06218                     *elementItem->element.d.ul = groupItem->baseLength;
06219                 }
06220             }
06221             groupItem = (void *)LST_Next(&(*object)->groupList);
06222         }
06223     }
06224     return DCM_NORMAL;
06225 }
06226 
06227 static CONDITION
06228 readPreamble(const char *name, unsigned char **ptr, int fd, U32 * size,
06229              off_t * fileOffset, CTNBOOLEAN knownLength,
06230              PRIVATE_OBJECT ** object, U32 * scannedLength)
06231 {
06232     int nBytes,
06233         tmp;
06234     CONDITION cond;
06235     char label[4];
06236 
06237     if (*size == 0)
06238         return DCM_STREAMCOMPLETE;
06239 
06240     if ((*size < DCM_PREAMBLELENGTH + 4) && knownLength) {
06241         if (debug)
06242             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06243         (void) DCM_CloseObject((DCM_OBJECT **) object);
06244         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06245                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06246                                   "readPreamble");
06247     }
06248     if (*ptr == NULL) {
06249         if (fd != -1) {
06250             nBytes = read(fd, (*object)->preamble, DCM_PREAMBLELENGTH);
06251             nBytes += read(fd, label, sizeof(label));
06252         } else {
06253             cond = (*object)->rd((*object)->userCtx, (*object)->preamble,
06254                                  DCM_PREAMBLELENGTH, &nBytes);
06255             cond = (*object)->rd((*object)->userCtx, label,
06256                                  sizeof(label), &tmp);
06257             nBytes += tmp;
06258         }
06259 
06260         if (nBytes != DCM_PREAMBLELENGTH + sizeof(label))
06261             return COND_PushCondition(DCM_FILEACCESSERROR,
06262                                       DCM_Message(DCM_FILEACCESSERROR), name,
06263                                       "readPreamble");
06264     } else {
06265         (void) memcpy((*object)->preamble, *ptr, DCM_PREAMBLELENGTH);
06266         (void) memcpy(label, (*ptr) + DCM_PREAMBLELENGTH, sizeof(label));
06267     }
06268 
06269     if (knownLength)
06270         *size -= DCM_PREAMBLELENGTH + sizeof(label);
06271     *fileOffset += (off_t) DCM_PREAMBLELENGTH + sizeof(label);
06272     if (*ptr != NULL)
06273         *ptr += DCM_PREAMBLELENGTH + sizeof(label);
06274     (*object)->objectSize += DCM_PREAMBLELENGTH + sizeof(label);
06275 
06276     if (strncmp(label, "DICM", 4) != 0)
06277         return 0;
06278 
06279     (*object)->preambleFlag = TRUE;
06280     return DCM_NORMAL;
06281 }
06282 
06283 
06284 static CONDITION
06285 readGroupElement(const char *name, unsigned char **ptr, int fd, U32 * size,
06286                  off_t * fileOffset, CTNBOOLEAN knownLength, int byteOrder,
06287                  CTNBOOLEAN explicitVR, CTNBOOLEAN acceptVRMismatch,
06288                  PRIVATE_OBJECT ** object, U32 * scannedLength,
06289                  DCM_ELEMENT * e)
06290 {
06291     unsigned char *localPtr;
06292     unsigned char buf[4];
06293     int nBytes;
06294     CONDITION cond;
06295     unsigned short group,
06296         element;
06297 
06298     if (*size == 0)
06299         return DCM_STREAMCOMPLETE;
06300 
06301     if ((*size < 4) && knownLength) {
06302         if (debug)
06303             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06304         (void) DCM_CloseObject((DCM_OBJECT **) object);
06305         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06306                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06307                                   "readFile");
06308     }
06309     if (*ptr == NULL) {
06310         if (fd != -1) {
06311             nBytes = read(fd, buf, 4);
06312         } else {
06313             cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
06314         }
06315 
06316         if (nBytes != 4)
06317             return COND_PushCondition(DCM_FILEACCESSERROR,
06318                                       DCM_Message(DCM_FILEACCESSERROR), name,
06319                                       "readGroupElement");
06320         localPtr = buf;
06321     } else {
06322         localPtr = *ptr;
06323     }
06324 
06325     if (knownLength)
06326         *size -= 4;
06327     *fileOffset += (off_t) 4;
06328     if (scannedLength != NULL)
06329         (*scannedLength) += 4;
06330     (*object)->objectSize += 4;
06331 
06332     if (byteOrder == BYTEORDER_SAME) {
06333         GET_SHORT_SAME_ORDER(localPtr, group);
06334         GET_SHORT_SAME_ORDER(localPtr + 2, element);
06335         e->tag = DCM_MAKETAG(group, element);
06336     } else {
06337         GET_SHORT_REVERSE_ORDER(localPtr, group);
06338         GET_SHORT_REVERSE_ORDER(localPtr + 2, element);
06339         e->tag = DCM_MAKETAG(group, element);
06340     }
06341     if (*ptr != NULL)
06342         *ptr += 4;
06343 
06344     if (debug)
06345         fprintf(stderr, "%04x %04x ", group, element);
06346 
06347     cond = DCM_LookupElement(e);
06348     if (cond != DCM_NORMAL)
06349         (void) COND_PopCondition(0);
06350     if (e->representation == DCM_CTX)
06351         ctxSensitiveLookup(object, e);
06352 
06353     return DCM_NORMAL;
06354 }
06355 
06356 static CONDITION
06357 readVRLength(const char *name, unsigned char **ptr, int fd, U32 * size,
06358              off_t * fileOffset,
06359              CTNBOOLEAN knownLength, int byteOrder, CTNBOOLEAN explicitVR,
06360              CTNBOOLEAN acceptVRMismatch,
06361              PRIVATE_OBJECT ** object, U32 * scannedLength, DCM_ELEMENT * e)
06362 {
06363     unsigned char *localPtr;
06364     unsigned char buf[4];
06365     char vrCode[3];
06366     VRMAP *vrPtr;
06367     int nBytes;
06368     CONDITION cond;
06369     CTNBOOLEAN calculatedLength = FALSE;
06370 
06371 ENTRY("readVRLength") ;
06372 
06373     if (*size == 0)
06374         RETURN( DCM_STREAMCOMPLETE );
06375 
06376     if ((*size < 4) && knownLength) {
06377         if (debug)
06378             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06379         (void) DCM_CloseObject((DCM_OBJECT **) object);
06380         RETURN( COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06381                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06382                                   "readVRLength") );
06383     }
06384     if (*ptr == NULL) {
06385         if (fd != -1) {
06386             nBytes = read(fd, buf, 4);
06387         } else {
06388             cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
06389         }
06390 
06391         if (nBytes != 4)
06392             RETURN( COND_PushCondition(DCM_FILEACCESSERROR,
06393                                       DCM_Message(DCM_FILEACCESSERROR), name,
06394                                       "readVRLength") ) ;
06395         localPtr = buf;
06396     } else
06397         localPtr = *ptr;
06398 
06399     if (knownLength)
06400         *size -= 4;
06401     *fileOffset += (off_t) 4;
06402     if (scannedLength != NULL)
06403         (*scannedLength) += 4;
06404     (*object)->objectSize += 4;
06405 
06406     e->length = 0;
06407     if (e->representation == DCM_DLM) {
06408         explicitVR = FALSE;     /* Special rule for delimitors */
06409     }
06410     if (explicitVR) {
06411         vrCode[0] = buf[0];
06412         vrCode[1] = buf[1];
06413         vrCode[2] = '\0';
06414         vrPtr = lookupVRCode(vrCode);
06415         if (vrPtr == NULL){
06416             if( rwc_err ){
06417              fprintf(stderr,"** DICOM ERROR: unknown VR code %s in element (%04x,%04x)\n",  /* RWC */
06418                      vrCode,DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06419             }
06420             RETURN( COND_PushCondition(DCM_UNRECOGNIZEDVRCODE,
06421                                 DCM_Message(DCM_UNRECOGNIZEDVRCODE), vrCode,
06422                                       "readVRLength") );
06423         }
06424 
06425         if (vrPtr->representation != e->representation) {
06426             if (vrPtr->representation == DCM_OB) {
06427                 /* This is probably from the waveform supplement where they */
06428                 /* transmit as OB and expect us to pull it out later */
06429                 /* We will just keep our VR which was based on context in */
06430                 /* the object */
06431                 e->representation = vrPtr->representation;
06432             } else if (e->representation == DCM_UN ||
06433                        e->representation == DCM_CTX ||
06434                        e->representation == DCM_RET ||
06435                        vrPtr->representation == DCM_OW ||
06436                        acceptVRMismatch) {      /* Believe input */
06437                 e->representation = vrPtr->representation;
06438             } else {
06439 #if 0
06440                 if (e->tag != DCM_PXLPIXELDATA){
06441                     STATUS("VR mismatch") ;
06442                     RETURN( COND_PushCondition(DCM_VRMISMATCH,
06443                                DCM_Message(DCM_VRMISMATCH), vrCode, e->tag));
06444                 }
06445 #else
06446                if( rwc_err ){
06447                 fprintf(stderr,"++ DICOM WARNING: VR mismatch in element (%04x,%04x)\n",  /* RWC */
06448                         DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06449                }
06450                e->representation = vrPtr->representation;
06451 #endif
06452             }
06453         }
06454         if (vrPtr->representation != DCM_OW &&
06455             vrPtr->representation != DCM_OB &&
06456             vrPtr->representation != DCM_UN &&
06457             vrPtr->representation != DCM_UT &&
06458             vrPtr->representation != DCM_SQ) {
06459             unsigned short shortLength;
06460             if (byteOrder == BYTEORDER_SAME) {
06461                 GET_SHORT_SAME_ORDER(localPtr + 2, shortLength);
06462             } else {
06463                 GET_SHORT_REVERSE_ORDER(localPtr + 2, shortLength);
06464             }
06465             e->length = shortLength;
06466             if (*ptr != NULL)
06467                 *ptr += 4;
06468             calculatedLength = TRUE;
06469         } else {
06470             if ((*size < 4) && knownLength) {
06471                 if (debug)
06472                     (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06473                 (void) DCM_CloseObject((DCM_OBJECT **) object);
06474                 RETURN( COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06475                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06476                                           "readVRLength"));
06477             }
06478             if (*ptr == NULL) {
06479                 if (fd != -1) {
06480                     nBytes = read(fd, buf, 4);
06481                 } else {
06482                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
06483                 }
06484 
06485                 if (nBytes != 4)
06486                     RETURN( COND_PushCondition(DCM_FILEACCESSERROR,
06487                                      DCM_Message(DCM_FILEACCESSERROR), name,
06488                                               "readVRLength"));
06489                 localPtr = buf;
06490             } else
06491                 localPtr = *ptr;
06492 
06493             if (knownLength)
06494                 *size -= 4;
06495             *fileOffset += (off_t) 4;
06496             if (scannedLength != NULL)
06497                 (*scannedLength) += 4;
06498             (*object)->objectSize += 4;
06499         }
06500     }
06501     if (!calculatedLength) {
06502         if (byteOrder == BYTEORDER_SAME) {
06503             GET_LONG_SAME_ORDER(localPtr, e->length);
06504         } else {
06505             GET_LONG_REVERSE_ORDER(localPtr, e->length);
06506         }
06507         if (*ptr != NULL)
06508             *ptr += 4;
06509     }
06510     if (debug) {
06511         char localVR[10];
06512         mapVRtoASCII(e->representation, localVR);
06513         fprintf(stderr, "%2s %6d %06x %s\n", localVR, e->length,
06514                 (unsigned int)*fileOffset, e->description);
06515     }
06516     if (((e->length & 1) != 0) && (e->length != DCM_UNSPECIFIEDLENGTH)) {
06517         if (debug)
06518             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06519         (void) DCM_CloseObject((DCM_OBJECT **) object);
06520         if( rwc_err ){
06521          fprintf(stderr,"** DICOM ERROR: illegal odd length=%d in element (%04x,%04x)\n",  /* RWC */
06522                  e->length,DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06523         }
06524         RETURN( COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
06525                                   DCM_Message(DCM_UNEVENELEMENTLENGTH),
06526                              DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag),
06527                                   e->length, "readFile"));
06528     }
06529     if ((e->length != (U32) DCM_UNSPECIFIEDLENGTH) && (e->length > (U32) (*size))) {
06530         if (debug)
06531             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06532         (void) DCM_CloseObject((DCM_OBJECT **) object);
06533         if( rwc_err ){
06534          fprintf(stderr,"** DICOM ERROR: oversize length=%d in element (%04x,%04x)\n",  /* RWC */
06535                  e->length,DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06536         }
06537         RETURN( COND_PushCondition(DCM_ELEMENTLENGTHERROR,
06538                                   DCM_Message(DCM_ELEMENTLENGTHERROR),
06539                              DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag),
06540                                   e->length, *size, "readFile"));
06541     }
06542     RETURN( DCM_NORMAL);
06543 }
06544 
06545 static CONDITION
06546 readSequence(const char *name, unsigned char **ptr, int fd, U32 * size,
06547              off_t * fileOffset, int recursionLevel, unsigned long opt,
06548           int byteOrder, CTNBOOLEAN explicitVR, CTNBOOLEAN acceptVRMismatch,
06549              CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
06550              CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
06551              U32 * scannedLength, DCM_ELEMENT * e,
06552              PRV_ELEMENT_ITEM ** elementItem)
06553 {
06554     CTNBOOLEAN knownLength = TRUE;
06555     CONDITION cond;
06556     U32 sequenceLength;
06557 
06558     U32 localLength;
06559     CTNBOOLEAN sequenceDone;
06560     DCM_ELEMENT tagE;
06561     DCM_OBJECT
06562         * sequenceObject;
06563     DCM_SEQUENCE_ITEM *sequenceItem;
06564     CONDITION flag;
06565     unsigned char *localPtr;
06566     off_t itemTagOffset;
06567 
06568     if (*size == (long) DCM_UNSPECIFIEDLENGTH)
06569         knownLength = FALSE;
06570 
06571     cond = newElementItem(e, FALSE, elementItem);
06572     if (cond != DCM_NORMAL)
06573         return cond;
06574     (*elementItem)->element.d.sq = LST_Create();
06575     if ((*elementItem)->element.d.sq == NULL)
06576         return COND_PushCondition(DCM_LISTFAILURE,
06577                               DCM_Message(DCM_LISTFAILURE), "readSequence");
06578 
06579     localLength = (*elementItem)->element.length;
06580     sequenceDone = (localLength == 0);
06581 
06582     while (!sequenceDone) {
06583         if (debug)
06584             fprintf(stderr, "Sequence Length: %d %x\n", localLength,
06585                     localLength);
06586 
06587         sequenceLength = 0;
06588         itemTagOffset = *fileOffset;
06589 
06590         flag = readGroupElement(name, ptr, fd, &localLength, fileOffset, knownLength,
06591                                 byteOrder, explicitVR, acceptVRMismatch, object, &sequenceLength, &tagE);
06592         if (flag == DCM_STREAMCOMPLETE)
06593             break;
06594         else if (flag != DCM_NORMAL)
06595             return flag;
06596 
06597         flag = readVRLength(name, ptr, fd, &localLength, fileOffset, knownLength,
06598                             byteOrder, explicitVR, acceptVRMismatch, object,
06599                             &sequenceLength, &tagE);
06600         if (flag != DCM_NORMAL)
06601             return flag;
06602 
06603         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06604             *size -= sequenceLength;
06605         if (scannedLength != NULL)
06606             *scannedLength += sequenceLength;
06607 
06608         sequenceLength = 0;
06609 
06610 
06611         if (debug)
06612             fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
06613                     DCM_TAG_GROUP(tagE.tag),
06614                     DCM_TAG_ELEMENT(tagE.tag), tagE.length, tagE.length);
06615         if (tagE.tag == DCM_DLMITEM) {
06616             localPtr = *ptr;
06617             cond = readFile1(name,
06618                              localPtr,
06619                              fd, tagE.length,
06620                              fileOffset, recursionLevel + 1, opt,
06621                              object, &sequenceObject, &sequenceLength,
06622                           remainOpenFlag, (*object)->userCtx, (*object)->rd,
06623                              (*object)->sk);
06624             *ptr = localPtr;
06625             if (cond == DCM_NORMAL) {
06626                 sequenceItem = CTN_MALLOC(sizeof(*sequenceItem));
06627                 if (sequenceItem == NULL)
06628                     return COND_PushCondition(DCM_MALLOCFAILURE,
06629                                               DCM_Message(DCM_MALLOCFAILURE),
06630                                          sizeof(*sequenceItem), "readFile");
06631 
06632                 ((PRIVATE_OBJECT *) sequenceObject)->offset = itemTagOffset;
06633                 sequenceItem->object = sequenceObject;
06634                 cond = LST_Enqueue(&(*elementItem)->element.d.sq,
06635                                    (void *)sequenceItem);
06636                 if (cond != LST_NORMAL)
06637                     return COND_PushCondition(DCM_LISTFAILURE,
06638                                   DCM_Message(DCM_LISTFAILURE), "readFile");
06639                 if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06640                     *size -= sequenceLength;
06641                 if (scannedLength != NULL)
06642                     *scannedLength += sequenceLength;
06643                 (*object)->objectSize += sequenceLength;
06644                 if (localLength != DCM_UNSPECIFIEDLENGTH)
06645                     localLength -= sequenceLength;
06646             } else
06647                 return cond;
06648         } else {
06649             sequenceDone = TRUE;
06650         }
06651         if (localLength == 0)
06652             sequenceDone = TRUE;
06653     }
06654     return DCM_NORMAL;
06655 }
06656 
06657 static CONDITION
06658 scanCompressedPixels(char *name, unsigned char **ptr, int fd, U32 * size,
06659                   off_t * fileOffset, int recursionLevel, unsigned long opt,
06660                      int byteOrder, CTNBOOLEAN explicitVR,
06661                      CTNBOOLEAN acceptVRMismatch,
06662                      CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
06663                      CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
06664                      U32 * scannedLength, DCM_ELEMENT * e,
06665                      PRV_ELEMENT_ITEM ** elementItem)
06666 {
06667     CTNBOOLEAN knownLength = TRUE;
06668     U32 sequenceLength;
06669     U32 scannedBytes = 0;
06670 
06671     U32 localLength;
06672     CTNBOOLEAN sequenceDone;
06673     DCM_ELEMENT tagE;
06674     CONDITION flag;
06675     unsigned char *localPtr;
06676 
06677     if (*size == (long) DCM_UNSPECIFIEDLENGTH)
06678         knownLength = FALSE;
06679 
06680     localLength = (*elementItem)->element.length;
06681     sequenceDone = (localLength == 0);
06682 
06683     while (!sequenceDone) {
06684         sequenceLength = 0;
06685         flag = readGroupElement(name, ptr, fd, &localLength, fileOffset,
06686                              FALSE, byteOrder, explicitVR, acceptVRMismatch,
06687                                 object, &sequenceLength, &tagE);
06688         if (flag == DCM_STREAMCOMPLETE)
06689             break;
06690         else if (flag != DCM_NORMAL)
06691             return flag;
06692 
06693         flag = readVRLength(name, ptr, fd, &localLength, fileOffset, knownLength,
06694                             byteOrder, explicitVR, acceptVRMismatch, object,
06695                             &sequenceLength, &tagE);
06696         if (flag != DCM_NORMAL)
06697             return flag;
06698 
06699         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06700             *size -= sequenceLength;
06701         if (scannedLength != NULL)
06702             *scannedLength += sequenceLength;
06703         scannedBytes += sequenceLength;
06704 
06705         if (debug)
06706             fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
06707                     DCM_TAG_GROUP(tagE.tag),
06708                     DCM_TAG_ELEMENT(tagE.tag), tagE.length, tagE.length);
06709         if (tagE.tag == DCM_DLMITEM) {
06710             localPtr = *ptr;
06711             if (tagE.length != 0) {
06712                 lseek(fd, tagE.length, SEEK_CUR);
06713                 *fileOffset += tagE.length;
06714                 if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06715                     *size -= tagE.length;
06716                 if (scannedLength != NULL)
06717                     *scannedLength += tagE.length;
06718             }
06719         } else {
06720             sequenceDone = TRUE;
06721         }
06722         if (localLength == 0)
06723             sequenceDone = TRUE;
06724 
06725         if (debug)
06726             fprintf(stderr, "Scanned Bytes: %d\n", scannedBytes);
06727     }
06728     if ((scannedBytes & 1) != 0) {
06729         lseek(fd, 1, SEEK_CUR);
06730         *fileOffset += 1;
06731         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06732             *size -= 1;
06733     }
06734     return DCM_NORMAL;
06735 }
06736 
06737 static CONDITION
06738 readData(const char *name, unsigned char **ptr, int fd, U32 * size,
06739          off_t * fileOffset,
06740          CTNBOOLEAN knownLength, int byteOrder, CTNBOOLEAN explicitVR,
06741          CTNBOOLEAN acceptVRMismatch,
06742          CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
06743          CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
06744          U32 * scannedLength, DCM_ELEMENT * e,
06745          PRV_ELEMENT_ITEM ** elementItem)
06746 {
06747     CTNBOOLEAN pixelFlag;
06748     CONDITION cond;
06749     int nBytes;
06750 
06751     pixelFlag = (e->tag == DCM_PXLPIXELDATA);
06752     cond = newElementItem(e, (pixelFlag == FALSE), elementItem);
06753     if (cond != DCM_NORMAL) {
06754         (void) DCM_CloseObject((DCM_OBJECT **) object);
06755         return cond;
06756     }
06757     (*elementItem)->element.data_offset = 0 ;      /* RWCox */
06758     if (pixelFlag) {
06759         if (fileFlag)
06760             *remainOpenFlag = TRUE;
06761         (*elementItem)->byteOrder = byteOrder;
06762         (*elementItem)->dataOffset = *fileOffset;
06763         (*elementItem)->currentOffset = 0;
06764         (*elementItem)->element.d.ot = NULL;
06765         if ((*object)->pixelBitsAllocated == 8)
06766             (*elementItem)->element.representation = DCM_OB;
06767         else
06768             (*elementItem)->element.representation = DCM_OW;
06769         if (fileFlag) {
06770             if (fd != -1) {
06771                 if ((*elementItem)->element.length != DCM_UNSPECIFIEDLENGTH){
06772 
06773                     pxl_off = lseek( fd , 0 , SEEK_CUR ) ;
06774                     pxl_len = (*elementItem)->element.length ;
06775 
06776                     (*elementItem)->element.data_offset = pxl_off ;   /* RWCox */
06777 
06778                     (void) lseek(fd,
06779                                  (off_t) (*elementItem)->element.length,
06780                                  SEEK_CUR);
06781                 } else {
06782                     U32 l1 = 0;
06783                     U32 s1;
06784                     off_t f1 = 0;
06785 
06786                     s1 = *size;
06787                     scanCompressedPixels("", ptr, fd,
06788                                          &s1,   /* size */
06789                                          &f1,   /* fileOffset */
06790                                          0, 0,
06791                                          byteOrder, explicitVR,
06792                                          acceptVRMismatch,
06793                                          fileFlag, remainOpenFlag,
06794                                          convertFlag, object,
06795                                          &l1,   /* scannedLength */
06796                                          e, elementItem);
06797                     (*elementItem)->originalDataLength = l1;
06798                     (*elementItem)->paddedDataLength = l1;
06799                 }
06800             } else {
06801                 (*object)->sk((*object)->userCtx,
06802                               (*elementItem)->element.length, SEEK_CUR);
06803             }
06804             (*object)->fd = fd;
06805         }
06806     } else {
06807         if (fileFlag) {
06808             if (fd != -1) {
06809                 (*elementItem)->element.data_offset = lseek(fd,0,SEEK_CUR);  /* RWCox */
06810                 nBytes = read(fd, (*elementItem)->element.d.ot,
06811                               (int) (*elementItem)->element.length);
06812             } else {
06813                 cond = (*object)->rd((*object)->userCtx,
06814                                      (*elementItem)->element.d.ot,
06815                             (long) (*elementItem)->element.length, &nBytes);
06816             }
06817             if (nBytes != (int) (*elementItem)->element.length) {
06818                 (void) DCM_CloseObject((DCM_OBJECT **) object);
06819                 return COND_PushCondition(DCM_FILEACCESSERROR,
06820                         DCM_Message(DCM_FILEACCESSERROR), name, "readFile");
06821             }
06822         } else {
06823             (void) memcpy((*elementItem)->element.d.ot, ptr,
06824                           (*elementItem)->element.length);
06825             ptr += (*elementItem)->originalDataLength;
06826         }
06827         if( LITTLE_ENDIAN_ARCHITECTURE ){
06828           if ((*elementItem)->element.representation == DCM_AT)
06829             swapATGroupElement(&(*elementItem)->element);
06830         }
06831         if (byteOrder != BYTEORDER_SAME)
06832             swapInPlace(object, &(*elementItem)->element);
06833         if (convertFlag) {
06834             cond = verifyFormat(*elementItem);
06835             if (cond != DCM_NORMAL)
06836                 return cond;
06837         }
06838     }
06839     if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06840         *size -= (*elementItem)->originalDataLength;
06841     *fileOffset += (off_t) (*elementItem)->originalDataLength;
06842     if (scannedLength != NULL)
06843         (*scannedLength) += (*elementItem)->originalDataLength;
06844 
06845     if ((*elementItem)->element.length != DCM_UNSPECIFIEDLENGTH) {
06846       (*elementItem)->paddedDataLength = (*elementItem)->element.length;
06847     }
06848     if (((*elementItem)->paddedDataLength != DCM_UNSPECIFIEDLENGTH) &&
06849         ((*elementItem)->paddedDataLength & 1) )
06850         (*elementItem)->paddedDataLength += 1;
06851     (*object)->objectSize += (*elementItem)->paddedDataLength;
06852 
06853     return DCM_NORMAL;
06854 
06855 }
06856 
06857 static CONDITION
06858 checkAttributeOrder(DCM_ELEMENT * e, long *lastGroup, long *lastElement,
06859                     CTNBOOLEAN allowRepeatElements)
06860 {
06861     unsigned short group;
06862     unsigned short element;
06863 
06864     group = DCM_TAG_GROUP(e->tag);
06865     element = DCM_TAG_ELEMENT(e->tag);
06866 
06867     if ((long) group == *lastGroup) {
06868         if (((long) element == *lastElement) && allowRepeatElements) {
06869           return DCM_REPEATEDELEMENT;
06870         }
06871         if ((long) element <= *lastElement)
06872             return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06873                                       DCM_Message(DCM_ELEMENTOUTOFORDER),
06874                                       group, element, "checkAttributeOrder");
06875     } else if ((long) group > *lastGroup) {
06876     } else {
06877         return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06878                                   DCM_Message(DCM_ELEMENTOUTOFORDER),
06879                                   group, element, "checkAttributeOrder");
06880     }
06881     *lastGroup = (long) group;
06882     *lastElement = (long) element;
06883 
06884     return DCM_NORMAL;
06885 }
06886 
06887 static CONDITION
06888 handleGroupItem(PRIVATE_OBJECT ** obj, PRV_GROUP_ITEM ** groupItem,
06889                 unsigned short group)
06890 {
06891     CTNBOOLEAN createGroupFlag;
06892 
06893     if (*groupItem == NULL)
06894         createGroupFlag = TRUE;
06895     else if ((*groupItem)->group != group)
06896         createGroupFlag = TRUE;
06897     else
06898         createGroupFlag = FALSE;
06899 
06900     if (createGroupFlag == TRUE) {
06901         *groupItem = CTN_MALLOC(sizeof(**groupItem));
06902         if (*groupItem == NULL) {
06903             (void) DCM_CloseObject((DCM_OBJECT **) obj);
06904             return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
06905                                       DCM_Message(DCM_ELEMENTCREATEFAILED),
06906                                       "handleGroupItem",
06907                                       group, 0xffff, sizeof(**groupItem));
06908         }
06909         (*groupItem)->group = group;
06910         (*groupItem)->baseLength = 0;
06911         (*groupItem)->longVRAttributes = 0;
06912         (*groupItem)->elementList = LST_Create();
06913         if ((*groupItem)->elementList == NULL) {
06914             (void) DCM_CloseObject((DCM_OBJECT **) obj);
06915             return COND_PushCondition(DCM_LISTFAILURE,
06916                                       DCM_Message(DCM_LISTFAILURE),
06917                                       "handleGroupItem");
06918         }
06919         if (LST_Enqueue(&(*obj)->groupList, (void *)*groupItem) != LST_NORMAL) {
06920             (void) DCM_CloseObject((DCM_OBJECT **) obj);
06921             return COND_PushCondition(DCM_LISTFAILURE,
06922                                       DCM_Message(DCM_LISTFAILURE),
06923                                       "handleGroupItem");
06924         }
06925     }
06926     return DCM_NORMAL;
06927 }
06928 
06929 static CONDITION
06930 readFile1(const char *name, unsigned char *callerBuf, int fd, U32 size,
06931           off_t * fileOffset, int recursionLevel,
06932           unsigned long opt, PRIVATE_OBJECT ** parentObject,
06933           DCM_OBJECT ** callerObject,
06934           U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
06935           void *ctx,
06936           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
06937           CONDITION(*sk) (void *ctx, int offset, int flag))
06938 {
06939     CONDITION
06940     cond;
06941     int
06942         byteOrder;
06943     long
06944         lastGroup = -1,
06945         lastElement = -1;
06946     U32
06947         sequenceLength,
06948         scannedSequenceLength;
06949     PRIVATE_OBJECT
06950         ** object;
06951     PRV_GROUP_ITEM
06952         * groupItem = NULL;
06953     DCM_ELEMENT
06954         e;
06955     CTNBOOLEAN
06956         convertFlag = FALSE,
06957         done = FALSE,
06958         knownLength = TRUE,
06959         explicitVR = FALSE,
06960         acceptVRMismatch = FALSE,
06961         part10Flag = FALSE;
06962     unsigned char
06963        *ptr = NULL;
06964     PRV_ELEMENT_ITEM
06965         * elementItem = NULL;
06966     CTNBOOLEAN
06967         fileFlag = TRUE;
06968     CONDITION flag;
06969     CTNBOOLEAN allowRepeatElements = FALSE;
06970 
06971 ENTRY("readFile1") ;
06972 
06973     ptr = callerBuf;
06974     if (ptr != NULL)
06975         fileFlag = FALSE;
06976 
06977     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
06978         part10Flag = TRUE;
06979         opt &= ~DCM_ORDERMASK;
06980         opt &= ~DCM_FILEFORMATMASK;
06981         opt |= DCM_EXPLICITLITTLEENDIAN;
06982     }
06983     if ((opt & DCM_SPECIALFORMATMASK) == DCM_EFILM) {
06984         part10Flag = TRUE;
06985         opt &= ~DCM_ORDERMASK;
06986         opt &= ~DCM_FILEFORMATMASK;
06987         opt |= DCM_ORDERLITTLEENDIAN;
06988     }
06989     if ((opt & DCM_REPEATELEMENTSMASK) == DCM_ALLOWREPEATELEMENTS) {
06990       allowRepeatElements = TRUE;
06991     }
06992 
06993     switch (opt & DCM_ORDERMASK) {
06994     case DCM_ORDERNATIVE:
06995         byteOrder = NATIVE_ORDER;
06996         break;
06997     case DCM_ORDERLITTLEENDIAN:
06998         byteOrder = LITTLE_ORDER;
06999         break;
07000     case DCM_EXPLICITLITTLEENDIAN:
07001         byteOrder = LITTLE_ORDER;
07002         explicitVR = TRUE;
07003         break;
07004     case DCM_ORDERBIGENDIAN:
07005         byteOrder = BIG_ORDER;
07006         break;
07007     case DCM_EXPLICITBIGENDIAN:
07008         byteOrder = BIG_ORDER;
07009         explicitVR = TRUE;
07010         break;
07011     default:
07012         byteOrder = NATIVE_ORDER;
07013         break;
07014     }
07015     if ((opt & DCM_CONVERTMASK) == DCM_FORMATCONVERSION)
07016         convertFlag = TRUE;
07017     if ((opt & DCM_VRMASK) == DCM_ACCEPTVRMISMATCH)
07018         acceptVRMismatch = TRUE;
07019 
07020     if (scannedLength != NULL)
07021         *scannedLength = 0;
07022 
07023     cond = DCM_CreateObject(callerObject, opt);
07024     if (cond != DCM_NORMAL)
07025         RETURN( cond ) ;
07026 
07027     object = (PRIVATE_OBJECT **) callerObject;
07028     if (fileFlag)
07029         strcpy((*object)->fileName, name);
07030 
07031     (*object)->fd = -1;
07032     (*object)->rd = rd;
07033     (*object)->sk = sk;
07034     (*object)->userCtx = ctx;
07035     (*object)->dataOptions = 0;
07036     if (size == (long) DCM_UNSPECIFIEDLENGTH)
07037         knownLength = FALSE;
07038 
07039     if ((fileFlag) && ((opt & DCM_DELETEMASK) == DCM_DELETEONCLOSE) && (recursionLevel == 0))
07040         (*object)->deleteFlag = TRUE;
07041 
07042     if (parentObject != NULL)
07043         (*object)->pixelRepresentation = (*parentObject)->pixelRepresentation;
07044 
07045     if (recursionLevel == 0 && part10Flag) {
07046         flag = readPreamble(name, &ptr, fd, &size, fileOffset, knownLength,
07047                             object, scannedLength);
07048         if (flag != DCM_NORMAL)
07049             { STATUS("readPreamble fails"); goto abort; }
07050     }
07051     while (!done) {
07052         flag = readGroupElement(name, &ptr, fd, &size, fileOffset, knownLength,
07053                             byteOrder, explicitVR, acceptVRMismatch, object,
07054                                 scannedLength, &e);
07055         if (flag == DCM_STREAMCOMPLETE)
07056             break;
07057         else if (flag != DCM_NORMAL)
07058             { STATUS("readGroupElement fails"); goto abort; }
07059 #if 0
07060         if (e.tag == DCM_MAKETAG(0x003a, 0x1000)) {
07061             fprintf(stderr, "Found waveform\n");
07062         }
07063 #endif
07064         flag = readVRLength(name, &ptr, fd, &size, fileOffset, knownLength,
07065                             byteOrder, explicitVR, acceptVRMismatch, object,
07066                             scannedLength, &e);
07067         if (flag != DCM_NORMAL)
07068             { STATUS("readVRLength fails"); goto abort; }
07069 
07070         if ((e.representation == DCM_UN) &&
07071             (e.length == DCM_UNSPECIFIEDLENGTH)) {
07072             e.representation = DCM_SQ;
07073         }
07074 #ifndef SMM
07075         if ((e.tag == DCM_DLMITEMDELIMITATIONITEM) ||
07076             (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)) {
07077             RETURN( DCM_NORMAL) ;
07078         }
07079 #else
07080         if (e.tag == DCM_DLMITEMDELIMITATIONITEM) {
07081             (*object)->objectSize -= 8;
07082             RETURN( DCM_NORMAL );
07083         }
07084         if (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)
07085             RETURN( DCM_NORMAL );
07086 #endif
07087 
07088         if (e.representation == DCM_SQ) {
07089             sequenceLength = e.length;
07090             scannedSequenceLength = 0;
07091             flag = readSequence(name, &ptr, fd, &sequenceLength,
07092                                 fileOffset, recursionLevel, opt,
07093                                 byteOrder, explicitVR, acceptVRMismatch,
07094                                 fileFlag, remainOpenFlag,
07095                                 convertFlag, object, &scannedSequenceLength,
07096                                 &e, &elementItem);
07097             if (flag != DCM_NORMAL)
07098                 { STATUS("readSequence fails"); goto abort; }
07099             if (size != (long) DCM_UNSPECIFIEDLENGTH)
07100                 size -= scannedSequenceLength;
07101             if (scannedLength != NULL)
07102                 *scannedLength += scannedSequenceLength;
07103 
07104         } else {
07105 
07106             flag = readData(name, &ptr, fd, &size, fileOffset, knownLength,
07107                           byteOrder, explicitVR, acceptVRMismatch, fileFlag,
07108                             remainOpenFlag, convertFlag,
07109                             object, scannedLength, &e, &elementItem);
07110             if (flag != DCM_NORMAL)
07111                 { STATUS("readData fails"); goto abort; }
07112         }
07113         computeVM(object, &elementItem->element);
07114 
07115         cond = checkAttributeOrder(&e, &lastGroup, &lastElement, allowRepeatElements);
07116         if (cond != DCM_NORMAL) {
07117             if (cond == DCM_REPEATEDELEMENT) {
07118                 CTN_FREE(elementItem);
07119                 continue;
07120             } else {
07121                 CTN_FREE(elementItem);   /* 22 June 2005 [rickr] */
07122                 RETURN( cond ) ;
07123             }
07124         }
07125 
07126         cond = handleGroupItem(object, &groupItem, DCM_TAG_GROUP(e.tag));
07127         if (cond != DCM_NORMAL)
07128              /* goto abort; ASG */ RETURN( cond );
07129 
07130         if (DCM_TAG_ELEMENT(e.tag) != 0x0000) {
07131             groupItem->baseLength += 8 + elementItem->paddedDataLength;
07132             if (elementItem->element.representation == DCM_OB ||
07133                 elementItem->element.representation == DCM_OW ||
07134                 elementItem->element.representation == DCM_SQ) {
07135                 groupItem->longVRAttributes++;
07136                 (*object)->longVRAttributes++;
07137             }
07138         }
07139         if ((DCM_TAG_ELEMENT(e.tag) == 0x0000) && ((*object)->groupLengthFlag == FALSE)) {
07140             CTN_FREE(elementItem);
07141         } else {
07142             cond = LST_Enqueue(&groupItem->elementList, (void *)elementItem);
07143             if (cond != LST_NORMAL) {
07144                 (void) DCM_CloseObject(callerObject);
07145                 RETURN( COND_PushCondition(DCM_LISTFAILURE,
07146                                           DCM_Message(DCM_LISTFAILURE),
07147                                           "readFile") );
07148             }
07149             cond = updateObjectType(object, &elementItem->element);     /* repair */
07150 
07151             cond = updateSpecialElements(object, elementItem);  /* repair */
07152         }
07153 
07154         if (size == 0)
07155             done = TRUE;
07156 
07157         if (part10Flag) {
07158             if ((*object)->objectSize == (DCM_PREAMBLELENGTH + 4 + 12 + (*object)->metaHeaderLength)) {
07159                 opt &= ~DCM_ORDERMASK;
07160                 opt |= (*object)->dataOptions & DCM_ORDERMASK;
07161                 explicitVR = FALSE;
07162                 switch (opt & DCM_ORDERMASK) {
07163                 case DCM_ORDERNATIVE:
07164                     byteOrder = NATIVE_ORDER;
07165                     break;
07166                 case DCM_ORDERLITTLEENDIAN:
07167                     byteOrder = LITTLE_ORDER;
07168                     break;
07169                 case DCM_EXPLICITLITTLEENDIAN:
07170                     byteOrder = LITTLE_ORDER;
07171                     explicitVR = TRUE;
07172                     break;
07173                 case DCM_ORDERBIGENDIAN:
07174                     byteOrder = BIG_ORDER;
07175                     break;
07176                 case DCM_EXPLICITBIGENDIAN:
07177                     byteOrder = BIG_ORDER;
07178                     explicitVR = TRUE;
07179                     break;
07180                 default:
07181                     byteOrder = LITTLE_ORDER;
07182                     explicitVR = TRUE;
07183                     break;
07184                 }
07185             }
07186         }
07187     }
07188 
07189 #ifdef SMM
07190 #endif
07191 
07192     groupItem = (void *)LST_Head(&(*object)->groupList);
07193     if (groupItem != NULL) {
07194         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
07195         while (groupItem != NULL) {
07196             elementItem = (void *)LST_Head(&groupItem->elementList);
07197             if (elementItem != NULL) {
07198                 if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
07199                     *elementItem->element.d.ul = groupItem->baseLength;
07200                 }
07201             }
07202             groupItem = (void *)LST_Next(&(*object)->groupList);
07203         }
07204     }
07205     RETURN( DCM_NORMAL );
07206 
07207 abort:
07208     RETURN (flag);
07209 }
07210 
07211 /* locateElement
07212 **
07213 ** Purpose:
07214 **      Locate the DICOM element with the specified tag number in the given
07215 **      DICOM object
07216 **
07217 ** Parameter Dictionary:
07218 **      obj             Handle to the DICOM object to be searched
07219 **      tag             Tag number of the element to be searched
07220 **
07221 ** Return Values:
07222 **      Pointer to the element if found else NULL
07223 **
07224 ** Notes:
07225 **
07226 ** Algorithm:
07227 **      Description of the algorithm (optional) and any other notes.
07228 */
07229 static PRV_ELEMENT_ITEM *
07230 locateElement(PRIVATE_OBJECT ** obj, DCM_TAG tag)
07231 {
07232     PRV_GROUP_ITEM
07233     * groupItem;
07234     PRV_ELEMENT_ITEM
07235         * elementItem;
07236     CTNBOOLEAN
07237         found = FALSE;
07238 
07239     groupItem = (void *)LST_Head(&(*obj)->groupList);
07240     if (groupItem == NULL)
07241         return NULL;
07242 
07243     (void) LST_Position(&(*obj)->groupList, (void *)groupItem);
07244     while (groupItem != NULL) {
07245         if (groupItem->group == DCM_TAG_GROUP(tag))
07246             break;
07247 
07248         groupItem = (void *)LST_Next(&(*obj)->groupList);
07249     }
07250     if (groupItem == NULL)
07251         return NULL;
07252 
07253     elementItem = (void *)LST_Head(&groupItem->elementList);
07254     if (elementItem == NULL)
07255         return NULL;
07256 
07257     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
07258     while (!found && (elementItem != NULL)) {
07259         if (elementItem->element.tag == tag) {
07260             found = TRUE;
07261         } else
07262             elementItem = (void *)LST_Next(&groupItem->elementList);
07263     }
07264     if (found)
07265         return elementItem;
07266     else
07267         return NULL;
07268 }
07269 
07270 /* computeVM
07271 **
07272 ** Purpose:
07273 **      Compute the multiplicity of the specified element in the DICOM
07274 **      object
07275 **
07276 ** Parameter Dictionary:
07277 **      object          Handle to the DICOM object
07278 **      element         Element whose value multiplicity is to be found out.
07279 **
07280 ** Return Values:
07281 **      None
07282 **
07283 ** Notes:
07284 **
07285 ** Algorithm:
07286 **      Description of the algorithm (optional) and any other notes.
07287 */
07288 static void
07289 computeVM(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
07290 {
07291     char
07292        *c;
07293     int
07294         i;
07295 
07296     switch (element->representation) {
07297     case DCM_AE:                /* Application Entity */
07298     case DCM_AS:                /* Age string */
07299     case DCM_CS:                /* Control string */
07300     case DCM_DA:                /* Date */
07301     case DCM_DS:                /* Decimal string */
07302     case DCM_DT:                /* Date/Time */
07303     case DCM_IS:                /* Integer string */
07304     case DCM_LO:                /* Long string */
07305     case DCM_PN:                /* Person Name */
07306     case DCM_SH:                /* Short string */
07307     case DCM_TM:                /* Time */
07308     case DCM_UI:                /* Unique identifier (UID) */
07309     case DCM_UT:                /* Unlimited text */
07310         element->multiplicity = 1;
07311         c = element->d.string;
07312         for (i = 0; i < (int) element->length; i++)
07313             if (*c++ == '\\')
07314                 element->multiplicity++;
07315         break;
07316 
07317     case DCM_FD:                /* Floating double */
07318         element->multiplicity = element->length / 8;
07319         break;
07320     case DCM_AT:                /* Attribute tag */
07321     case DCM_FL:                /* Float */
07322     case DCM_SL:                /* Signed long */
07323     case DCM_UL:                /* Unsigned long */
07324         element->multiplicity = element->length / 4;
07325         break;
07326     case DCM_SS:                /* Signed short */
07327     case DCM_US:                /* Unsigned short */
07328         element->multiplicity = element->length / 2;
07329         break;
07330     case DCM_LT:                /* Long text */
07331     case DCM_OT:                /* Other binary value */
07332     case DCM_SQ:                /* Sequence of items */
07333     case DCM_ST:                /* Short text */
07334     /*case DCM_UNKNOWN:*/
07335     case DCM_UN:
07336     case DCM_RET:
07337     case DCM_CTX:
07338     case DCM_DD:                /* Data set */
07339     default:
07340         element->multiplicity = 1;
07341         break;
07342     }
07343 }
07344 /* ctxSensitiveLookup
07345 **
07346 ** Purpose:
07347 **      Lookup representation of elements that are context sensitive
07348 **
07349 ** Parameter Dictionary:
07350 **      object          Handle to the DICOM object containing this element.
07351 **      element         Element who representation is to be determined.
07352 **
07353 ** Return Values:
07354 **      None
07355 **
07356 ** Notes:
07357 **
07358 */
07359 static void
07360 ctxSensitiveLookup(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
07361 {
07362     switch (element->tag) {
07363         case DCM_IMGSMALLESTIMAGEPIXELVALUE:
07364         case DCM_IMGLARGESTIMAGEPIXELVALUE:
07365         case DCM_IMGSMALLESTPIXELVALUESERIES:
07366         case DCM_IMGLARGESTPIXELVALUESERIES:
07367         case DCM_IMGSMALLESTIMAGEPIXELVALUEPLANE:
07368         case DCM_IMGLARGESTIMAGEPIXELVALUEPLANE:
07369         case DCM_IMGLUTDESCRIPTOR:
07370         case DCM_IMGLUTDATA:
07371         case DCM_IMGLOOKUPDATARED:
07372         case DCM_IMGLOOKUPDATAGREEN:
07373         case DCM_IMGLOOKUPDATABLUE:
07374         if ((*object)->pixelRepresentation == 0x0000)
07375             element->representation = DCM_US;
07376         else if ((*object)->pixelRepresentation == 0x0001)
07377             element->representation = DCM_SS;
07378         else
07379             element->representation = DCM_US;
07380         break;
07381     case DCM_MAKETAG(0x003a, 0x1000):
07382         if (strcmp((*object)->waveformDataVR, "SS") == 0)
07383             element->representation = DCM_SS;
07384         break;
07385 
07386     default:
07387         break;
07388     }
07389 }
07390 
07391 static CONDITION
07392 copyData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * from,
07393          DCM_ELEMENT * to, U32 * rtnLength)
07394 {
07395     unsigned char *p = NULL;
07396     U32 l;
07397     int nBytes;
07398     CONDITION cond;
07399 
07400     if (from->element.representation == DCM_SQ)
07401         return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
07402                                   DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
07403                               from->element.tag, "copyData (DCM internal)");
07404 
07405     l = MIN(from->element.length, to->length);
07406     if (rtnLength != NULL)
07407         *rtnLength = l;
07408 
07409     if (from->element.d.ot == NULL) {
07410         if ((*object)->fd != -1) {
07411             (void) lseek((*object)->fd,
07412                          from->dataOffset + (off_t) p, SEEK_SET);
07413             nBytes = read((*object)->fd, to->d.ot, (int) l);
07414         } else {
07415             (*object)->sk((*object)->userCtx,
07416                           (long) (from->dataOffset + (off_t) p), SEEK_SET);
07417             cond = (*object)->rd((*object)->userCtx, to->d.ot, (long) l, &nBytes);
07418         }
07419         if (nBytes != (int) l) {
07420             return COND_PushCondition(DCM_FILEACCESSERROR,
07421                                       DCM_Message(DCM_FILEACCESSERROR),
07422                                       (*object)->fileName,
07423                                       "copyData (DCM internal)");
07424         }
07425         if( LITTLE_ENDIAN_ARCHITECTURE ){
07426           if (from->element.representation == DCM_AT) {
07427             DCM_ELEMENT e;
07428             e = from->element;
07429             e.length = l;
07430             e.d.ot = to->d.ot;
07431             swapATGroupElement(&e);
07432           }
07433         }
07434         if (from->byteOrder == BYTEORDER_REVERSE) {
07435             DCM_ELEMENT e;
07436             e = from->element;
07437             e.length = l;
07438             e.d.ot = to->d.ot;
07439             swapInPlace(object, &e);
07440         }
07441     } else {
07442         unsigned char *q;
07443         q = (unsigned char *) from->element.d.ot +
07444             (U32) p;
07445         (void) memcpy(to->d.ot, q, l);
07446     }
07447     p += l;
07448     if ((unsigned) p == from->element.length)
07449         return DCM_NORMAL;
07450     else
07451         return DCM_GETINCOMPLETE;
07452 }
07453 
07454 static CONDITION
07455 readLengthToEnd(int fd, const char *fileName,
07456                 unsigned long opt, U32 * lengthToEnd)
07457 {
07458     unsigned char buf[24];
07459     DCM_OBJECT *obj;
07460     CONDITION cond;
07461     DCM_ELEMENT e = {DCM_MAKETAG(0x0008, 0x0001), DCM_UL, "", 1, 4, NULL};
07462     void *ctx = NULL;
07463     U32 rtnLength = 0;
07464 
07465     if (read(fd, buf, 24) != 24)
07466         return COND_PushCondition(DCM_FILEACCESSERROR,
07467                                   DCM_Message(DCM_FILEACCESSERROR), fileName,
07468                                   "(DCM)readLengthToEnd");
07469 
07470     cond = DCM_ImportStream(buf, 24, opt, &obj);
07471     if (cond != DCM_NORMAL)
07472         return cond;
07473 
07474     e.d.ul = lengthToEnd;
07475     cond = DCM_GetElementValue(&obj, &e, &rtnLength, &ctx);
07476 
07477     (void) DCM_CloseObject(&obj);
07478 
07479     return cond;
07480 }
07481 
07482 static void
07483 swapATGroupElement(DCM_ELEMENT * e)
07484 {
07485     U32
07486     length;
07487     unsigned short
07488         tmp,
07489        *us;
07490 
07491     length = e->length;
07492     us = e->d.us;
07493     while (length >= 4) {
07494         tmp = us[0];
07495         us[0] = us[1];
07496         us[1] = tmp;
07497         us += 2;
07498         length -= 4;
07499     }
07500 }
07501 
07502 static void
07503 dumpSS(short *ss, long vm)
07504 {
07505     long index = 0;
07506     RWC_printf("decimal SS:") ;
07507     while (index < vm) {
07508         RWC_printf("%7d ", *(ss++));
07509         if ((++index) % 8 == 0)
07510             RWC_printf("\n");
07511     }
07512     RWC_printf("\n");
07513 }
07514 
07515 static void
07516 dumpSL(S32 * sl, long vm)
07517 {
07518     long index = 0;
07519     RWC_printf("decimal SL:") ;
07520     while (index < vm) {
07521         RWC_printf("%7d ", *(sl++));
07522         if ((++index) % 8 == 0)
07523             RWC_printf("\n");
07524     }
07525     RWC_printf("\n");
07526 }
07527 
07528 static void
07529 dumpUS(unsigned short *us, long vm)
07530 {
07531     long index = 0;
07532     RWC_printf("decimal US:") ;
07533     while (index < vm) {
07534         RWC_printf("%7d ", *(us++));
07535         if ((++index) % 8 == 0)
07536             RWC_printf("\n");
07537     }
07538     RWC_printf("\n");
07539 }
07540 static void
07541 dumpUL(U32 * ul, long vm)
07542 {
07543     long index = 0;
07544     RWC_printf("decimal UL:") ;
07545     while (index < vm) {
07546         RWC_printf("%7d ", *(ul++));
07547         if ((++index) % 8 == 0)
07548             RWC_printf("\n");
07549     }
07550     RWC_printf("\n");
07551 }
07552 static void
07553 dumpOB(unsigned char* c, long vm)
07554 {
07555   long index = 0;
07556   RWC_printf("hex OB:") ;
07557   while (index < vm) {
07558     RWC_printf("%02x ", *(c++));
07559     if ((++index) % 8 == 0)
07560       RWC_printf("\n");
07561   }
07562   if( index%8 != 0 ) RWC_printf("\n");
07563 }
07564 
07565 static void
07566 dumpBinaryData(void *d, DCM_VALUEREPRESENTATION vr, long vm,
07567                long vmLimit)
07568 {
07569     vm = (vm < vmLimit) ? vm : vmLimit;
07570 
07571     if (vm <= 1)
07572         return;
07573 
07574     switch (vr) {
07575     case DCM_SL:
07576         dumpSL((S32 *) d, vm);
07577         break;
07578     case DCM_UL:
07579         dumpUL((U32 *) d, vm);
07580         break;
07581     case DCM_SS:
07582         dumpSS((short *) d, vm);
07583         break;
07584     case DCM_US:
07585         dumpUS((unsigned short *) d, vm);
07586         break;
07587     case DCM_OB:
07588     case DCM_UN:
07589         dumpOB((unsigned char*) d, vm);
07590         break;
07591     default:
07592         break;
07593     }
07594 }
07595 
07596 static void
07597 compareGroup(PRV_GROUP_ITEM * g1, PRV_GROUP_ITEM * g2,
07598              void (*callback) (const DCM_ELEMENT * e1,
07599                                const DCM_ELEMENT * e2,
07600                                void *ctx),
07601              void *ctx)
07602 {
07603     PRV_ELEMENT_ITEM *e1 = NULL,
07604        *e2 = NULL;
07605 
07606     if (g1 != NULL) {
07607         e1 = (void *)LST_Head(&g1->elementList);
07608         if (e1 != NULL)
07609             LST_Position(&g1->elementList, (void *)e1);
07610     }
07611     if (g2 != NULL) {
07612         e2 = (void *)LST_Head(&g2->elementList);
07613         if (e2 != NULL)
07614             LST_Position(&g2->elementList, (void *)e2);
07615     }
07616     while (e1 != NULL) {
07617         if (e2 == NULL) {
07618             callback(&e1->element, NULL, ctx);
07619             e1 = (void *)LST_Next(&g1->elementList);
07620         } else if (e1->element.tag == e2->element.tag) {
07621             callback(&e1->element, &e2->element, ctx);
07622             e1 = (void *)LST_Next(&g1->elementList);
07623             e2 = (void *)LST_Next(&g2->elementList);
07624         } else if (e1->element.tag < e2->element.tag) {
07625             callback(&e1->element, NULL, ctx);
07626             e1 = (void *)LST_Next(&g1->elementList);
07627         } else {
07628             callback(NULL, &e2->element, ctx);
07629             e2 = (void *)LST_Next(&g2->elementList);
07630         }
07631     }
07632 
07633     while (e2 != NULL) {
07634         callback(NULL, &e2->element, ctx);
07635         e2 = (void *)LST_Next(&g2->elementList);
07636     }
07637 }
07638 
07639 static void
07640 remapFileName(const char *name, char *mapName)
07641 {
07642     char c;
07643 
07644     while ((c = *name++) != '\0') {
07645         if (c == '\\')
07646             *mapName++ = '/';
07647         else if (isupper(c))
07648             *mapName++ = tolower(c);
07649         else
07650             *mapName++ = c;
07651     }
07652     *mapName = '\0';
07653 }
07654 
07655 static void
07656 copySequence(PRIVATE_OBJECT ** dstObj, DCM_ELEMENT * e)
07657 {
07658     LST_HEAD *lst;
07659     DCM_SEQUENCE_ITEM *sqItem;
07660     DCM_ELEMENT newElement;
07661 
07662     lst = LST_Create();
07663     if (e->d.sq != NULL) {
07664         sqItem = (void *)LST_Head(&e->d.sq);
07665         (void) LST_Position(&e->d.sq, (void *)sqItem);
07666     }
07667     while (sqItem != NULL) {
07668         DCM_OBJECT *copy;
07669         DCM_SEQUENCE_ITEM *copyItem;
07670 
07671         DCM_CopyObject(&sqItem->object, &copy);
07672         copyItem = AFMALL( DCM_SEQUENCE_ITEM, sizeof(*copyItem));
07673         copyItem->object = copy;
07674         (void) LST_Enqueue(&lst, (void *)copyItem);
07675 
07676         sqItem = (void *)LST_Next(&e->d.sq);
07677     }
07678 
07679     memset(&newElement, 0, sizeof(newElement));
07680     newElement.tag = e->tag;
07681     newElement.representation = e->representation;
07682     newElement.d.sq = lst;
07683     DCM_AddSequenceElement((DCM_OBJECT **) dstObj, &newElement);
07684 }
07685 
07686 /* Restart public functions */
07687 
07688 CONDITION
07689 DCM_GetCompressedValue(DCM_OBJECT ** callerObject, DCM_TAG tag, void *buf,
07690                        size_t bufSize, DCM_GET_COMPRESSED_CALLBACK* callback,
07691                        void *ctx)
07692 {
07693     PRIVATE_OBJECT
07694         ** object;
07695     PRV_ELEMENT_ITEM
07696         * elementItem;
07697     S32 nBytes;
07698     S32 toRead;
07699     CONDITION cond;
07700     int doneFlag = 0;
07701     size_t elementLength;
07702     unsigned char *ptr;
07703     U32 size = 0;
07704     off_t fileOffset = 0;
07705     unsigned long opt;
07706     int byteOrder;
07707     int explicitVR;
07708     CTNBOOLEAN acceptVRMismatch = FALSE;
07709     DCM_ELEMENT e;
07710     U32 sequenceLength = 0;
07711     CONDITION flag;
07712     int index = 0;
07713     CTNBOOLEAN firstBuffer = TRUE;
07714     U32 *offsetBuffer = NULL;
07715     U32 offsetBufferCount = 0;
07716     U32 streamOffset = 0;
07717     int startOfFragment = 1;
07718 
07719     object = (PRIVATE_OBJECT **) callerObject;
07720     cond = checkObject(object, "DCM_GetCompressedValue");
07721     if (cond != DCM_NORMAL)
07722         return cond;
07723 
07724     elementItem = locateElement(object, tag);
07725 
07726     if (elementItem == NULL)
07727         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
07728                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
07729                                   DCM_TAG_ELEMENT(tag),
07730                                   "DCM_GetEncodedValue");
07731 
07732     elementLength = elementItem->originalDataLength;
07733     ptr = NULL;                 /* Means reading from a file */
07734     size = DCM_UNSPECIFIEDLENGTH;
07735     fileOffset = elementItem->dataOffset;
07736 
07737     opt |= (*object)->dataOptions & DCM_ORDERMASK;
07738     explicitVR = FALSE;
07739     switch (opt & DCM_ORDERMASK) {
07740     case DCM_ORDERNATIVE:
07741         byteOrder = NATIVE_ORDER;
07742         break;
07743     case DCM_ORDERLITTLEENDIAN:
07744         byteOrder = LITTLE_ORDER;
07745         break;
07746     case DCM_EXPLICITLITTLEENDIAN:
07747         byteOrder = LITTLE_ORDER;
07748         explicitVR = TRUE;
07749         break;
07750     case DCM_ORDERBIGENDIAN:
07751         byteOrder = BIG_ORDER;
07752         break;
07753     case DCM_EXPLICITBIGENDIAN:
07754         byteOrder = BIG_ORDER;
07755         explicitVR = TRUE;
07756         break;
07757     default:
07758         byteOrder = LITTLE_ORDER;
07759         explicitVR = TRUE;
07760         break;
07761     }
07762     if ((opt & DCM_VRMASK) == DCM_ACCEPTVRMISMATCH)
07763         acceptVRMismatch = TRUE;
07764 
07765     (void) lseek((*object)->fd, elementItem->dataOffset, SEEK_SET);
07766     while (elementLength != 0) {
07767         sequenceLength = 0;
07768         memset(&e, 0, sizeof(e));
07769         flag = readGroupElement("", &ptr, (*object)->fd, &size, &fileOffset,
07770                              FALSE, byteOrder, explicitVR, acceptVRMismatch,
07771                                 object, &sequenceLength, &e);
07772         if (flag == DCM_STREAMCOMPLETE)
07773             break;
07774         else if (flag != DCM_NORMAL)
07775             return flag;
07776 
07777         flag = readVRLength("", &ptr, (*object)->fd, &size, &fileOffset,
07778                             FALSE,      /* Known length */
07779                             byteOrder, explicitVR, acceptVRMismatch, object,
07780                             &sequenceLength, &e);
07781         if (flag != DCM_NORMAL)
07782             return flag;
07783 
07784         elementLength -= sequenceLength + e.length;
07785 
07786         if (firstBuffer) {
07787             firstBuffer = FALSE;
07788             if (e.length != 0) {
07789                 offsetBuffer = CTN_MALLOC(e.length);
07790                 offsetBufferCount = e.length / sizeof(U32);
07791                 if (offsetBuffer == NULL)
07792                     exit(1);    /* repair */
07793                 nBytes = read((*object)->fd, offsetBuffer, e.length);
07794                 if (nBytes != e.length) {
07795                     exit(1);    /* repair */
07796                 }
07797                 if (byteOrder == BYTEORDER_REVERSE) {
07798                     DCM_ELEMENT offsetBufferElement;
07799                     memset(&offsetBufferElement, 0, sizeof(DCM_ELEMENT));
07800                     offsetBufferElement.length = e.length;
07801                     offsetBufferElement.d.ul = offsetBuffer;
07802                     offsetBufferElement.representation = DCM_UL;
07803                     swapInPlace(object, &offsetBufferElement);
07804                 }
07805                 callback(offsetBuffer, e.length, index, 1, 0, 1, ctx);
07806                 streamOffset = 0;
07807             } else {
07808                 streamOffset = 0xffffffff;
07809             }
07810         } else {
07811             U32 l = e.length;
07812             int j;
07813             int lastIndex;
07814 
07815             lastIndex = index;
07816             for (j = 0; j < offsetBufferCount; j++) {
07817                 if (streamOffset == offsetBuffer[j])
07818                     index = j + 1;
07819             }
07820             startOfFragment = 1;
07821             while (l != 0) {
07822                 toRead = MIN(bufSize, l);
07823                 nBytes = read((*object)->fd, buf, toRead);
07824                 if (nBytes != toRead) {
07825                     exit(1);    /* repair */
07826                 }
07827                 callback(buf, toRead, index,
07828                          (index != lastIndex) ? 1 : 0,
07829                          0, startOfFragment, ctx);
07830                 l -= toRead;
07831                 lastIndex = index;      /* Guarantee first flag is off */
07832                 startOfFragment = 0;
07833             }
07834             streamOffset += sequenceLength + e.length;
07835         }
07836         fileOffset += e.length;
07837         index++;
07838     }
07839     callback(buf, 0, index, 0, 1, 1, ctx);
07840     return DCM_NORMAL;
07841 }
07842 
07843 CONDITION
07844 DCM_PrintSequenceList(DCM_OBJECT ** object, DCM_TAG tag)
07845 {
07846     PRIVATE_OBJECT **obj,
07847        *sqObject;
07848     CONDITION cond;
07849     PRV_ELEMENT_ITEM *elementItem;
07850     LST_HEAD *lst;
07851     DCM_SEQUENCE_ITEM *sqItem;
07852 
07853     obj = (PRIVATE_OBJECT **) object;
07854     cond = checkObject(obj, "DCM_PrintSequenceList");
07855     if (cond != DCM_NORMAL)
07856         return cond;
07857 
07858     elementItem = locateElement(obj, tag);
07859 
07860     if (elementItem == NULL)
07861         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
07862                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
07863                                   DCM_TAG_ELEMENT(tag),
07864                                   "DCM_PrintSequenceList");
07865 
07866     lst = elementItem->element.d.sq;
07867     sqItem = (void *)LST_Head(&lst);
07868     (void) LST_Position(&lst, (void *)sqItem);
07869     while (sqItem != NULL) {
07870         sqObject = (PRIVATE_OBJECT *) sqItem->object;
07871         RWC_printf("size: %6d offset: %6d, pixel offset: %6d\n",
07872                sqObject->objectSize,
07873                sqObject->offset,
07874                sqObject->pixelOffset);
07875         sqItem = (void *)LST_Next(&lst);
07876     }
07877 }
07878 
07879 CONDITION
07880 DCM_GetSequenceByOffset(DCM_OBJECT ** object, DCM_TAG tag, unsigned long offset,
07881                         DCM_OBJECT ** rtnObject)
07882 {
07883     PRIVATE_OBJECT **obj,
07884        *sqObject;
07885     CONDITION cond;
07886     PRV_ELEMENT_ITEM *elementItem;
07887     LST_HEAD *lst;
07888     DCM_SEQUENCE_ITEM *sqItem;
07889 
07890     obj = (PRIVATE_OBJECT **) object;
07891     cond = checkObject(obj, "DCM_PrintSequenceList");
07892     if (cond != DCM_NORMAL)
07893         return cond;
07894 
07895     elementItem = locateElement(obj, tag);
07896 
07897     if (elementItem == NULL)
07898         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
07899                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
07900                                   DCM_TAG_ELEMENT(tag),
07901                                   "DCM_PrintSequenceList");
07902 
07903     lst = elementItem->element.d.sq;
07904     sqItem = (void *)LST_Head(&lst);
07905     (void) LST_Position(&lst, (void *)sqItem);
07906     while (sqItem != NULL) {
07907         sqObject = (PRIVATE_OBJECT *) sqItem->object;
07908         if (sqObject->offset == offset) {
07909             *rtnObject = sqItem->object;
07910             return DCM_NORMAL;
07911         }
07912         sqItem = (void *)LST_Next(&lst);
07913     }
07914     return 0;
07915 }
07916 
07917 CONDITION
07918 DCM_CopyObject(DCM_OBJECT ** src, DCM_OBJECT ** dst)
07919 {
07920     PRIVATE_OBJECT **srcObj;
07921     PRIVATE_OBJECT *dstObj;
07922     PRV_GROUP_ITEM *groupItem;
07923     PRV_ELEMENT_ITEM *elementItem;
07924 
07925     if (src == NULL) {
07926         (void) COND_PushCondition(DCM_NULLADDRESS,
07927                             DCM_Message(DCM_NULLADDRESS), "DCM_CopyObject");
07928         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
07929                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CopyObject");
07930     }
07931     dstObj = (PRIVATE_OBJECT *) CTN_MALLOC(sizeof(PRIVATE_OBJECT));
07932     if (dstObj == NULL) {
07933         (void) COND_PushCondition(DCM_MALLOCFAILURE,
07934                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
07935                                   "DCM_CopyObject");
07936         *dst = NULL;
07937         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
07938                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CopyObject");
07939     }
07940     (void) memset(dstObj, 0, sizeof(PRIVATE_OBJECT));
07941     (void) strcpy(dstObj->keyType, KEY_DCM_OBJECT);
07942 
07943     dstObj->objectType = DCM_OBJECTUNKNOWN;
07944     dstObj->accessMethod = DCM_MEMORY_ACCESS;
07945     dstObj->deleteFlag = FALSE;
07946     dstObj->groupLengthFlag = FALSE;
07947     dstObj->objectSize = 0;
07948     dstObj->offset = 0;
07949     dstObj->pixelSize = 0;
07950     dstObj->pixelOffset = 0;
07951     dstObj->pixelBitsAllocated = 0;
07952     dstObj->pixelRepresentation = 0xffff;
07953     dstObj->groupCtx = NULL;
07954     dstObj->elementCtx = NULL;
07955     dstObj->fd = -1;
07956     dstObj->fileName[0] = '\0';
07957     dstObj->preambleFlag = FALSE;
07958     dstObj->preamble[0] = '\0';
07959     dstObj->dataOptions = 0;
07960     dstObj->metaHeaderLength = 0xffffffff;
07961     dstObj->longVRAttributes = 0;
07962     dstObj->waveformDataVR[0] = '\0';
07963 
07964     dstObj->groupList = LST_Create();
07965     if (dstObj->groupList == NULL) {
07966         CTN_FREE(dstObj);
07967         *dst = NULL;
07968         return COND_PushCondition(DCM_LISTFAILURE,
07969                                   DCM_Message(DCM_LISTFAILURE),
07970                                   "DCM_CreateObject");
07971     }
07972     srcObj = (PRIVATE_OBJECT **) src;
07973 
07974     groupItem = (void *)LST_Head(&(*srcObj)->groupList);
07975     if (groupItem != NULL)
07976         (void) LST_Position(&(*srcObj)->groupList, (void *)groupItem);
07977 
07978     while (groupItem != NULL) {
07979         elementItem = (void *)LST_Head(&groupItem->elementList);
07980         if (elementItem != NULL)
07981             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
07982         while (elementItem != NULL) {
07983             if (elementItem->element.representation == DCM_SQ) {
07984                 copySequence(&dstObj, &elementItem->element);
07985             } else {
07986                 DCM_AddElement((DCM_OBJECT **) & dstObj, &elementItem->element);
07987             }
07988             elementItem = (void *)LST_Next(&groupItem->elementList);
07989         }
07990         groupItem = (void *)LST_Next(&(*srcObj)->groupList);
07991     }
07992 
07993     *dst = (DCM_OBJECT *) dstObj;
07994     return DCM_NORMAL;
07995 }
07996 
07997 CONDITION
07998 DCM_MergeObject(DCM_OBJECT ** src, DCM_OBJECT ** dst)
07999 {
08000     PRIVATE_OBJECT **srcObj;
08001     PRIVATE_OBJECT *dstObj;
08002     PRV_GROUP_ITEM *groupItem;
08003     PRV_ELEMENT_ITEM *elementItem;
08004 
08005     if (src == NULL) {
08006         (void) COND_PushCondition(DCM_NULLADDRESS,
08007                             DCM_Message(DCM_NULLADDRESS), "DCM_MergeObject");
08008         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
08009                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_MergeObject");
08010     }
08011     dstObj = *((PRIVATE_OBJECT **)dst);
08012     if (dstObj == NULL) {
08013         (void) COND_PushCondition(DCM_MALLOCFAILURE,
08014                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
08015                                   "DCM_MergeObject");
08016         *dst = NULL;
08017         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
08018                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_MergeObject");
08019     }
08020     srcObj = (PRIVATE_OBJECT **) src;
08021 
08022     groupItem = (void *)LST_Head(&(*srcObj)->groupList);
08023     if (groupItem != NULL)
08024         (void) LST_Position(&(*srcObj)->groupList, (void *)groupItem);
08025 
08026     while (groupItem != NULL) {
08027         elementItem = (void *)LST_Head(&groupItem->elementList);
08028         if (elementItem != NULL)
08029             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
08030         while (elementItem != NULL) {
08031             if (elementItem->element.representation == DCM_SQ) {
08032                 copySequence(&dstObj, &elementItem->element);
08033             } else {
08034                 DCM_AddElement((DCM_OBJECT **) & dstObj, &elementItem->element);
08035             }
08036             elementItem = (void *)LST_Next(&groupItem->elementList);
08037         }
08038         groupItem = (void *)LST_Next(&(*srcObj)->groupList);
08039     }
08040 
08041     /**dst = (DCM_OBJECT *) dstObj;*/
08042     return DCM_NORMAL;
08043 }
08044 
08045 
08046 CONDITION
08047 DCM_GetFirstElement(DCM_OBJECT ** callerObject, DCM_ELEMENT** e)
08048 {
08049   PRIVATE_OBJECT** object;
08050   PRV_GROUP_ITEM* groupItem;
08051   PRV_ELEMENT_ITEM* elementItem;
08052   CONDITION cond;
08053 
08054   object = (PRIVATE_OBJECT **) callerObject;
08055   cond = checkObject(object, "DCM_GetFirstElement");
08056   if (cond != DCM_NORMAL)
08057     return cond;
08058 
08059   groupItem = (void *)LST_Head(&(*object)->groupList);
08060 
08061   if (groupItem == NULL) {
08062     *e = 0;
08063     return DCM_EMPTYOBJECT;
08064   }
08065   (void) LST_Position(&(*object)->groupList, (void *)groupItem);
08066   (*object)->groupCtx = groupItem;
08067 
08068   elementItem = (void *)LST_Head(&groupItem->elementList);
08069   (*object)->elementCtx = elementItem;
08070   if (elementItem == NULL) {
08071     return DCM_GetNextElement(callerObject, e);
08072   }
08073 
08074   *e = &elementItem->element;
08075   return DCM_NORMAL;
08076 }
08077 
08078 CONDITION
08079 DCM_GetNextElement(DCM_OBJECT ** callerObject, DCM_ELEMENT** e)
08080 {
08081   PRIVATE_OBJECT** object;
08082   PRV_GROUP_ITEM* groupItem;
08083   PRV_ELEMENT_ITEM* elementItem;
08084   CONDITION cond;
08085 
08086   object = (PRIVATE_OBJECT **) callerObject;
08087   cond = checkObject(object, "DCM_GetNextElement");
08088   if (cond != DCM_NORMAL)
08089     return cond;
08090 
08091   groupItem = (*object)->groupCtx;
08092   elementItem = (*object)->elementCtx;
08093 
08094   if (elementItem != 0) {
08095     (void)LST_Position(&groupItem->elementList, (void *)elementItem);
08096     elementItem = (PRV_ELEMENT_ITEM*)LST_Next(&groupItem->elementList);
08097   }
08098 
08099   if (elementItem == 0) {
08100     (void)LST_Position(&(*object)->groupList, (void *)groupItem);
08101     groupItem = (PRV_GROUP_ITEM*)LST_Next(&(*object)->groupList);
08102     if (groupItem != 0) {
08103       elementItem = (PRV_ELEMENT_ITEM*)LST_Head(&groupItem->elementList);
08104     }
08105   }
08106 
08107   if (groupItem == 0) {
08108     *e = 0;
08109     return DCM_GETNEXTELEMENTCOMPLETE;
08110   }
08111 
08112   (*object)->groupCtx = groupItem;
08113   (*object)->elementCtx = elementItem;
08114 
08115   if (elementItem == 0)
08116     return DCM_GetNextElement(callerObject, e);
08117 
08118   *e = &elementItem->element;
08119   return DCM_NORMAL;
08120 }
08121 
08122 CONDITION
08123 DCM_AddFragment(DCM_OBJECT** callerObject, void* fragment, U32 fragmentLength)
08124 {
08125   PRIVATE_OBJECT** object;
08126   PRV_ELEMENT_ITEM* elementItem;
08127   PRV_ELEMENT_ITEM* newItem;
08128   CONDITION cond;
08129   PRV_GROUP_ITEM *groupItem = 0;
08130   DCM_FRAGMENT_ITEM* fragmentItem;
08131   U32 mallocLength;
08132 
08133   if ((fragmentLength & 1) != 0) {
08134     return COND_PushCondition(DCM_UNEVENFRAGMENTLENGTH,
08135          DCM_Message(DCM_UNEVENFRAGMENTLENGTH), fragmentLength, "DCM_AddFragment");
08136   }
08137 
08138   object = (PRIVATE_OBJECT **) callerObject;
08139   cond = checkObject(object, "DCM_AddFragment");
08140   if (cond != DCM_NORMAL)
08141     return cond;
08142 
08143   cond = findCreateGroup(object, 0x7fe0, &groupItem);
08144   if (cond != DCM_NORMAL)
08145     return COND_PushCondition(DCM_INSERTFAILED,
08146          DCM_Message(DCM_INSERTFAILED), 0x7fe0, 0x0010, "DCM_AddFragment");
08147 
08148   elementItem = locateElement(object, 0x7fe00010);
08149   if (elementItem == NULL) {
08150     DCM_ELEMENT e;
08151     memset(&e, 0, sizeof(e));
08152     e.tag = DCM_PXLPIXELDATA;
08153     e.representation = DCM_OB;
08154     e.multiplicity = 1;
08155     e.length = 0;
08156     e.d.fragments = 0;
08157     cond = newElementItem(&e, FALSE, &newItem);
08158     if (cond != DCM_NORMAL)
08159       return cond;
08160     newItem->element.d.fragments = LST_Create();
08161     if (newItem->element.d.fragments == NULL) {
08162       return COND_PushCondition(DCM_LISTFAILURE,
08163                 DCM_Message(DCM_LISTFAILURE), "DCM_AddFragment");
08164     }
08165     cond = insertThisElementItem(object, newItem);
08166     if (cond != DCM_NORMAL)
08167       return cond;
08168   }
08169 
08170   elementItem = locateElement(object, 0x7fe00010);
08171 
08172   mallocLength = sizeof(DCM_FRAGMENT_ITEM) + fragmentLength;
08173   fragmentItem = CTN_MALLOC(mallocLength);
08174   if (fragmentItem == NULL) {
08175     return COND_PushCondition(DCM_MALLOCFAILURE,
08176                                 DCM_Message(DCM_MALLOCFAILURE), mallocLength,
08177                                 "DCM_AddFragment");
08178   }
08179 
08180   fragmentItem->fragment = ((char*)fragmentItem)+ sizeof(DCM_FRAGMENT_ITEM);
08181   fragmentItem->length = fragmentLength;
08182   memcpy(fragmentItem->fragment, fragment, fragmentLength);
08183   elementItem->fragmentFlag = 1;
08184   LST_Enqueue(&elementItem->element.d.fragments, (void *)fragmentItem);
08185 
08186   return DCM_NORMAL;
08187 }
08188 /*
08189           Copyright (C) 1993, 1994, RSNA and Washington University
08190 
08191           The software and supporting documentation for the Radiological
08192           Society of North America (RSNA) 1993, 1994 Digital Imaging and
08193           Communications in Medicine (DICOM) Demonstration were developed
08194           at the
08195                   Electronic Radiology Laboratory
08196                   Mallinckrodt Institute of Radiology
08197                   Washington University School of Medicine
08198                   510 S. Kingshighway Blvd.
08199                   St. Louis, MO 63110
08200           as part of the 1993, 1994 DICOM Central Test Node project for, and
08201           under contract with, the Radiological Society of North America.
08202 
08203           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
08204           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
08205           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
08206           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
08207           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
08208           THE SOFTWARE IS WITH THE USER.
08209 
08210           Copyright of the software and supporting documentation is
08211           jointly owned by RSNA and Washington University, and free access
08212           is hereby granted as a license to use this software, copy this
08213           software and prepare derivative works based upon this software.
08214           However, any distribution of this software source code or
08215           supporting documentation or derivative works (source code and
08216           supporting documentation) must include the three paragraphs of
08217           the copyright notice.
08218 */
08219 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
08220 
08221 /*
08222 **                              DICOM 93
08223 **                   Electronic Radiology Laboratory
08224 **                 Mallinckrodt Institute of Radiology
08225 **              Washington University School of Medicine
08226 **
08227 ** Module Name(s):      DCM_Message
08228 ** Author, Date:        Stephen M. Moore, 27-Apr-93
08229 ** Intent:              Define the ASCIZ messages that go with each DCM
08230 **                      error number and provide a function for looking up
08231 **                      the error message.
08232 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
08233 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
08234 ** Revision:            $Revision: 1.21 $
08235 ** Status:              $State: Exp $
08236 */
08237 
08238 typedef struct vector {
08239     CONDITION cond;
08240     char *message;
08241 }   VECTOR;
08242 
08243 static VECTOR messageVector[] = {
08244     {DCM_NORMAL, "Normal return from DCM routine"},
08245     {DCM_FILEOPENFAILED, "DCM failed to open file: %s in %s"},
08246     {DCM_FILEACCESSERROR, "DCM failed to access file: %s in %s"},
08247     {DCM_OBJECTCREATEFAILED, "DCM failed to create object in %s"},
08248     {DCM_NULLOBJECT, "NULL object passed to routine %s"},
08249     {DCM_ILLEGALOBJECT, "Illegal object passed to routine %s"},
08250     {DCM_ELEMENTNOTFOUND, "Requested element (%x %x) not found in %s"},
08251     {DCM_ILLEGALSTREAMLENGTH,
08252     "DCM Illegal Stream Length (%ld) (Not enough data to define a full element) in %s"},
08253     {DCM_ELEMENTCREATEFAILED, "DCM failed to create element in %s (%04x %04x %d)"},
08254     {DCM_UNRECOGNIZEDGROUP, "DCM unrecognized group: %04x in %s"},
08255     {DCM_UNRECOGNIZEDELEMENT, "DCM unrecognized element: (%04x %04x) in %s"},
08256     {DCM_ELEMENTOUTOFORDER, "DCM group/element out of order (%04x %04x) in %s"},
08257     {DCM_LISTFAILURE, "DCM routine failed on list operation in %s"},
08258     {DCM_ILLEGALOPTION, "DCM illegal stream option: %s"},
08259     {DCM_ILLEGALADD, "DCM attempt to add illegal element: %x %x in %s"},
08260     {DCM_GETINCOMPLETE, "DCM Get Element incomplete in %s"},
08261     {DCM_ILLEGALCONTEXT, "DCM Illegal context value in %s"},
08262     {DCM_ILLEGALREPRESENTATION,
08263     "DCM Caller specified illegal representation for element (%04x %04x) in %s"},
08264     {DCM_UNEVENELEMENTLENGTH,
08265     "DCM attempt to add data element (%x %x) with uneven length (%ld)  in %s"},
08266     {DCM_ELEMENTLENGTHERROR,
08267     "DCM Data Element (%04x %04x) longer (%ld) than remaining length (%ld) of \
08268 data in stream or file in %s"},
08269     {DCM_GROUPNOTFOUND, "Requested group (%x) not found in %s"},
08270     {DCM_FILECREATEFAILED, "DCM failed to create file %s (%s)"},
08271     {DCM_FILEIOERROR, "DCM io error on file %s (%s)"},
08272     {DCM_INSERTFAILED,
08273     "DCM failed to insert new element (%04x %04x) in %s"},
08274     {DCM_CANNOTGETSEQUENCEVALUE,
08275     "DCM Cannot retrieve value of element with SQ representation (%08x) in (%s)"},
08276     {DCM_FILEDELETEFAILED, "DCM Failed to delete file %s in %s"},
08277     {DCM_MALLOCFAILURE, "DCM Failed to malloc %ld bytes in %s"},
08278     {DCM_NULLADDRESS, "DCM NULL address passed to routine %s"},
08279     {DCM_UNEXPECTEDREPRESENTATION,
08280     "DCM Routine %s expected %s representation for element %04x %04x"},
08281     {DCM_BADELEMENTINGROUP,
08282     "DCM Bad element (%04x %04x) found in group %04x in %s"},
08283     {DCM_CALLBACKABORTED, "DCM Callback aborted by user in %s"},
08284     {DCM_READSTREAMFAILED, "DCM Failed to read stream in %s"},
08285     {DCM_UNRECOGNIZEDVRCODE, "DCM Unrecognized VR code (%s) in %s"},
08286     {DCM_VRMISMATCH, "DCM Incorrect VR (%s) for attribute with tag %08x"},
08287     {DCM_EXPORTBUFFERTOOSMALL,
08288     "DCM Caller's export buffer length (%d) is too short in %s"},
08289     {DCM_BADOFFSET,
08290     "DCM Offset value (%d) larger than attribute length (%d) in %s"},
08291     {DCM_BADLENGTH,
08292     "DCM Combination of offset, length (%d %d) is longer than element length (%d) in %s"},
08293     {DCM_NOTASEQUENCE,
08294     "DCM Attempt to perform sequence operation on element (%04x %04x) not a sequence in %s"},
08295     {DCM_GENERALWARNING, "DCM General warning in %s: %s"},
08296     {DCM_UNEVENFRAGMENTLENGTH,
08297     "DCM attempt to add fragment with uneven length (%ld) in %s"},
08298     {0, NULL}
08299 
08300 };
08301 
08302 
08303 /* DCM_Message
08304 **
08305 ** Purpose:
08306 **      Find the ASCIZ message that goes with an DCM error number and
08307 **      return a pointer to static memory containing that error message.
08308 **
08309 ** Parameter Dictionary:
08310 **      condition       The error condition for which the message is to be
08311 **                      returned
08312 **
08313 ** Return Values:
08314 **      The error message if a valid error condition was reported else NULL.
08315 **
08316 ** Algorithm:
08317 **      Description of the algorithm (optional) and any other notes.
08318 */
08319 
08320 char *
08321 DCM_Message(CONDITION condition)
08322 {
08323     int
08324         index;
08325 
08326     for (index = 0; messageVector[index].message != NULL; index++)
08327         if (condition == messageVector[index].cond)
08328             return messageVector[index].message;
08329 
08330     return NULL;
08331 }
08332 
08333 DCM_DumpVector()
08334 {
08335     int index;
08336 
08337     for (index = 0; index < (int) DIM_OF(messageVector); index++) {
08338         if (messageVector[index].message != NULL)
08339             RWC_printf("%8x %8d %s\n", messageVector[index].cond,
08340                    messageVector[index].cond,
08341                    messageVector[index].message);
08342     }
08343 }
08344 /*
08345           Copyright (C) 1993, 1994, RSNA and Washington University
08346 
08347           The software and supporting documentation for the Radiological
08348           Society of North America (RSNA) 1993, 1994 Digital Imaging and
08349           Communications in Medicine (DICOM) Demonstration were developed
08350           at the
08351                   Electronic Radiology Laboratory
08352                   Mallinckrodt Institute of Radiology
08353                   Washington University School of Medicine
08354                   510 S. Kingshighway Blvd.
08355                   St. Louis, MO 63110
08356           as part of the 1993, 1994 DICOM Central Test Node project for, and
08357           under contract with, the Radiological Society of North America.
08358 
08359           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
08360           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
08361           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
08362           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
08363           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
08364           THE SOFTWARE IS WITH THE USER.
08365 
08366           Copyright of the software and supporting documentation is
08367           jointly owned by RSNA and Washington University, and free access
08368           is hereby granted as a license to use this software, copy this
08369           software and prepare derivative works based upon this software.
08370           However, any distribution of this software source code or
08371           supporting documentation or derivative works (source code and
08372           supporting documentation) must include the three paragraphs of
08373           the copyright notice.
08374 */
08375 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
08376 
08377 /*
08378 **                              DICOM 93
08379 **                   Electronic Radiology Laboratory
08380 **                 Mallinckrodt Institute of Radiology
08381 **              Washington University School of Medicine
08382 **
08383 ** Module Name(s):      DCM_LookupElement(DCM_ELEMENT *element)
08384 ** Author, Date:        Stephen M. Moore, 30-Apr-93
08385 ** Intent:              This module contains the routine and data which
08386 **                      define the DICOM data dictionary.  A number of
08387 **                      static objects are maintained which define how
08388 **                      elements in the DICOM V3.0 standard are to be
08389 **                      interpreted.
08390 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
08391 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
08392 ** Revision:            $Revision: 1.21 $
08393 ** Status:              $State: Exp $
08394 */
08395 
08396 /*  The DCM dictionary consists of a list of lists.  Each group (COMMAND,
08397 **  IMAGE, ...) is defined in a list separately.  The object DCMDICT
08398 **  below is used to define the entry for a single data element in a
08399 **  known group.  We define the fields:
08400 **      element
08401 **      representation
08402 **      english Description
08403 **  The outer layer DCM dictionary consists of a list of groups.  The
08404 **  group entries define the "group" number and give a pointer to the
08405 **  DCMDICT list for that group.  The intent is to search the outer layer
08406 **  dictionary to find the proper group, then search the particular group
08407 **  list to find the proper element.
08408 */
08409 typedef struct {
08410     DCM_TAG tag;
08411     DCM_VALUEREPRESENTATION representation;
08412     char englishDescription[48];
08413 }   DCMDICT;
08414 
08415 typedef struct {
08416     unsigned short group;
08417     unsigned long entries;
08418     DCMDICT *dict;
08419 }   GROUPPTR;
08420 
08421 
08422 /*  Define the entries for the COMMAND group
08423 */
08424 static DCMDICT CMD_dictionary[] = {
08425     {DCM_CMDGROUPLENGTH, DCM_UL, "CMD Group Length"},
08426     {DCM_CMDAFFECTEDCLASSUID, DCM_UI, "CMD Affected SOP Class UID"},
08427     {DCM_CMDREQUESTEDCLASSUID, DCM_UI, "CMD Requested SOP Class UID"},
08428     {DCM_CMDCOMMANDFIELD, DCM_US, "CMD Command Field"},
08429     {DCM_CMDMSGID, DCM_US, "CMD Message ID"},
08430     {DCM_CMDMSGIDRESPOND, DCM_US, "CMD Message ID Responded to"},
08431     {DCM_CMDMOVEDESTINATION, DCM_AE, "CMD Move Destination"},
08432     {DCM_CMDPRIORITY, DCM_US, "CMD Priority"},
08433     {DCM_CMDDATASETTYPE, DCM_US, "CMD Data Set Type"},
08434     {DCM_CMDSTATUS, DCM_US, "CMD Status"},
08435     {DCM_CMDOFFENDINGELEMENT, DCM_AT, "CMD Offending Element"},
08436     {DCM_CMDERRORCOMMENT, DCM_LO, "CMD Error Comment"},
08437     {DCM_CMDERRORID, DCM_US, "CMD Error ID"},
08438     {DCM_CMDREQUESTEDINSTANCEUID, DCM_UI, "CMD SOP Requested Instance UID"},
08439     {DCM_CMDAFFECTEDINSTANCEUID, DCM_UI, "CMD SOP Affected Instance UID"},
08440     {DCM_CMDEVENTTYPEID, DCM_US, "CMD Event Type ID"},
08441     {DCM_CMDACTIONTYPEID, DCM_US, "CMD Action Type ID"},
08442     {DCM_CMDREMAININGSUBOPERATIONS, DCM_US, "CMD Remaining Suboperations"},
08443     {DCM_CMDCOMPLETEDSUBOPERATIONS, DCM_US, "CMD Completed Suboperations"},
08444     {DCM_CMDFAILEDSUBOPERATIONS, DCM_US, "CMD Failed Suboperations"},
08445     {DCM_CMDWARNINGSUBOPERATIONS, DCM_US, "CMD Warning Suboperations"},
08446     {DCM_CMDMOVEAETITLE, DCM_AE, "CMD AE Title"},
08447     {DCM_CMDMOVEMESSAGEID, DCM_US, "CMD Message ID"},
08448     {DCM_CMDATTRIBUTEIDLIST, DCM_AT, "CMD Attribute Identifier List"},
08449 
08450 };
08451 
08452 /* Define the entries for the file Meta Header group
08453 */
08454 
08455 static DCMDICT META_dictionary[] = {
08456     {DCM_METAGROUPLENGTH, DCM_UL, "META Group Length"},
08457     {DCM_METAINFORMATIONVERSION, DCM_OB, "META File Meta Information Version"},
08458     {DCM_METAMEDIASTORAGESOPCLASS, DCM_UI, "META Media Stored SOP Class UID"},
08459     {DCM_METAMEDIASTORAGESOPINSTANCE, DCM_UI, "META Media Stored SOP Instance UID"},
08460     {DCM_METATRANSFERSYNTAX, DCM_UI, "META Transfer Syntax UID"},
08461     {DCM_METAIMPLEMENTATIONCLASS, DCM_UI, "META Implementation Class UID"},
08462     {DCM_METAIMPLEMENTATIONVERSION, DCM_SH, "META Implementation Version Name"},
08463     {DCM_METASOURCEAETITLE, DCM_AE, "META Source Application Entity Title"},
08464     {DCM_METAPRIVATEINFORMATIONCREATOR, DCM_UI, "META Private Information Creator"},
08465     {DCM_METAPRIVATEINFORMATION, DCM_OB, "META Private Information"}
08466 };
08467 
08468 /* Define the elements in the Basic Directory Information Group, 0x0004 */
08469 
08470 static DCMDICT BASICDIR_dictionary[] = {
08471     {DCM_DIRFILESETID, DCM_CS, "DIR File-set ID"},
08472     {DCM_DIRFILESETDESCRFILEID, DCM_CS, "DIR File-set descriptor ID"},
08473     {DCM_DIRSPECIFICCHARACTER, DCM_CS, "DIR Specific character set"},
08474     {DCM_DIRFIRSTOFFSET, DCM_UL, "DIR Offset of the first dir of root dir entity"},
08475     {DCM_DIRLASTOFFSET, DCM_UL, "DIR Offset of the last dir of root dir entity"},
08476     {DCM_DIRFILESETCONSISTENCY, DCM_US, "DIR File-set consistency flag"},
08477     {DCM_DIRRECORDSEQUENCE, DCM_SQ, "DIR Directory record sequence"},
08478     {DCM_DIRNEXTRECORDOFFSET, DCM_UL, "DIR Offset of next directory record"},
08479     {DCM_DIRRECORDINUSE, DCM_US, "DIR Record in use flag"},
08480     {DCM_DIRLOWERLEVELOFFSET, DCM_UL, "DIR Offset of referenced lower-level dir entity"},
08481     {DCM_DIRRECORDTYPE, DCM_CS, "DIR Directory Record Type"},
08482     {DCM_DIRPRIVATERECORDUID, DCM_UI, "DIR Private Record UID"},
08483     {DCM_DIRREFERENCEDFILEID, DCM_CS, "DIR Referenced File ID"},
08484     {DCM_DIRMRDRRECORDOFFSET, DCM_UL, "DIR Directory Record Offset"},
08485     {DCM_DIRREFSOPCLASSUID, DCM_UI, "DIR Referenced SOP Class UID in File"},
08486     {DCM_DIRREFSOPINSTANCEUID, DCM_UI, "DIR Referenced SOP Instance UID in File"},
08487     {DCM_DIRREFTRANSFERSYNTAXUID, DCM_UI, "DIR Referenced Transfer Syntax in File"},
08488     {DCM_DIRNUMREFERENCES, DCM_UL, "DIR Number of References"}
08489 };
08490 
08491 /* Define the entries for the IDENTIFYING group
08492 */
08493 static DCMDICT ID_dictionary[] = {
08494     {DCM_IDGROUPLENGTH, DCM_UL, "ID Group Length"},
08495 /*    {DCM_IDLENGTHTOEND, DCM_RET, "ID Length to End (RET)"}, */
08496     {DCM_IDLENGTHTOEND, DCM_UL, "ID Length to End (RET)"},
08497     {DCM_IDSPECIFICCHARACTER, DCM_CS, "ID Specific Character Set"},
08498     {DCM_IDIMAGETYPE, DCM_CS, "ID Image Type"},
08499     {DCM_IDRECOGNITIONCODE, DCM_RET, "ID Recognition Code (RET)"},
08500     {DCM_IDINSTANCECREATEDATE, DCM_DA, "ID Instance Creation Date"},
08501     {DCM_IDINSTANCECREATETIME, DCM_TM, "ID Instance Creation Time"},
08502     {DCM_IDINSTANCECREATORUID, DCM_UI, "ID Instance Creator UID"},
08503     {DCM_IDSOPCLASSUID, DCM_UI, "ID SOP Class UID"},
08504     {DCM_IDSOPINSTANCEUID, DCM_UI, "ID SOP Instance UID"},
08505     {DCM_IDSTUDYDATE, DCM_DA, "ID Study Date"},
08506     {DCM_IDSERIESDATE, DCM_DA, "ID Series Date"},
08507     {DCM_IDACQUISITIONDATE, DCM_DA, "ID Acquisition Date"},
08508     {DCM_IDIMAGEDATE, DCM_DA, "ID Image Date"},
08509     {DCM_IDOVERLAYDATE, DCM_DA, "ID Overlay Date"},
08510     {DCM_IDCURVEDATE, DCM_DA, "ID Curve Date"},
08511     {DCM_IDSTUDYTIME, DCM_TM, "ID Study Time"},
08512     {DCM_IDSERIESTIME, DCM_TM, "ID Series Time"},
08513     {DCM_IDACQUISITIONTIME, DCM_TM, "ID Acquisition Time"},
08514     {DCM_IDIMAGETIME, DCM_TM, "ID Image Time"},
08515     {DCM_IDOVERLAYTIME, DCM_TM, "ID Overlay Time"},
08516     {DCM_IDCURVETIME, DCM_TM, "ID Curve Time"},
08517     {DCM_IDDATASETTYPE, DCM_RET, "ID Data Set Type (RET)"},
08518     {DCM_IDDATASETSUBTYPE, DCM_RET, "ID Data Set Subtype (RET)"},
08519     {DCM_IDNMSERIESTYPE, DCM_CS, "ID Nuc Med Series Type (RET)"},
08520     {DCM_IDACCESSIONNUMBER, DCM_SH, "ID Accession Number"},
08521     {DCM_IDQUERYLEVEL, DCM_CS, "ID Query Level"},
08522     {DCM_IDRETRIEVEAETITLE, DCM_AE, "ID Retrieve AE Title"},
08523     {DCM_IDINSTANCEAVAILABILITY, DCM_CS, "ID Instance Availability"},
08524     {DCM_IDFAILEDINSTANCEUIDLIST, DCM_UI, "ID Failed SOP Instances"},
08525     {DCM_IDMODALITY, DCM_CS, "ID Modality"},
08526     {DCM_IDMODALITIESINSTUDY, DCM_CS, "ID Modalities in Study"},
08527     {DCM_IDMODALITYSUBTYPE, DCM_SQ, "ID Modality Subtype"},     /* Sup 30 0.6 */
08528     {DCM_IDPRESENTATIONINTENTTYPE, DCM_CS, "ID Presentation Intent Type"},
08529     {DCM_IDCONVERSIONTYPE, DCM_CS, "ID Conversion Type"},
08530     {DCM_IDMANUFACTURER, DCM_LO, "ID Manufacturer"},
08531     {DCM_IDINSTITUTIONNAME, DCM_LO, "ID Institution Name"},
08532     {DCM_IDINSTITUTIONADDR, DCM_ST, "ID Institution Address"},
08533     {DCM_IDINSTITUTECODESEQUENCE, DCM_SQ, "ID Institution Code Sequence"},
08534     {DCM_IDREFERRINGPHYSICIAN, DCM_PN, "ID Referring Physician's Name"},
08535     {DCM_IDREFERRINGPHYSADDR, DCM_ST, "ID Referring Physician's Address"},
08536     {DCM_IDREFERRINGPHYSPHONE, DCM_SH, "ID Referring Physician's Telephone"},
08537     {DCM_IDCODEVALUE, DCM_SH, "ID Code Value"},
08538     {DCM_IDCODINGSCHEMEDESIGNATOR, DCM_SH, "ID Coding Scheme Designator"},
08539     {DCM_IDCODINGSCHEMEVERSION, DCM_SH, "ID Coding Scheme Version"},
08540     /* Sup 15, Version 1.2_interim_971226 */
08541     {DCM_IDCODEMEANING, DCM_LO, "ID Code Meaning"},
08542     {DCM_IDMAPPINGRESOURCE, DCM_CS, "ID Mapping Resource"},     /* Sup 15, 1.1a */
08543     {DCM_IDCONTEXTGROUPVERSION, DCM_DT, "ID Context Group Version"},
08544     /* Sup 15, Version 1.1a */
08545     {DCM_IDCODESETEXTENSIONFLAG, DCM_CS, "ID Code Set Extension Flag"},
08546     /* 0x010B: Sup 15, Version 1.a */
08547     {DCM_IDPRIVATECODINGSCHEMECREATORUID, DCM_UI, "ID Private Coding Scheme Creator UID"},
08548     /* 0x010C: Sup 15, Version 1.1 */
08549     {DCM_IDCODESETEXTENSIONCREATORUID, DCM_UI, "ID Coding Scheme Creator UID"},
08550     /* 0x010D: Sup 15, Version 1.1 */
08551     {DCM_IDMAPPINGRESOURCESEQ, DCM_SQ, "ID Mapping Resource Sequence"},
08552     /* Sup 15, Version 1.1 */
08553     {DCM_IDCONTEXTIDENTIFIER, DCM_CS, "ID Context Identifier"}, /* Sup 15 */
08554     {DCM_IDNETWORKID, DCM_LO, "ID Network ID (RET)"},
08555     {DCM_IDSTATIONNAME, DCM_SH, "ID Station Name"},
08556     {DCM_IDSTUDYDESCRIPTION, DCM_LO, "ID Study Description"},
08557     {DCM_IDPROCEDURECODESEQUENCE, DCM_SQ, "ID Procedure Code Sequence"},
08558     {DCM_IDSERIESDESCR, DCM_LO, "ID Series Description"},
08559     {DCM_IDINSTITUTIONALDEPT, DCM_LO, "ID Institutional Department Name"},
08560     {DCM_IDPHYSICIANOFRECORD, DCM_PN, "ID Physician of Record"},
08561     {DCM_IDPERFORMINGPHYSICIAN, DCM_PN, "ID Performing Physician's Name"},
08562     {DCM_IDPHYSREADINGSTUDY, DCM_PN, "ID Name of Physician(s) Reading Study"},
08563     {DCM_IDOPERATORNAME, DCM_PN, "ID Operator's Name"},
08564     {DCM_IDADMITTINGDIAGDESCR, DCM_LO, "ID Admitting Diagnoses Description"},
08565     {DCM_IDADMITDIAGCODESEQUENCE, DCM_SQ, "ID Admitting Diagnosis Code Sequence"},
08566     {DCM_IDMANUFACTURERMODEL, DCM_LO, "ID Manufacturer Model Name"},
08567     {DCM_IDREFERENCEDRESULTSSEQ, DCM_SQ, "ID Referenced Results Sequence"},
08568     {DCM_IDREFERENCEDSTUDYSEQ, DCM_SQ, "ID Referenced Study Sequence"},
08569     {DCM_IDREFERENCEDSTUDYCOMPONENTSEQ, DCM_SQ, "ID Referenced Study Component Sequence"},
08570     {DCM_IDREFERENCEDSERIESSEQ, DCM_SQ, "ID Referenced Series Sequence"},
08571     {DCM_IDREFERENCEDPATIENTSEQ, DCM_SQ, "ID Referenced Patient Sequence"},
08572     {DCM_IDREFERENCEDVISITSEQ, DCM_SQ, "ID Referenced Visit Sequence"},
08573     {DCM_IDREFERENCEDOVERLAYSEQ, DCM_SQ, "ID Referenced Overlay Sequence"},
08574     {DCM_IDREFERENCEDIMAGESEQ, DCM_SQ, "ID Referenced Image Sequence"},
08575     {DCM_IDREFERENCEDCURVESEQ, DCM_SQ, "ID Referenced Curve Sequence"},
08576     {DCM_IDREFERENCEDPREVIOUSWAVEFORM, DCM_SQ, "ID Referenced Previous Waveform"},      /* Sup 30 0.6 */
08577     {DCM_IDREFERENCEDSIMULTANEOUSWAVEFORMS, DCM_SQ, "ID Referenced Simultaneous Waveforms"},    /* Sup 30 0.6 */
08578     {DCM_IDREFERENCEDSUBSEQUENTWAVEFORM, DCM_SQ, "ID Referenced Subsequent Waveform"},  /* Sup 30 0.6 */
08579     {DCM_IDREFERENCEDSOPCLASSUID, DCM_UI, "ID Referenced SOP Class UID"},
08580     {DCM_IDREFERENCEDSOPINSTUID, DCM_UI, "ID Referenced SOP Instance UID"},
08581     {DCM_IDREFERENCEDFRAMENUMBER, DCM_IS, "ID Referenced Frame Number"},
08582     {DCM_IDTRANSACTIONUID, DCM_UI, "ID Transaction UID"},
08583     {DCM_IDFAILUREREASON, DCM_US, "ID Failure Reason"},
08584     {DCM_IDFAILEDSOPSEQUENCE, DCM_SQ, "ID Failed SOP Sequence"},
08585     {DCM_IDREFERENCEDSOPSEQUENCE, DCM_SQ, "ID Referenced SOP Sequence"},
08586     {DCM_IDLOSSYIMAGECOMPRESSION, DCM_CS, "ID Lossy Image Compression (RET)"},
08587     {DCM_IDDERIVATIONDESCR, DCM_ST, "ID Derivation Description"},
08588     {DCM_IDSOURCEIMAGESEQ, DCM_SQ, "ID Source Image Sequence"},
08589     {DCM_IDSTAGENAME, DCM_SH, "ID Stage Name"},
08590     {DCM_IDSTAGENUMBER, DCM_IS, "ID Stage Number"},
08591     {DCM_IDNUMBEROFSTAGES, DCM_IS, "ID Number of Stages"},
08592     {DCM_IDVIEWNUMBER, DCM_IS, "ID View Number"},
08593     {DCM_IDNUMBEROFEVENTTIMERS, DCM_IS, "ID Number of Event Timers"},
08594     {DCM_IDNUMBERVIEWSINSTAGE, DCM_IS, "ID Number of Views in Stage"},
08595     {DCM_IDEVENTELAPSEDTIME, DCM_DS, "ID Event Elapsed Time(s)"},
08596     {DCM_IDEVENTTIMERNAME, DCM_LO, "ID Event Event Timer Name(s)"},
08597     {DCM_IDSTARTTRIM, DCM_IS, "ID Start Trim"},
08598     {DCM_IDSTOPTRIM, DCM_IS, "ID Stop Trim"},
08599     {DCM_IDDISPLAYFRAMERATE, DCM_IS, "ID Recommended Display Frame Rate"},
08600     {DCM_IDTRANSDUCERPOSITION, DCM_CS, "ID Transducer Position (RET)"},
08601     {DCM_IDTRANSDUCERORIENTATION, DCM_CS, "ID Transducer Orientation (RET)"},
08602     {DCM_IDANATOMICSTRUCTURE, DCM_CS, "ID Anatomic Structure (RET)"},
08603     {DCM_IDANATOMICREGIONSEQUENCE, DCM_SQ, "ID Anatomic Region of Interest Sequence"},
08604     {DCM_IDANATOMICREGIONMODIFIERSEQ, DCM_SQ,
08605     "ID Anatomic Region Modifier Sequence"},
08606     {DCM_IDPRIMARYANATOMICSTRUCTURESEQ, DCM_SQ,
08607     "ID Primary Anatomic Structure Sequence"},
08608     {DCM_IDPRIMARYANATOMICSTRUCTUREMODIFIERSEQ, DCM_SQ,
08609     "ID Primary Anatomic Structure Modifier Sequence"},
08610     {DCM_IDTRANSDUCERPOSITIONSEQ, DCM_SQ, "ID Transducer Position Sequence"},
08611     {DCM_IDTRANSDUCERPOSITIONMODIFIERSEQ, DCM_SQ, "ID Transducer Position Modifer Sequence"},
08612     {DCM_IDTRANSDUCERORIENTATIONSEQ, DCM_SQ, "ID Transducer Orientation Sequence"},
08613     {DCM_IDTRANSDUCERORIENTATIONMODIFIERSEQ, DCM_SQ, "ID Transducer Orientation Modifer Sequence"},
08614     {DCM_IDCOMMENTS, DCM_RET, "ID Comments (RET)"}
08615 };
08616 
08617 /* Define the entries for the PATIENT INFORMATION group
08618 */
08619 static DCMDICT PAT_dictionary[] = {
08620     {DCM_PATGROUPLENGTH, DCM_UL, "PAT Group Length"},
08621     {DCM_PATNAME, DCM_PN, "PAT Patient Name"},
08622     {DCM_PATID, DCM_LO, "PAT Patient ID"},
08623     {DCM_ISSUERPATIENTID, DCM_LO, "PAT Issuer of Patient ID"},
08624     {DCM_PATBIRTHDATE, DCM_DA, "PAT Patient Birthdate"},
08625     {DCM_PATBIRTHTIME, DCM_TM, "PAT Patient Birth Time"},
08626     {DCM_PATSEX, DCM_CS, "PAT Patient Sex"},
08627     {DCM_PATINSURANCEPLANCODESEQ, DCM_SQ, "PAT Patient's Insurance Plan Code Sequence"},
08628     {DCM_PATOTHERIDS, DCM_LO, "PAT Other Patient IDs"},
08629     {DCM_PATOTHERNAMES, DCM_PN, "PAT Other Patient Names"},
08630     {DCM_PATBIRTHNAME, DCM_PN, "PAT Patient's Birth Name "},
08631     {DCM_PATAGE, DCM_AS, "PAT Patient Age"},
08632     {DCM_PATSIZE, DCM_DS, "PAT Patient Size"},
08633     {DCM_PATWEIGHT, DCM_DS, "PAT Patient Weight"},
08634     {DCM_PATADDRESS, DCM_LO, "PAT Patient Address"},
08635     {DCM_PATINSURANCEPLANID, DCM_RET, "PAT Insurance Plan Identifier"},
08636     {DCM_PATMOTHERBIRTHNAME, DCM_PN, "PAT Patient's Mother's Birth Name"},
08637     {DCM_PATMILITARYRANK, DCM_LO, "PAT Military Rank"},
08638     {DCM_PATBRANCHOFSERVICE, DCM_LO, "PAT Branch of Service"},
08639     {DCM_PATMEDICALRECORDLOCATOR, DCM_LO, "PAT Medical Record Locator"},
08640     {DCM_PATMEDICALALERTS, DCM_LO, "PAT Medical Alerts"},
08641     {DCM_PATCONTRASTALLERGIES, DCM_LO, "PAT Contrast Allergies"},
08642     {DCM_COUNTRYOFRESIDENCE, DCM_LO, "PAT Country of Residence"},
08643     {DCM_REGIONOFRESIDENCE, DCM_LO, "PAT Region of Residence"},
08644     {DCM_PATTELEPHONENUMBER, DCM_SH, "PAT Patient's Telephone Numbers"},
08645     {DCM_PATETHNICGROUP, DCM_SH, "PAT Ethnic Group"},
08646     {DCM_PATOCCUPATION, DCM_SH, "PAT Occupation"},
08647     {DCM_PATSMOKINGSTATUS, DCM_CS, "PAT Smoking Status"},
08648     {DCM_PATADDITIONALPATHISTORY, DCM_LT, "PAT Additional Patient History"},
08649     {DCM_PATPREGNANCYSTATUS, DCM_US, "PAT Pregnancy Status"},
08650     {DCM_PATLASTMENSTRUALDATE, DCM_DA, "PAT Last Menstrual Date"},
08651     {DCM_PATRELIGIOUSPREFERENCE, DCM_LO, "PAT Religious Preference"},
08652     {DCM_PATCOMMENTS, DCM_LT, "PAT Comments"}
08653 };
08654 
08655 /* Define the entries for the ACQUISITION group, 0018
08656 */
08657 
08658 static DCMDICT ACQ_dictionary[] = {
08659     {DCM_ACQGROUPLENGTH, DCM_UL, "ACQ Group Length"},
08660     {DCM_ACQCONTRASTBOLUSAGENT, DCM_LO, "ACQ Contrast/Bolus Agent"},
08661     {DCM_ACQCONTRASTBOLUSAGENTSEQ, DCM_SQ, "ACQ Contrast/Bolus Agent Sequence"},
08662     {DCM_ACQCONTRASTBOLUSADMINROUTESEQ, DCM_SQ, "ACQ Contrast/Bolus Administration Route Seq"},
08663     {DCM_ACQBODYPARTEXAMINED, DCM_CS, "ACQ Body Part Examined"},
08664     {DCM_ACQSCANNINGSEQUENCE, DCM_CS, "ACQ Scanning Sequence"},
08665     {DCM_ACQSEQUENCEVARIANT, DCM_CS, "ACQ Sequence Variant"},
08666     {DCM_ACQSCANOPTIONS, DCM_CS, "ACQ Scan Options"},
08667     {DCM_ACQMRACQUISITIONTYPE, DCM_CS, "ACQ MR Acquisition Type "},
08668     {DCM_ACQSEQUENCENAME, DCM_SH, "ACQ Sequence Name"},
08669     {DCM_ACQANGIOFLAG, DCM_CS, "ACQ Angio Flag"},
08670     {DCM_ACQINTERVENTIONDRUGINFOSEQ, DCM_SQ, "ACQ Intervention Drug Information Sequence"},
08671     {DCM_ACQINTERVENTIONDRUGSTOPTIME, DCM_TM, "ACQ Intervention Drug Stop Time"},
08672     {DCM_ACQINTERVENTIONDRUGDOSE, DCM_DS, "ACQ Intervention Drug Dose"},
08673     {DCM_ACQINTERVENTIONDRUGCODESEQ, DCM_SQ, "ACQ Intervention Drug Code Sequence"},
08674     {DCM_ACQADDITIONALDRUGSEQ, DCM_SQ, "ACQ Additional Drug Sequence"},
08675     {DCM_ACQRADIONUCLIDE, DCM_LO, "ACQ Radionuclide (RET)"},
08676     {DCM_ACQRADIOPHARMACEUTICAL, DCM_LO, "ACQ Radiopharmaceutical"},
08677     {DCM_ACQENERGYWCENTERLINE, DCM_DS, "ACQ Energy Window Centerline (RET)"},
08678     {DCM_ACQENERGYWTOTALWIDTH, DCM_DS, "ACQ Energy Window Total Width (RET)"},
08679     {DCM_ACQINTERVENTIONDRUGNAME, DCM_LO, "ACQ Intervention Drug Name"},
08680     {DCM_ACQINTERVENTIONDRUGSTART, DCM_TM, "ACQ Intervention Drug Start Time"},
08681     {DCM_ACQINTERVENTIONALTHERAPYSEQ, DCM_SQ, "ACQ Interventional Therapy Sequence"},
08682     {DCM_ACQTHERAPYTYPE, DCM_CS, "ACQ Therapy type"},
08683     {DCM_ACQINTERVENTIONALSTATUS, DCM_CS, "ACQ Interventional status"},
08684     {DCM_ACQTHERAPYDESCRIPTION, DCM_CS, "ACQ Therapy descriptionm"},
08685     {DCM_ACQCINERATE, DCM_IS, "ACQ Cine Rate"},
08686     {DCM_ACQSLICETHICKNESS, DCM_DS, "ACQ Slice Thickness"},
08687     {DCM_ACQKVP, DCM_DS, "ACQ KVP"},
08688     {DCM_ACQCOUNTSACCUMULATED, DCM_IS, "ACQ Counts Accumulated"},
08689     {DCM_ACQTERMINATIONCONDITION, DCM_CS, "ACQ Acquisition Termination Condition"},
08690     {DCM_ACQEFFECTIVESERIESDURATION, DCM_DS, "ACQ Effective Series Duration"},
08691     {DCM_ACQSTARTCONDITION, DCM_CS, "ACQ Start Condition"},
08692     {DCM_ACQSTARTCONDITIONDATA, DCM_IS, "ACQ Start Condition Data"},
08693     {DCM_ACQTERMINATIONCONDITIONDATA, DCM_IS, "ACQ Termination Condition Data"},
08694     {DCM_ACQREPETITIONTIME, DCM_DS, "ACQ Repetition Time"},
08695     {DCM_ACQECHOTIME, DCM_DS, "ACQ Echo Time"},
08696     {DCM_ACQINVERSIONTIME, DCM_DS, "ACQ Inversion Time"},
08697     {DCM_ACQNUMBEROFAVERAGES, DCM_DS, "ACQ Number of Averages"},
08698     {DCM_ACQIMAGINGFREQUENCY, DCM_DS, "ACQ Imaging Frequency"},
08699     {DCM_ACQIMAGEDNUCLEUS, DCM_SH, "ACQ Imaged Nucleus"},
08700     {DCM_ACQECHONUMBER, DCM_IS, "ACQ Echo Number"},
08701     {DCM_ACQMAGNETICFIELDSTRENGTH, DCM_DS, "ACQ Magnetic Field Strength"},
08702     {DCM_ACQSLICESPACING, DCM_DS, "ACQ Spacing Between Slices"},
08703     {DCM_ACQPHASEENCODINGSTEPS, DCM_IS, "ACQ Number of Phase Encoding Steps"},
08704     {DCM_ACQDATACOLLECTIONDIAMETER, DCM_DS, "ACQ Data Collection Diameter"},
08705     {DCM_ACQECHOTRAINLENGTH, DCM_IS, "ACQ Echo Train Length"},
08706     {DCM_ACQPERCENTSAMPLING, DCM_DS, "ACQ Percent Sampling"},
08707     {DCM_ACQPERCENTPHASEFIELDVIEW, DCM_DS, "ACQ Percent Phase Field of View"},
08708     {DCM_ACQPIXELBANDWIDTH, DCM_DS, "ACQ Pixel Bandwidth"},
08709     {DCM_ACQDEVICESERIALNUM, DCM_LO, "ACQ Device Serial Number"},
08710     {DCM_ACQPLATEID, DCM_LO, "ACQ Plate ID"},
08711     {DCM_ACQSECONDARYCAPTUREDEVID, DCM_LO, "ACQ Secondary Capture Device ID"},
08712     {DCM_ACQDATESECONDARYCAPTURE, DCM_DA, "ACQ Date of Secondary Capture"},
08713     {DCM_ACQTIMESECONDARYCAPTURE, DCM_TM, "ACQ Time of Secondary Capture"},
08714     {DCM_ACQSECONDARYCAPTMANUFACTURER, DCM_LO,
08715     "ACQ Secondary Capture Device Manufacturer"},
08716     {DCM_ACQSECONDARYCAPTMODEL, DCM_LO, "ACQ Secondary Capture Device Model Name"},
08717     {DCM_ACQSECONDARYCAPTSOFTWAREVERSION, DCM_LO,
08718     "ACQ Secondary Capture Device Software Version"},
08719     {DCM_ACQSOFTWAREVERSION, DCM_LO, "ACQ Software Version"},
08720     {DCM_ACQVIDEOIMAGEFORMATACQ, DCM_SH, "ACQ Video Image Format Acquired"},
08721     {DCM_ACQDIGITALIMAGEFORMATACQ, DCM_LO, "ACQ Digital Image Format Acquired"},
08722     {DCM_ACQPROTOCOLNAME, DCM_LO, "ACQ Protocol Name"},
08723     {DCM_ACQCONTRASTBOLUSROUTE, DCM_LO, "ACQ Contrast/Bolus Route"},
08724     {DCM_ACQCONTRASTBOLUSVOL, DCM_DS, "ACQ Contrast/Bolus Volume"},
08725     {DCM_ACQCONTRASTBOLUSSTARTTIME, DCM_TM, "ACQ Contrast/Bolus Start Time"},
08726     {DCM_ACQCONTRASTBOLUSSTOPTIME, DCM_TM, "ACQ Contrast/Bolus Stop Time"},
08727     {DCM_ACQCONTRASTBOLUSTOTALDOSE, DCM_DS, "ACQ Contrast/Bolus Total Dose"},
08728     {DCM_ACQSYRINGECOUNTS, DCM_IS, "ACQ Syringe Counts"},
08729     {DCM_ACQCONTRASTFLOWRATE, DCM_DS, "ACQ Contrast Flow Rate (ml/sec)"},
08730     {DCM_ACQCONTRASTFLOWDURATION, DCM_DS, "ACQ Contrast Flow Duration (sec)"},
08731     {DCM_ACQCONTRASTBOLUSINGREDIENT, DCM_CS, "ACQ Contrast Bolus Ingredient"},
08732     {DCM_ACQCONTRASTBOLUSINGREDIENTCONCENTRATION, DCM_DS, "ACQ Contrast Bolus Ingredient Concentration"},
08733     {DCM_ACQSPATIALRESOLUTION, DCM_DS, "ACQ Spatial Resolution"},
08734     {DCM_ACQTRIGGERTIME, DCM_DS, "ACQ Trigger Time"},
08735     {DCM_ACQTRIGGERSRCTYPE, DCM_LO, "ACQ Trigger Source or Type"},
08736     {DCM_ACQNOMINALINTERVAL, DCM_IS, "ACQ Nominal Interval"},
08737     {DCM_ACQFRAMETIME, DCM_DS, "ACQ Frame Time"},
08738     {DCM_ACQFRAMINGTYPE, DCM_LO, "ACQ Framing Type"},
08739     {DCM_ACQFRAMETIMEVECTOR, DCM_DS, "ACQ Frame Time Vector"},
08740     {DCM_ACQFRAMEDELAY, DCM_DS, "ACQ Frame Delay"},
08741     {DCM_ACQIMAGETRIGGERDELAY, DCM_DS, "ACQ Image Trigger Delay"},      /* Sup 30 0.6 */
08742     {DCM_ACQGROUPTIMEOFFSET, DCM_DS, "ACQ Group Time Offset"},  /* Sup 30 0.6 */
08743     {DCM_ACQTRIGGERTIMEOFFSET, DCM_DS, "ACQ Trigger Time Offset"},      /* Sup 30 0.6 */
08744     {DCM_ACQSYNCTRIGGER, DCM_CS, "ACQ Synchronization Trigger"},        /* Sup 30 0.6 */
08745     {DCM_ACQSYNCFRAMEOFREFERENCE, DCM_UI, "ACQ Synchronization Frame of Reference"},    /* Sup 30 0.6 */
08746     {DCM_ACQTRIGGERSAMPLEPOSITION, DCM_UL, "ACQ Trigger Sample Position"},      /* Sup 30 0.6 */
08747     {DCM_ACQRADIOPHARMROUTE, DCM_LO, "ACQ Radiopharmaceutical Route"},
08748     {DCM_ACQRADIOPHARMVOLUME, DCM_DS, "ACQ Radiopharmaceutical Volume"},
08749     {DCM_ACQRADIOPHARMSTARTTIME, DCM_TM, "ACQ Radiopharmaceutical Start Time"},
08750     {DCM_ACQRADIOPHARMSTOPTIME, DCM_TM, "ACQ Radiopharmaceutical Stop Time"},
08751     {DCM_ACQRADIONUCLIDETOTALDOSE, DCM_DS, "ACQ Radionuclide Total Dose"},
08752     {DCM_ACQRADIONUCLIDEHALFLIFE, DCM_DS, "ACQ Radionuclide Half Life"},
08753     {DCM_ACQRADIONUCLIDEPOSITRONFRACTION, DCM_DS, "ACQ Radionuclide Positron Fraction"},
08754     {DCM_ACQRADIOPHARMACEUTICALSPECIFICACTIVITY, DCM_DS,
08755     "ACQ Radiopharmaceutical Specific Activity"},
08756     {DCM_ACQBEATREJECTIONFLAG, DCM_CS, "ACQ Beat Rejection Flag"},
08757     {DCM_ACQLOWRRVALUE, DCM_IS, "ACQ Low R-R Value"},
08758     {DCM_ACQHIGHRRVALUE, DCM_IS, "ACQ High R-R Value"},
08759     {DCM_ACQINTERVALSACQUIRED, DCM_IS, "ACQ Intervals Acquired"},
08760     {DCM_ACQINTERVALSREJECTED, DCM_IS, "ACQ Intervals Rejected"},
08761     {DCM_ACQPVCREJECTION, DCM_LO, "ACQ PVC Rejection"},
08762     {DCM_ACQSKIPBEATS, DCM_IS, "ACQ Skip Beats"},
08763     {DCM_ACQHEARTRATE, DCM_IS, "ACQ Heart Rate"},
08764     {DCM_ACQCARDIACNUMBEROFIMAGES, DCM_IS, "ACQ Cardiac Number of Images"},
08765     {DCM_ACQTRIGGERWINDOW, DCM_IS, "ACQ Trigger Window"},
08766     {DCM_ACQRECONSTRUCTIONDIAMETER, DCM_DS, "ACQ Reconstruction Diameter"},
08767     {DCM_ACQDISTANCESRCTODETECTOR, DCM_DS, "ACQ Distance Source-Detector"},
08768     {DCM_ACQDISTANCESRCTOPATIENT, DCM_DS, "ACQ Distance Source-Patient"},
08769     {DCM_ACQESTIMATEDRADIOGRAPHICMAGFACTOR, DCM_DS, "ACQ Estimated Radiographic Mag Factor"},
08770     {DCM_ACQGANTRYTILT, DCM_DS, "ACQ Gantry/Detector Tilt"},
08771     {DCM_ACQGANTRYSLEW, DCM_DS, "ACQ Gantry/Detector Slew"},
08772     {DCM_ACQTABLEHEIGHT, DCM_DS, "ACQ Table Height"},
08773     {DCM_ACQTABLETRAVERSE, DCM_DS, "ACQ Table Traverse"},
08774     {DCM_ACQTABLEMOTION, DCM_CS, "ACQ Table Motion (STATIC, DYNAMIC)"},
08775     {DCM_ACQTABLEVERTICALINCREMENT, DCM_DS, "ACQ Table Vertical Increment (mm)"},
08776     {DCM_ACQTABLELATERALINCREMENT, DCM_DS, "ACQ Table Lateral Increment (mm)"},
08777     {DCM_ACQTABLELONGITUDINALINCREMENT, DCM_DS, "ACQ Table Longitudinal Increment (mm)"},
08778     {DCM_ACQTABLEANGLE, DCM_DS, "ACQ Table Angle (relative to horizontal: deg)"},
08779     {DCM_ACQROTATIONDIRECTION, DCM_CS, "ACQ Rotation Direction"},
08780     {DCM_ACQANGULARPOSITION, DCM_DS, "ACQ Angular Position"},
08781     {DCM_ACQRADIALPOSITION, DCM_DS, "ACQ Radial Position"},
08782     {DCM_ACQSCANARC, DCM_DS, "ACQ Scan Arc"},
08783     {DCM_ACQANGULARSTEP, DCM_DS, "ACQ Angular Step"},
08784     {DCM_ACQCENTERROTATIONOFFSET, DCM_DS, "ACQ Center of Rotation Offset"},
08785     {DCM_ACQROTATIONOFFSET, DCM_DS, "ACQ Rotation Offset (RET)"},
08786     {DCM_ACQFIELDOFVIEWSHAPE, DCM_CS, "ACQ Field of View Shape"},
08787     {DCM_ACQFIELDOFVIEWDIMENSION, DCM_IS, "ACQ Field of View Dimension(s)"},
08788     {DCM_ACQEXPOSURETIME, DCM_IS, "ACQ Exposure Time"},
08789     {DCM_ACQXRAYTUBECURRENT, DCM_IS, "ACQ X-ray Tube Current"},
08790     {DCM_ACQEXPOSURE, DCM_IS, "ACQ Exposure"},
08791     {DCM_ACQAVERAGEPULSEWIDTH, DCM_DS, "ACQ Average width of X-Ray pulse (ms)"},
08792     {DCM_ACQRADIATIONSETTING, DCM_CS, "ACQ General level of X-Ray dose exposure"},
08793     {DCM_ACQRADIATIONMODE, DCM_CS, "ACQ X-Ray radiation mode (CONTINUOUS, PULSED)"},
08794     {DCM_ACQIMAGEAREADOSEPRODUCT, DCM_DS, "ACQ X-Ray dose to which patient was exposed"},
08795     {DCM_ACQFILTERTYPE, DCM_SH, "ACQ Filter Type, extremity"},
08796     {DCM_ACQTYPEOFFILTERS, DCM_LO, "ACQ Type of filter(s) inserted into X-Ray beam"},
08797     {DCM_ACQINTENSIFIERSIZE, DCM_DS, "ACQ Intensifier Size (mm)"},
08798     {DCM_ACQIMAGERPIXELSPACING, DCM_DS, "ACQ Image Pixel Spacing"},
08799     {DCM_ACQGRID, DCM_CS, "ACQ Grid (IN, NONE)"},
08800     {DCM_ACQGENERATORPOWER, DCM_IS, "ACQ Generator Power"},
08801     {DCM_ACQCOLLIMATORGRIDNAME, DCM_SH, "ACQ Collimator/Grid Name"},
08802     {DCM_ACQCOLLIMATORTYPE, DCM_CS, "ACQ Collimator Type"},
08803     {DCM_ACQFOCALDISTANCE, DCM_IS, "ACQ Focal Distance"},
08804     {DCM_ACQXFOCUSCENTER, DCM_DS, "ACQ X Focus Center"},
08805     {DCM_ACQYFOCUSCENTER, DCM_DS, "ACQ Y Focus Center"},
08806     {DCM_ACQFOCALSPOT, DCM_DS, "ACQ Focal Spot"},
08807     {DCM_ACQDATELASTCALIBRATION, DCM_DA, "ACQ Date of Last Calibration"},
08808     {DCM_ACQTIMELASTCALIBRATION, DCM_TM, "ACQ Time of Last Calibration"},
08809     {DCM_ACQCONVOLUTIONKERNEL, DCM_SH, "ACQ Convolution Kernel"},
08810     {DCM_ACQUPPERLOWERPIXELVALUES, DCM_RET, "ACQ Upper/Lower Pixel Values (RET)"},
08811     {DCM_ACQACTUALFRAMEDURATION, DCM_IS, "ACQ Actual Frame Duration"},
08812     {DCM_ACQCOUNTRATE, DCM_IS, "ACQ Count Rate"},
08813     {DCM_ACQPREFPLAYBACKSEQUENCING, DCM_US, "ACQ Preferred Playback Sequencing"},
08814     {DCM_ACQRECEIVINGCOIL, DCM_SH, "ACQ Receiving Coil"},
08815     {DCM_ACQTRANSMITTINGCOIL, DCM_SH, "ACQ Transmitting Coil"},
08816     {DCM_ACQPLATETYPE, DCM_SH, "ACQ Plate Type"},
08817     {DCM_ACQPHOSPHORTYPE, DCM_LO, "ACQ Phosphor Type"},
08818 #if STANDARD_VERSION < VERSION_APR1995
08819     {DCM_ACQSCANVELOCITY, DCM_IS, "ACQ Scan Velocity"},
08820 #else
08821     {DCM_ACQSCANVELOCITY, DCM_DS, "ACQ Scan Velocity"},
08822 #endif
08823     {DCM_ACQWHOLEBODYTECHNIQUE, DCM_CS, "ACQ Whole Body Technique"},
08824     {DCM_ACQSCANLENGTH, DCM_IS, "ACQ Scan Length"},
08825     {DCM_ACQACQUISITIONMATRIX, DCM_US, "ACQ Acquisition Matrix"},
08826     {DCM_ACQPHASEENCODINGDIRECTION, DCM_CS, "ACQ Phase Encoding Direction"},
08827     {DCM_ACQFLIPANGLE, DCM_DS, "ACQ Flip Angle"},
08828     {DCM_ACQVARIABLEFLIPANGLE, DCM_CS, "ACQ Variable Flip Angle"},
08829     {DCM_ACQSAR, DCM_DS, "ACQ SAR"},
08830     {DCM_ACQDBDT, DCM_DS, "ACQ DB/DT"},
08831     {DCM_ACQDEVICEPROCESSINGDESCR, DCM_LO, "ACQ Acquisition Device Processing Description"},
08832     {DCM_ACQDEVICEPROCESSINGCODE, DCM_LO, "ACQ Acquisition Device Processing Code"},
08833     {DCM_ACQCASSETTEORIENTATION, DCM_CS, "ACQ Cassette Orientation"},
08834     {DCM_ACQCASSETTESIZE, DCM_CS, "ACQ Cassette Size"},
08835     {DCM_ACQEXPOSURESONPLATE, DCM_US, "ACQ Exposures on Plate"},
08836     {DCM_ACQRELATIVEXRAYEXPOSURE, DCM_IS, "ACQ Relative X-ray Exposure"},
08837     {DCM_ACQCOLUMNANGULATION, DCM_CS, "ACQ Column Angulation"},
08838     {DCM_ACQTOMOLAYERHEIGHT, DCM_DS, "ACQ Tomo Layer Height (mm)"},
08839     {DCM_ACQTOMOANGLE, DCM_DS, "ACQ Tomo Angle"},
08840     {DCM_ACQTOMOTIME, DCM_DS, "ACQ Tomo Time"},
08841     {0x00181490, DCM_CS, "ACQ Tomo Type"},                      /* 2002.04.26 */
08842     {0x00181491, DCM_CS, "ACQ Tomo Class"},                     /* 2002.04.26 */
08843     {0x00181495, DCM_IS, "ACQ Number of Tomosynthesis Source Images"}, /* 2002.04.26 */
08844     {DCM_ACQPOSITIONERMOTION, DCM_CS, "ACQ Positioner Motion"},
08845     {0x00181508, DCM_CS, "ACQ Positioner Type"},                /* 2002.04.26 */
08846     {DCM_ACQPOSITIONERPRIMARYANGLE, DCM_DS, "ACQ Positioner Primary Angle"},
08847     {DCM_ACQPOSITIONERSECONDARYANGLE, DCM_DS, "ACQ Positioner Secondary Angle"},
08848     {DCM_ACQPOSITIONERPRIMARYANGLEINCR, DCM_DS, "ACQ Positioner Primary Angle Increment"},
08849     {DCM_ACQPOSITIONERSECONDARYANGLEINCR, DCM_DS, "ACQ Positioner Secondary Angle Increment"},
08850     {DCM_ACQDETECTORPRIMARYANGLE, DCM_DS, "ACQ Detector Primary Angle"},
08851     {DCM_ACQDETECTORSECONDARYANGLE, DCM_DS, "ACQ Detector Secondary Angle"},
08852     {DCM_ACQSHUTTERSHAPE, DCM_CS, "ACQ Shutter Shape"},
08853     {DCM_ACQSHUTTERLEFTVERTICALEDGE, DCM_IS, "ACQ Shutter Left Vertical Edge"},
08854     {DCM_ACQSHUTTERRIGHTVERTICALEDGE, DCM_IS, "ACQ Shutter Right Vertical Edge"},
08855     {DCM_ACQSHUTTERUPPERHORIZONTALEDGE, DCM_IS, "ACQ Shutter Upper Horizontal Edge"},
08856     {DCM_ACQSHUTTERLOWERHORIZONTALEDGE, DCM_IS, "ACQ Shutter Lower Horizontal Edge"},
08857     {DCM_ACQCENTEROFCIRCULARSHUTTER, DCM_IS, "ACQ Center of Circular Shutter"},
08858     {DCM_ACQRADIUSOFCIRCULARSHUTTER, DCM_IS, "ACQ Radius of Circular Shutter"},
08859     {DCM_ACQVERTICESOFPOLYGONALSHUTTER, DCM_IS, "ACQ Vertices of the Polygonal Shutter"},
08860     {DCM_ACQCOLLIMATORSHAPE, DCM_CS, "ACQ Collimator Shape"},
08861     {DCM_ACQCOLLIMATORLEFTVERTICALEDGE, DCM_IS, "ACQ Collimator Left Vertical Edge"},
08862     {DCM_ACQCOLLIMATORRIGHTVERTICALEDGE, DCM_IS, "ACQ Collimator Right Vertical Edge"},
08863     {DCM_ACQCOLLIMATORUPPERHORIZONTALEDGE, DCM_IS, "ACQ Collimator Upper Horizontal Edge"},
08864     {DCM_ACQCOLLIMATORLOWERHORIZONTALEDGE, DCM_IS, "ACQ Collimator Lower Horizontal Edge"},
08865     {DCM_ACQCENTEROFCIRCULARCOLLIMATOR, DCM_IS, "ACQ Center of Circular Collimator"},
08866     {DCM_ACQRADIUSOFCIRCULARCOLLIMATOR, DCM_IS, "ACQ Radius of Circular Collimator"},
08867     {DCM_ACQVERTICESOFPOLYGONALCOLLIMATOR, DCM_IS, "ACQ Vertices of the Polygonal Collimator"},
08868     {DCM_ACQACQUISITIONTIMESYNCHRONIZED, DCM_CS,
08869     "ACQ Acquisition Time Synchronized"},       /* Sup 30 0.7 */
08870     {DCM_ACQTIMESOURCE, DCM_SH, "ACQ Time Source"},     /* Sup 30 0.7 */
08871     {DCM_ACQTIMEDISTRIBUTIONPROTOCOL, DCM_CS,
08872     "ACQ Time Distribution Protocol"},  /* Sup 30 0.7 */
08873     {DCM_ACQCOMMENTS, DCM_RET, "ACQ Comments"},
08874     {DCM_ACQOUTPUTPOWER, DCM_SH, "ACQ Output Power"},
08875     {DCM_ACQTRANSDUCERDATA, DCM_LO, "ACQ Transducer Data"},
08876     {DCM_ACQFOCUSDEPTH, DCM_DS, "ACQ Focus Depth"},
08877 #if STANDARD_VERSION < VERSION_APR1995
08878     {DCM_ACQPREPROCESSINGFUNCTION, DCM_LO, "ACQ Preprocessing Function"},
08879 #else
08880     {DCM_ACQPROCESSINGFUNCTION, DCM_LO, "ACQ Processing Function"},
08881 #endif
08882     {DCM_ACQPOSTPROCESSINGFUNCTION, DCM_LO, "ACQ Postprocessing Function"},
08883     {DCM_ACQMECHANICALINDEX, DCM_DS, "ACQ Mechanical Index"},
08884     {DCM_ACQTHERMALINDEX, DCM_DS, "ACQ Thermal Index"},
08885     {DCM_ACQCRANIALTHERMALINDEX, DCM_DS, "ACQ Cranial Thermal Index"},
08886     {DCM_ACQSOFTTISSUETHERMALINDEX, DCM_DS, "ACQ Soft Tissue Thermal Index"},
08887     {DCM_ACQSOFTTISSUEFOCUSTHERMALINDEX, DCM_DS,
08888     "ACQ Soft Tissue-focus Thermal Index"},
08889     {DCM_ACQSOFTTISSUESURFACETHERMALINDEX, DCM_CS,
08890     "ACQ Soft Tissue-surface Thermal Index"},
08891     {DCM_ACQDEPTHOFSCANFIELD, DCM_IS, "ACQ Depth of Scan Field"},
08892     {DCM_ACQPATIENTPOSITION, DCM_CS, "ACQ Patient Position"},
08893     {DCM_ACQVIEWPOSITION, DCM_CS, "ACQ View Position"},
08894     {DCM_ACQIMAGETRANSFORMATIONMATRIX, DCM_DS,
08895     "ACQ Image Transformation Matrix"},
08896     {DCM_ACQIMAGETRANSLATIONVECTOR, DCM_DS,
08897     "ACQ Image Translation Vector"},
08898     {DCM_ACQSENSITIVITY, DCM_DS, "ACQ Sensitivity"},
08899     {DCM_ACQUSREGIONSEQUENCE, DCM_SQ, "ACQ Ultrasound Region Sequence"},
08900     {DCM_ACQREGIONSPATIALFORMAT, DCM_US, "ACQ Region Spatial Format"},
08901     {DCM_ACQREGIONDATATYPE, DCM_US, "ACQ Region Data Type"},
08902     {DCM_ACQREGIONFLAGS, DCM_UL, "ACQ Region Flags"},
08903     {DCM_ACQREGIONLOCATIONMINX0, DCM_UL, "ACQ Region Location Min X(0)"},
08904     {DCM_ACQREGIONLOCATIONMINY0, DCM_UL, "ACQ Region Location Min Y(0)"},
08905     {DCM_ACQREGIONLOCATIONMAXX1, DCM_UL, "ACQ Region Location Max X(1)"},
08906     {DCM_ACQREGIONLOCATIONMAXY1, DCM_UL, "ACQ Region Location Max Y(1)"},
08907     {DCM_ACQREFERENCEPIXELX, DCM_SL, "ACQ Reference Pixel X"},
08908     {DCM_ACQREFERENCEPIXELY, DCM_SL, "ACQ Reference Pixel Y"},
08909     {DCM_ACQPHYSICALUNITSXDIRECTION, DCM_US, "ACQ Physical Units X Direction"},
08910     {DCM_ACQPHYSICALUNITSYDIRECTION, DCM_US, "ACQ Physical Units Y Direction"},
08911     {DCM_ACQREFPIXELPHYSICALVALUEX, DCM_FD, "ACQ Reference Pixel Physical Value X"},
08912     {DCM_ACQREFPIXELPHYSICALVALUEY, DCM_FD, "ACQ Reference Pixel Physical Value Y"},
08913     {DCM_ACQPHYSICALDELTAX, DCM_FD, "ACQ Physical Delta X"},
08914     {DCM_ACQPHYSICALDELTAY, DCM_FD, "ACQ Physical Delta Y"},
08915     {DCM_ACQTRANSDUCERFREQUENCY, DCM_UL, "ACQ Transducer Frequency"},
08916     {DCM_ACQTRANSDUCERTYPE, DCM_CS, "ACQ Transducer Type"},
08917     {DCM_ACQPULSEREPETITIONFREQ, DCM_UL, "ACQ Pulse Repetition Frequency"},
08918     {DCM_ACQDOPPLERCORRECTIONANGLE, DCM_FD, "ACQ Doppler Correction Angle"},
08919     {DCM_ACQSTERRINGANGLE, DCM_FD, "ACQ Sterring Angle"},
08920     {DCM_ACQDOPPLERSAMPLEVOLXPOS, DCM_UL, "ACQ Doppler Sample Volume X Position"},
08921     {DCM_ACQDOPPLERSAMPLEVOLYPOS, DCM_UL, "ACQ Doppler Sample Volume Y Position"},
08922     {DCM_ACQTMLINEPOSITIONX0, DCM_UL, "ACQ TM-Line Position X(0)"},
08923     {DCM_ACQTMLINEPOSITIONY0, DCM_UL, "ACQ TM-Line Position Y(0)"},
08924     {DCM_ACQTMLINEPOSITIONX1, DCM_UL, "ACQ TM-Line Position X(1)"},
08925     {DCM_ACQTMLINEPOSITIONY1, DCM_UL, "ACQ TM-Line Position Y(1)"},
08926     {DCM_ACQPIXELCOMPORGANIZATION, DCM_US, "ACQ Pixel Component Organization"},
08927     {DCM_ACQPIXELCOMPMASK, DCM_UL, "ACQ Pixel Component Mask"},
08928     {DCM_ACQPIXELCOMPRANGESTART, DCM_UL, "ACQ Pixel Component Range Start"},
08929     {DCM_ACQPIXELCOMPRANGESTOP, DCM_UL, "ACQ Pixel Component Range Stop"},
08930     {DCM_ACQPIXELCOMPPHYSUNITS, DCM_US, "ACQ Pixel Component Physical Units"},
08931     {DCM_ACQPIXELCOMPDATATYPE, DCM_US, "ACQ Pixel Component Data Type"},
08932     {DCM_ACQNUMBERTABLEBREAKPOINTS, DCM_UL, "ACQ Number of Table Break Points"},
08933     {DCM_ACQTABLEXBREAKPOINTS, DCM_UL, "ACQ Table of X Break Points"},
08934     {DCM_ACQTABLEYBREAKPOINTS, DCM_FD, "ACQ Table of Y Break Points"},
08935     {DCM_ACQNUMBEROFTABLEENTRIES, DCM_UL, "ACQ Number of Table Entries"},
08936     {DCM_ACQTABLEOFPIXELVALUES, DCM_UL, "ACQ Table of Pixel Values"},
08937     {DCM_ACQTABLEOFPARAMETERVALUES, DCM_FL, "ACQ Table of Parameter Values"},
08938 
08939     {0x00187000, DCM_CS, "ACQ Detector Conditions Nominal Flag"}, /* 2002.04.26 */
08940     {0x00187001, DCM_DS, "ACQ Detector Temperature"},           /* 2002.04.26 */
08941     {0x00187004, DCM_CS, "ACQ Detector Type"},                  /* 2002.04.26 */
08942     {0x00187005, DCM_CS, "ACQ Detector Configuration"},         /* 2002.04.26 */
08943     {0x00187006, DCM_LT, "ACQ Detector Description"},           /* 2002.04.26 */
08944     {0x00187008, DCM_LT, "ACQ Detector Mode"},                  /* 2002.04.26 */
08945     {0x0018700A, DCM_SH, "ACQ Detector ID"},                    /* 2002.04.26 */
08946 
08947     {0x00187028, DCM_DS, "ACQ Detector Active Origin"}          /* 2002.04.26 */
08948 };
08949 
08950 /* Define the entries for the RELATIONSHIP group (0020)
08951 */
08952 static DCMDICT REL_dictionary[] = {
08953     {DCM_RELGROUPLENGTH, DCM_UL, "REL Group Length"},
08954     {DCM_RELSTUDYINSTANCEUID, DCM_UI, "REL Study Instance UID"},
08955     {DCM_RELSERIESINSTANCEUID, DCM_UI, "REL Series Instance UID"},
08956     {DCM_RELSTUDYID, DCM_SH, "REL Study ID"},
08957     {DCM_RELSERIESNUMBER, DCM_IS, "REL Series Number"},
08958     {DCM_RELACQUISITIONNUMBER, DCM_IS, "REL Acquisition Number"},
08959     {DCM_RELIMAGENUMBER, DCM_IS, "REL Instance Number"},
08960 
08961     {DCM_RELISOTOPENUMBER, DCM_IS, "REL Isotope Number (RET)"},
08962     {DCM_RELPHASENUMBER, DCM_IS, "REL Phase Number (RET)"},
08963     {DCM_RELINTERVALNUMBER, DCM_IS, "REL Interval Number (RET)"},
08964     {DCM_RELTIMESLOTNUMBER, DCM_IS, "REL Time Slot Number (RET)"},
08965     {DCM_RELANGLENUMBER, DCM_IS, "REL Angle Number (RET)"},
08966 
08967     {DCM_RELPATIENTORIENTATION, DCM_CS, "REL Patient Orientation"},
08968     {DCM_RELOVERLAYNUMBER, DCM_IS, "REL Overlay Number"},
08969     {DCM_RELCURVENUMBER, DCM_IS, "REL Curve Number"},
08970     {DCM_RELLOOKUPTABLENUMBER, DCM_IS, "REL Looup Table Number"},
08971     {DCM_RELIMAGEPOSITION, DCM_RET, "REL Image Position (RET)"},
08972     {DCM_RELIMAGEPOSITIONPATIENT, DCM_DS, "REL Image Position Patient"},
08973     {DCM_RELIMAGEORIENTATION, DCM_RET, "REL Image Orientation"},
08974     {DCM_RELIMAGEORIENTATIONPATIENT, DCM_DS, "REL Image Orientation (Patient)"},
08975     {DCM_RELLOCATION, DCM_RET, "REL Location (RET)"},
08976     {DCM_RELFRAMEOFREFERENCEUID, DCM_UI, "REL Frame of Reference UID"},
08977     {DCM_RELLATERALITY, DCM_CS, "REL Laterality"},
08978     { DCM_MAKETAG(0x0020, 0x0062), DCM_CS, "REL Image Laterality"},
08979     {DCM_RELIMAGEGEOMETRYTYPE, DCM_RET, "REL Image Geometry Type (RET)"},
08980     {DCM_RELMASKINGIMAGE, DCM_RET, "REL Masking Image (RET)"},
08981     {DCM_RELTEMPORALPOSITIONID, DCM_IS, "REL Temporal Position Identifier"},
08982     {DCM_RELNUMBERTEMPORALPOSITIONS, DCM_IS, "REL Number of Temporal Positions"},
08983     {DCM_RELTEMPORALRESOLUTION, DCM_DS, "REL Temporal Resolution"},
08984     {DCM_RELSERIESINSTUDY, DCM_IS, "REL Series in Study"},
08985     {DCM_RELACQUISITIONSINSERIES, DCM_RET, "REL Acquisitions in Series"},
08986     {DCM_RELIMAGESINACQUISITION, DCM_IS, "REL Images in Acquisition"},
08987     {DCM_RELACQUISITIONSINSTUDY, DCM_IS, "REL Acquisitions in Study"},
08988     {DCM_RELREFERENCE, DCM_RET, "REL Reference (RET)"},
08989     {DCM_RELPOSITIONREFINDICATOR, DCM_LO, "REL Position Reference Indicator"},
08990     {DCM_RELSLICELOCATION, DCM_DS, "REL Slice Location"},
08991     {DCM_RELOTHERSTUDYNUMBERS, DCM_IS, "REL Other Study Numbers"},
08992     {DCM_RELNUMBERPATRELATEDSTUDIES, DCM_IS,
08993     "REL Number of Patient Related Studies"},
08994     {DCM_RELNUMBERPATRELATEDSERIES, DCM_IS, "REL Number of Patient Related Series"},
08995     {DCM_RELNUMBERPATRELATEDIMAGES, DCM_IS, "REL Number of Patient Related Instances"},
08996     {DCM_RELNUMBERSTUDYRELATEDSERIES, DCM_IS, "REL Number of Study Related Series"},
08997     {DCM_RELNUMBERSTUDYRELATEDIMAGES, DCM_IS, "REL Number of Study Related Instances"},
08998     {DCM_RELNUMBERSERIESRELATEDINST, DCM_IS, "REL Number of Series Related Instances"},
08999     {DCM_RELSOURCEIMAGEID, DCM_RET, "REL Source Image IDs (RET)"},
09000     {DCM_RELMODIFYINGDEVICEID, DCM_RET, "REL Modifying Device ID (RET)"},
09001     {DCM_RELMODIFIEDIMAGEID, DCM_RET, "REL Modified Image ID (RET)"},
09002     {DCM_RELMODIFIEDIMAGEDATE, DCM_RET, "REL Modified Image Date (RET)"},
09003     {DCM_RELMODIFYINGDEVICEMFR, DCM_RET, "REL Modifying Device Mfr (RET)"},
09004     {DCM_RELMODIFIEDIMAGETIME, DCM_RET, "REL Modified Image Time"},
09005     {DCM_RELMODIFIEDIMAGEDESCRIPTION, DCM_RET,
09006     "REL Modified Image Description (RET)"},
09007     {DCM_RELIMAGECOMMENTS, DCM_LT, "REL Image Comments"},
09008     {DCM_RELORIGINALIMAGEID, DCM_RET, "REL Original Image ID (RET)"},
09009     {DCM_RELORIGINALIMAGEIDNOMENCLATURE, DCM_RET,
09010     "REL Orig Image ID Nomenclature (RET)"}
09011 };
09012 
09013 /* Define the entries for the IMAGE group (0028)
09014 */
09015 static DCMDICT IMG_dictionary[] = {
09016     {DCM_IMGGROUPLENGTH, DCM_UL, "IMG Group Length"},
09017     {DCM_IMGSAMPLESPERPIXEL, DCM_US, "IMG Samples Per Pixel"},
09018     {DCM_IMGPHOTOMETRICINTERP, DCM_CS, "IMG Photometric Interpretation"},
09019     {DCM_IMGIMAGEDIMENSIONS, DCM_RET, "IMG Image Dimensions (RET)"},
09020     {DCM_IMGPLANARCONFIGURATION, DCM_US, "IMG Planar Configuration"},
09021     {DCM_IMGNUMBEROFFRAMES, DCM_IS, "IMG Number of Frames"},
09022     {DCM_IMGFRAMEINCREMENTPOINTER, DCM_AT, "IMG Frame Increment Pointer"},
09023     {DCM_IMGROWS, DCM_US, "IMG Rows"},
09024     {DCM_IMGCOLUMNS, DCM_US, "IMG Columns"},
09025     {DCM_IMGPLANES, DCM_US, "IMG Planes"},
09026     {DCM_IMGUSOUNDCOLORDATAPRESENT, DCM_US, "IMG Ultrasound Color Data Present"},
09027     {DCM_IMGPIXELSPACING, DCM_DS, "IMG Pixel Spacing"},
09028     {DCM_IMGZOOMFACTOR, DCM_DS, "IMG Zoom Factor"},
09029     {DCM_IMGZOOMCENTER, DCM_DS, "IMG Zoom Center"},
09030     {DCM_IMGPIXELASPECTRATIO, DCM_IS, "IMG Pixel Aspect Ratio"},
09031     {DCM_IMGIMAGEFORMAT, DCM_RET, "IMG Image Format (RET)"},
09032     {DCM_IMGMANIPULATEDIMAGE, DCM_RET, "IMG Manipulated Image (RET)"},
09033     {DCM_IMGCORRECTEDIMAGE, DCM_CS, "IMG Corrected Image"},
09034     {DCM_IMGCOMPRESSIONCODE, DCM_RET, "IMG Compression Code"},
09035     {DCM_IMGBITSALLOCATED, DCM_US, "IMG Bits Allocated"},
09036     {DCM_IMGBITSSTORED, DCM_US, "IMG Bits Stored"},
09037     {DCM_IMGHIGHBIT, DCM_US, "IMG High Bit"},
09038     {DCM_IMGPIXELREPRESENTATION, DCM_US, "IMG Pixel Representation"},
09039     {DCM_IMGSMALLESTPIXELVALUE, DCM_RET, "IMG Smallest Pixel Value (RET)"},
09040     {DCM_IMGLARGESTPIXELVALUE, DCM_RET, "IMG Largest Pixel Vaue (RET)"},
09041     {DCM_IMGSMALLESTIMAGEPIXELVALUE, DCM_CTX, "IMG Smallest Image Pixel Value"},
09042     {DCM_IMGLARGESTIMAGEPIXELVALUE, DCM_CTX, "IMG Largest Image Pixel Value"},
09043     {DCM_IMGSMALLESTPIXELVALUESERIES, DCM_CTX, "IMG Smallest Pixel Value in Series"},
09044     {DCM_IMGLARGESTPIXELVALUESERIES, DCM_CTX, "IMG Largest Pixel Value in Series"},
09045     {DCM_IMGSMALLESTIMAGEPIXELVALUEPLANE, DCM_CTX, "IMG Smallest Pixel Value in Plane"},
09046     {DCM_IMGLARGESTIMAGEPIXELVALUEPLANE, DCM_CTX, "IMG Largest Pixel Value in Plane"},
09047     {DCM_IMGPIXELPADDINGVALUE, DCM_CTX, "IMG Pixel Padding Value"},
09048     {DCM_IMGWAVEFORMPADDINGVALUE, DCM_CTX, "IMG Waveform Padding Value"},       /* Sup 30 0.6 */
09049     {DCM_IMGIMAGELOCATION, DCM_RET, "IMG Image Location"},
09050     {DCM_MAKETAG(0x0028, 0x0300), DCM_CS, "IMG Quality Control Image"},
09051     {DCM_MAKETAG(0x0028, 0x0301), DCM_CS, "IMG Burned In Annotation"},
09052     {DCM_IMGPIXELINTENSITYRELATIONSHIP, DCM_CS, "IMG Pixel Intensity Relationship"},
09053     {DCM_MAKETAG(0x0028, 0x1041), DCM_SS, "IMG Pixel Intensity Relationship Sign"},
09054     {DCM_IMGWINDOWCENTER, DCM_DS, "IMG Window Center"},
09055     {DCM_IMGWINDOWWIDTH, DCM_DS, "IMG Window Width"},
09056     {DCM_IMGRESCALEINTERCEPT, DCM_DS, "IMG Rescale Intercept"},
09057     {DCM_IMGRESCALESLOPE, DCM_DS, "IMG Rescale Slope"},
09058     {DCM_IMGRESCALETYPE, DCM_LO, "IMG Rescale Type"},
09059     {DCM_IMGWINDOWCWEXPLANATION, DCM_LO, "IMG Window Center & Width Explanation"},
09060     {DCM_IMGGRAYSCALE, DCM_RET, "IMG Gray Scale (RET)"},
09061     {DCM_IMGRECOMMENDEDVIEWINGMODE, DCM_CS, "IMG Recommended Viewing Mode"},
09062     {DCM_IMGLUTDESCRIPTGRAY, DCM_RET, "IMG Lookup Table Desc-Gray (RET)"},
09063     {DCM_IMGLUTDESCRIPTRED, DCM_US, "IMG Lookup Table Desc-Red"},
09064     {DCM_IMGLUTDESCRIPTGREEN, DCM_US, "IMG Lookup Table Desc-Green"},
09065     {DCM_IMGLUTDESCRIPTBLUE, DCM_US, "IMG Lookup Table Desc-Blue"},
09066     {DCM_IMGPALETTECOLORLUTUID, DCM_UI, "IMG Palette Color Lookup Table UID"},
09067     {DCM_IMGLOOKUPDATAGRAY, DCM_RET, "IMG Lookup Data-Gray"},
09068 
09069 #if 0
09070     /* As originally defined in 1993 */
09071     {DCM_IMGLOOKUPDATARED, DCM_US, "IMG Lookup Data-Red"},
09072     {DCM_IMGLOOKUPDATAGREEN, DCM_US, "IMG Lookup Data-Green"},
09073     {DCM_IMGLOOKUPDATABLUE, DCM_US, "IMG Lookup Data-Blue"},
09074 #endif
09075 
09076     {DCM_IMGLOOKUPDATARED, DCM_CTX, "IMG Lookup Data-Red"},
09077     {DCM_IMGLOOKUPDATAGREEN, DCM_CTX, "IMG Lookup Data-Green"},
09078     {DCM_IMGLOOKUPDATABLUE, DCM_CTX, "IMG Lookup Data-Blue"},
09079 
09080     {DCM_IMGSEGMENTEDREDLUTDATA, DCM_OW, "IMG Segmented Red Palette Color LUT Data"},
09081     {DCM_IMGSEGMENTEDGREENLUTDATA, DCM_OW, "IMG Segmented Green Palette Color LUT Data"},
09082     {DCM_IMGSEGMENTEDBLUELUTDATA, DCM_OW, "IMG Segmented Blue Palette Color LUT Data"},
09083 
09084     {DCM_IMGLOSSYIMAGECOMPRESSION, DCM_CS, "IMG Lossy Image Compression"},
09085     {DCM_IMGMODALITYLUTSEQUENCE, DCM_SQ, "IMG Modality LUT Sequence"},
09086     {DCM_IMGLUTDESCRIPTOR, DCM_CTX, "IMG LUT Descriptor"},
09087     {DCM_IMGLUTEXPLANATION, DCM_LO, "IMG LUT Explanation"},
09088     {DCM_IMGMODALITYLUTTYPE, DCM_LO, "IMG Modality LUT Type"},
09089     {DCM_IMGLUTDATA, DCM_CTX, "IMG LUT Data"},
09090     {DCM_IMGVOILUTSEQUENCE, DCM_SQ, "IMG VOI LUT Sequence"},
09091     {DCM_IMGCOMMENTS, DCM_RET, "IMG Comments (RET)"},
09092     {DCM_IMGBIPLANEACQSEQUENCE, DCM_SQ, "IMG Bi-Plane Acquisition Sequence"},
09093     {DCM_IMGREPRESENTATIVEFRAMENUMBER, DCM_US, "IMG Representative Frame Number"},
09094     {DCM_IMGFRAMENUMBERSOFINTEREST, DCM_US, "IMG Frame Numbers of Interest"},
09095     {DCM_IMGFRAMEOFINTERESTDESCRIPTION, DCM_LO, "IMG Frame of Interest Description"},
09096     {DCM_IMGMASKPOINTER, DCM_US, "IMG Mask Pointer(s)"},
09097     {DCM_IMGRWAVEPOINTER, DCM_US, "IMG R Wave Pointer"},
09098     {DCM_IMGMASKSUBTRACTIONSEQ, DCM_SQ, "IMG Mask Subtraction Sequence"},
09099     {DCM_IMGMASKOPERATION, DCM_CS, "IMG Mask Operation"},
09100     {DCM_IMGAPPLICABLEFRAMERANGE, DCM_US, "IMG Applicable Frame Range"},
09101     {DCM_IMGMASKFRAMENUMBERS, DCM_US, "IMG Mask Frame Numbers"},
09102     {DCM_IMGCONTRASTFRAMEAVERAGING, DCM_US, "IMG Contrast Frame Averaging"},
09103     {DCM_IMGMASKSUBPIXELSHIFT, DCM_FL, "IMG Mask Sub-pixel shift"},
09104     {DCM_IMGTIDOFFSET, DCM_SS, "IMG TID Offset"},
09105     {DCM_MASKOPERATIONEXPLANATION, DCM_ST, "IMG Mask Operation Explanation"}
09106 };
09107 
09108 /* Define the entries for the STUDY group (0032)
09109 */
09110 static DCMDICT SDY_dictionary[] = {
09111     {DCM_SDYGROUPLENGTH, DCM_UL, "SDY Study Group length"},
09112     {DCM_SDYSTATUSID, DCM_CS, "SDY Study Status ID"},
09113     {DCM_SDYPRIORITYID, DCM_CS, "SDY Study Priority ID"},
09114     {DCM_SDYIDISSUER, DCM_LO, "SDY Study ID Issuer"},
09115     {DCM_SDYVERIFIEDDATE, DCM_DA, "SDY Study Verified Date"},
09116     {DCM_SDYVERIFIEDTIME, DCM_TM, "SDY Study Verified Time"},
09117     {DCM_SDYREADDATE, DCM_DA, "SDY Study Read Date"},
09118     {DCM_SDYREADTIME, DCM_TM, "SDY Study Read Time"},
09119     {DCM_SDYSCHEDULEDSTARTDATE, DCM_DA, "SDY Scheduled Study Start Date"},
09120     {DCM_SDYSCHEDULEDSTARTTIME, DCM_TM, "SDY Scheduled Study Start Time"},
09121     {DCM_SDYSCHEDULEDSTOPDATE, DCM_DA, "SDY Scheduled Study Stop Date"},
09122     {DCM_SDYSCHEDULEDSTOPTIME, DCM_TM, "SDY Scheduled Study Stop Time"},
09123     {DCM_SDYSCHEDULEDLOCATION, DCM_LO, "SDY Scheduled Study Location"},
09124     {DCM_SDYSCHEDULEDLOCATIONAETITLE, DCM_AE,
09125     "SDY Scheduled Study Location AE Title(s)"},
09126     {DCM_SDYREASON, DCM_LO, "SDY Study Reason"},
09127     {DCM_SDYREQUESTINGPHYSICIAN, DCM_PN, "SDY Requesting Physician "},
09128     {DCM_SDYREQUESTINGSERVICE, DCM_LO, "SDY Requesting Service"},
09129     {DCM_SDYARRIVALDATE, DCM_DA, "SDY Study Arrival Date"},
09130     {DCM_SDYARRIVALTIME, DCM_TM, "SDY Study Arrival Time"},
09131     {DCM_SDYCOMPLETIONDATE, DCM_DA, "SDY Study Completion Date"},
09132     {DCM_SDYCOMPLETIONTIME, DCM_TM, "SDY Study Completion Time"},
09133     {DCM_SDYSTUDYCOMPONENTSTATUSID, DCM_CS, "SDY Study Component Status ID"},
09134     {DCM_SDYREQUESTEDPRODESCRIPTION, DCM_LO, "SDY Requested Procedure Description"},
09135     {DCM_SDYREQUESTEDPROCODESEQ, DCM_SQ, "SDY Requested Procedure Code Seq"},
09136     {DCM_SDYREQUESTEDCONTRASTAGENT, DCM_LO, "SDY Requested Contrast Agent"},
09137     {DCM_SDYCOMMENTS, DCM_LT, "SDY Comments"}
09138 };
09139 
09140 /* Define the entries for the VISIT group, 0038
09141 */
09142 static DCMDICT VIS_dictionary[] = {
09143     {DCM_VISGROUPLENGTH, DCM_UL, "VIS Group Length"},
09144     {DCM_VISREFERENCEDPATALIASSEQ, DCM_SQ, "VIS Referenced Patient Alias Sequence"},
09145     {DCM_VISSTATUSID, DCM_CS, "VIS Visit Status ID"},
09146     {DCM_VISADMISSIONID, DCM_LO, "VIS Admission ID"},
09147     {DCM_VISISSUEROFADMISSIONID, DCM_LO, "VIS Issuer of Admission ID"},
09148     {DCM_VISROUTEOFADMISSION, DCM_LO, "VIS Route of Admission"},
09149     {DCM_VISSCHEDULEDADMISSIONDATE, DCM_DA, "VIS Scheduled Admission Date"},
09150     {DCM_VISSCHEDULEDADMISSIONTIME, DCM_TM, "VIS Scheduled Admission Time"},
09151     {DCM_VISSCHEDULEDDISCHARGEDATE, DCM_DA, "VIS Scheduled Discharge Date"},
09152     {DCM_VISSCHEDULEDDISCHARGETIME, DCM_TM, "VIS Scheduled Discharge Time"},
09153     {DCM_VISSCHEDULEDPATINSTRESIDENCE, DCM_LO, "VIS Scheduled Patient Institution Residence"},
09154     {DCM_VISADMITTINGDATE, DCM_DA, "VIS Admitting Date"},
09155     {DCM_VISADMITTINGTIME, DCM_TM, "VIS Admitting Time"},
09156     {DCM_VISDISCHARGEDATE, DCM_DA, "VIS Discharge Date"},
09157     {DCM_VISDISCHARGETIME, DCM_TM, "VIS Discharge Time"},
09158     {DCM_VISDISCHARGEDIAGDESCRIPTION, DCM_LO, "VIS Discharge Diagnosis Description"},
09159     {DCM_VISDISCHARGEDIAGNOSISCODESEQ, DCM_SQ, "VIS Discharge Diagnosis Code Sequence"},
09160     {DCM_VISSPECIALNEEDS, DCM_LO, "VIS Special Needs"},
09161     {DCM_VISCURRENTPATIENTLOCATION, DCM_LO, "VIS Current Patient Location"},
09162     {DCM_VISPATIENTSINSTRESIDENCE, DCM_LO, "VIS Patient's Institution Residence"},
09163     {DCM_VISPATIENTSTATE, DCM_LO, "VIS Patient State"},
09164     {DCM_VISCOMMENTS, DCM_LT, "VIS Comments"}
09165 };
09166 
09167 /* Define the entries for the Waveform group, 003a
09168 */
09169 static DCMDICT WAV_dictionary[] = {
09170     {DCM_MAKETAG(0x003a, 0x0000), DCM_UL, "WAV Group Length"},
09171     {DCM_MAKETAG(0x003a, 0x0002), DCM_SQ, "WAV Waveform Sequence"},     /* Sup 30 0.6 */
09172     {DCM_MAKETAG(0x003a, 0x0005), DCM_US, "WAV Number of Channels"},    /* Sup 30 0.6 */
09173     {DCM_MAKETAG(0x003a, 0x0010), DCM_UL, "WAV Number of Samples"},     /* Sup 30 0.6 */
09174     {DCM_MAKETAG(0x003a, 0x001a), DCM_DS, "WAV Sampling Frequency"},    /* Sup 30 0.6 */
09175     {DCM_MAKETAG(0x003a, 0x0020), DCM_SH, "WAV Group Label"},   /* Sup 30 0.6 */
09176     {DCM_MAKETAG(0x003a, 0x0103), DCM_CS, "WAV Data Value Representation"},     /* Sup 30 0.6 */
09177     {DCM_MAKETAG(0x003a, 0x0200), DCM_SQ, "WAV Channel Definition"},    /* Sup 30 0.6 */
09178     {DCM_MAKETAG(0x003a, 0x0202), DCM_IS, "WAV Channel Number"},        /* Sup 30 0.6 */
09179     {DCM_MAKETAG(0x003a, 0x0203), DCM_SH, "WAV Channel Label"}, /* Sup 30 0.6 */
09180     {DCM_MAKETAG(0x003a, 0x0205), DCM_CS, "WAV Channel Status"},        /* Sup 30 0.6 */
09181     {DCM_MAKETAG(0x003a, 0x0208), DCM_SQ, "WAV Waveform Source"},       /* Sup 30 0.6 */
09182     {DCM_MAKETAG(0x003a, 0x0209), DCM_SQ, "WAV Waveform Source Modifiers"},     /* Sup 30 0.6 */
09183     {DCM_MAKETAG(0x003a, 0x020a), DCM_SQ, "WAV Differential Waveform Source"},  /* Sup 30 0.6 */
09184     {DCM_MAKETAG(0x003a, 0x020b), DCM_SQ, "WAV Differential Waveform Source Modifiers"},        /* Sup 30 0.6 */
09185     {DCM_MAKETAG(0x003a, 0x0210), DCM_DS, "WAV Channel Sensitivity"},   /* Sup 30 0.6 */
09186     {DCM_MAKETAG(0x003a, 0x0211), DCM_SQ, "WAV Channel Sensitivity Units"},     /* Sup 30 0.6 */
09187     {DCM_MAKETAG(0x003a, 0x0212), DCM_DS, "WAV Channel Sensitivity Correction Factor"}, /* Sup 30 0.6 */
09188     {DCM_MAKETAG(0x003a, 0x0213), DCM_DS, "WAV Channel Baseline"},      /* Sup 30 0.6 */
09189     {DCM_MAKETAG(0x003a, 0x0214), DCM_DS, "WAV Channel Time Skew"},     /* Sup 30 0.6 */
09190     {DCM_MAKETAG(0x003a, 0x0215), DCM_DS, "WAV Channel Sample Skew"},   /* Sup 30 0.6 */
09191     {DCM_MAKETAG(0x003a, 0x0218), DCM_DS, "WAV Channel Offset"},        /* Sup 30 0.6 */
09192     {DCM_MAKETAG(0x003a, 0x021a), DCM_US, "WAV Bits Per Sample"},       /* Sup 30 0.6 */
09193     {DCM_MAKETAG(0x003a, 0x0216), DCM_CTX, "WAV Channel Minimum Value"},        /* Sup 30 0.6 */
09194     {DCM_MAKETAG(0x003a, 0x0217), DCM_CTX, "WAV Channel Maximum Value"},        /* Sup 30 0.6 */
09195     {DCM_MAKETAG(0x003a, 0x0220), DCM_DS, "WAV Filter Low Frequency"},  /* Sup 30 0.6 */
09196     {DCM_MAKETAG(0x003a, 0x0221), DCM_DS, "WAV Filter High Frequency"}, /* Sup 30 0.6 */
09197     {DCM_MAKETAG(0x003a, 0x0222), DCM_DS, "WAV Notch Filter Frequency"},        /* Sup 30 0.6 */
09198     {DCM_MAKETAG(0x003a, 0x0223), DCM_DS, "WAV Notch Filter Bandwidth"},        /* Sup 30 0.6 */
09199     {DCM_MAKETAG(0x003a, 0x1000), DCM_CTX, "WAV Waveform Data"} /* Sup 30 0.6 */
09200 };
09201 
09202 /* Define the entries for the Procedure Step group, 0040
09203 */
09204 
09205 static DCMDICT PRC_dictionary[] = {
09206     {DCM_PRCGROUPLENGTH, DCM_UL, "PRC Group Length"},
09207     {DCM_PRCSCHEDULEDSTATIONAETITLE, DCM_AE, "PRC Scheduled Station AE Title"},
09208     {DCM_PRCSCHEDULEDPROCSTEPSTARTDATE, DCM_DA, "PRC Scheduled Procedure Step Start Date"},
09209     {DCM_PRCSCHEDULEDPROCSTEPSTARTTIME, DCM_TM, "PRC Scheduled Procedure Step Start Time"},
09210     {DCM_PRCSCHEDULEDPROCSTEPENDDATE, DCM_DA, "PRC Scheduled Procedure Step End Date"},
09211     {DCM_PRCSCHEDULEDPROCSTEPENDTIME, DCM_TM, "PRC Scheduled Procedure Step End Time"},
09212     {DCM_PRCSCHEDULEDPERFORMINGPHYSNAME, DCM_PN, "PRC Scheduled Performing Physician's Name"},
09213     {DCM_PRCSCHEDULEDPROCSTEPDESCRIPTION, DCM_LO, "PRC Scheduled Step Description"},
09214     {DCM_PRCSCHEDULEDACTIONITEMCODESEQ, DCM_SQ, "PRC Scheduled Action Item Code Sequence"},
09215     {DCM_PRCSCHEDULEDPROCSTEPID, DCM_SH, "PRC Scheduled Procedure Step ID"},
09216     {DCM_PRCSCHEDULEDSTATIONNAME, DCM_SH, "PRC Scheduled Station Name"},
09217     {DCM_PRCSCHEDULEDPROCSTEPLOCATION, DCM_SH, "PRC Scheduled Procedure Step Location"},
09218     {DCM_PRCPREMEDICATION, DCM_LO, "PRC Pre-Medication"},
09219     {DCM_PRCSTATUS, DCM_CS, "PRC SPStep Status"},
09220     {DCM_PRCREFSTANDALONESOPSEQ, DCM_SQ, "PRC Ref Standalone SOP Inst Seq"},
09221     {DCM_PRCPERFORMEDSTATIONAET, DCM_AE, "PRC Performed Station AE Title"},
09222     {DCM_PRCPERFORMEDSTATIONNAME, DCM_SH, "PRC Performed Station Name"},
09223     {DCM_PRCPERFORMEDLOCATION, DCM_SH, "PRC Performed Location"},
09224     {DCM_PRCPPSSTARTDATE, DCM_DA, "PRC PPS Start Date"},
09225     {DCM_PRCPPSSTARTTIME, DCM_TM, "PRC PPS Start Time"},
09226     {DCM_PRCPPSENDDATE, DCM_DA, "PRC PPS End Date"},
09227     {DCM_PRCPPSENDTIME, DCM_TM, "PRC PPS End Time"},
09228     {DCM_PRCPPSSTATUS, DCM_CS, "PRC PPS Status"},
09229 #if 0
09230     {DCM_PRCPPSID, DCM_CS, "PRC PPS ID"},
09231 #else
09232     {DCM_PRCPPSID, DCM_SH, "PRC PPS ID"},    /* RWC correction */
09233 #endif
09234     {DCM_PRCPPSDESCRIPTION, DCM_LO, "PRC PPS Description"},
09235     {DCM_PRCPPTYPEDESCRIPTION, DCM_LO, "PRC Perf Procedure Type Description"},
09236     {DCM_PRCPERFORMEDAISEQUENCE, DCM_SQ, "PRC Perf AI Sequence"},
09237     {DCM_PRCSCHEDSTEPATTRSEQ, DCM_SQ, "PRC Scheduled Step Attr Seq"},
09238     {DCM_PRCREQUESTATTRIBUTESSEQ, DCM_SQ, "PRC Request Attributes Seq"},
09239     {DCM_PRCCOMMENTSPPS, DCM_ST, "PRC Comments on PPS"},
09240     {DCM_PRCQUANTITYSEQ, DCM_SQ, "PRC Quantity Sequence"},
09241     {DCM_PRCQUANTITY, DCM_DS, "PRC Quantity"},
09242     {DCM_PRCMEASURINGUNITSSEQ, DCM_SQ, "PRC Measuring Units Sequence"},
09243     {DCM_PRCBILLINGITEMSEQ, DCM_SQ, "PRC Billing Item Seq"},
09244     {DCM_PRCTOTALTIMEFLUOROSCOPY, DCM_US, "PRC Total Time Fluoroscopy"},
09245     {DCM_PRCTOTALNUMBEREXPOSURES, DCM_US, "PRC Total Number Exposures"},
09246     {DCM_PRCENTRANCEDOSE, DCM_US, "PRC Entrance Dose"},
09247     {DCM_PRCEXPOSEDAREA, DCM_US, "PRC Exposed Area"},
09248     {DCM_PRCDISTANCESOURCEENTRANCE, DCM_DS, "PRC Distance Source to Entrance"},
09249     {DCM_PRCCOMMENTSRADIATIONDOSE, DCM_ST, "PRC Comments on Radiation Dose"},
09250 
09251     {0x00400312, DCM_DS, "PRC X-Ray Output"},           /* 2002.04.26 */
09252     {0x00400314, DCM_DS, "PRC Half Value Layer"},       /* 2002.04.26 */
09253     {0x00400316, DCM_DS, "PRC Organ Dose"},             /* 2002.04.26 */
09254     {0x00400318, DCM_CS, "PRC Organ Exposed"},          /* 2002.04.26 */
09255 
09256     {DCM_PRCBILLINGPROCEDURESTEPSEQ, DCM_SQ, "PRC Billing Proc Step Seq"},
09257     {DCM_PRCFILMCONSUMPTIONSEQ, DCM_SQ, "PRC Film Consumption Seq"},
09258     {DCM_PRCBILLINGSUPPLIESDEVICESEQ, DCM_SQ, "PRC Billing Supplies/Devices Seq"},
09259     {DCM_PRCREFERENCEDPPS, DCM_SQ, "PRC Ref Procedure Step Seq"},
09260     {DCM_PRCPERFORMEDSERIESSEQ, DCM_SQ, "PRC Performed Series Seq"},
09261     {DCM_PRCSCHEDULEDPROCSTEPSEQ, DCM_SQ, "PRC Scheduled Procedure Step Sequence"},
09262     {DCM_PRCCOMMENTSONSCHEDULEDPROCSTEP, DCM_LT, "PRC Comments on the Scheduled Procedure Step"},
09263     {DCM_MAKETAG(0x0040, 0x050a), DCM_LO, "PRC Specimen Accession Number"},     /* Sup 15 */
09264     {DCM_MAKETAG(0x0040, 0x0550), DCM_SQ, "PRC Specimen Sequence"},     /* Sup 15 */
09265     {DCM_MAKETAG(0x0040, 0x0551), DCM_LO, "PRC Specimen Identifier"},   /* Sup 15 */
09266     {DCM_MAKETAG(0x0040, 0x0552), DCM_SQ, "PRC Specimen Description Sequence"}, /* Sup 15 */
09267     {DCM_MAKETAG(0x0040, 0x0553), DCM_ST, "PRC Specimen Description"},  /* Sup 15 */
09268     {DCM_MAKETAG(0x0040, 0x0555), DCM_SQ, "PRC Acquisition Context Sequence"},  /* Sup 15 */
09269     {DCM_MAKETAG(0x0040, 0x0556), DCM_ST, "PRC Acquisition Context Description"},       /* Sup 15 */
09270     {DCM_MAKETAG(0x0040, 0x059a), DCM_SQ, "PRC Specimen Type Code Sequence"},   /* Sup 15 */
09271     {DCM_MAKETAG(0x0040, 0x06fa), DCM_LO, "PRC Slide Identifier"},      /* Sup 15 */
09272     {DCM_MAKETAG(0x0040, 0x071a), DCM_SQ, "PRC Image Center Point Coordinates Sequence"},       /* Sup 15 */
09273     {DCM_MAKETAG(0x0040, 0x072a), DCM_DS, "PRC X offset in Slide Coordinate System"},   /* Sup 15 */
09274     {DCM_MAKETAG(0x0040, 0x073a), DCM_DS, "PRC Y offset in Slide Coordinate System"},   /* Sup 15 */
09275     {DCM_MAKETAG(0x0040, 0x074a), DCM_DS, "PRC Z offset in Slide Coordinate System"},   /* Sup 15 */
09276     {DCM_MAKETAG(0x0040, 0x08d8), DCM_SQ, "PRC Pixel Spacing Sequence"},        /* Sup 15 */
09277     {DCM_MAKETAG(0x0040, 0x08da), DCM_SQ, "PRC Coordinate System Axis Code Sequence"},  /* Sup 15 */
09278     {DCM_MAKETAG(0x0040, 0x08ea), DCM_SQ, "PRC Measurement Units Code Sequence"},       /* Sup 15 */
09279     {DCM_MAKETAG(0x0040, 0x09f8), DCM_SQ, "PRC Vital Stain Code Sequence"},     /* Sup 15 */
09280     {DCM_PRCREQUESTEDPROCEDUREID, DCM_SH, "PRC Requested Procedure ID"},
09281     {DCM_PRCREASONFORREQUESTEDPROC, DCM_LO, "PRC Reason for the Requested Procedure"},
09282     {DCM_PRCREQUESTEDPROCPRIORITY, DCM_SH, "PRC Patient Transport Arrangements"},
09283     {DCM_PRCPATIENTTRANSPORTARRANGEMENTS, DCM_LO, "PRC Patient Transport Arrangements"},
09284     {DCM_PRCREQUESTEDPROCLOCATION, DCM_LO, "PRC Requested Procedure Location"},
09285     {DCM_PRCPLACERORDERNUMBERPROC, DCM_SH, "PRC Placer Order Number / Procedure"},
09286 
09287     {DCM_PRCFILLERORDERNUMBERPROC, DCM_SH, "PRC Filler Order Number / Procedure"},
09288     {DCM_PRCCONFIDENTIALITYCODE, DCM_LO, "PRC Confidentiality Code"},
09289     {DCM_PRCREPORTINGPRIORITY, DCM_SH, "PRC  Reporting Priority"},
09290     {DCM_PRCNAMESINTENDEDRECIPIENTSRESULTS, DCM_PN, "PRC Names of Intended Recipients of Results"},
09291     {DCM_PRCREQUESTEDPROCCOMMENTS, DCM_LT, "PRC Requested Procedure Comments"},
09292     {DCM_PRCREASONFORIMAGINGSERVICEREQ, DCM_LO, "PRC Reason for the Imaging Service Request"},
09293     {DCM_PRCISSUEDATEIMAGINGSERVICEREQ, DCM_DA, "PRC Issue Date of Imaging Service Request"},
09294     {DCM_PRCISSUETIMEIMAGINGSERVICEREQ, DCM_TM, "PRC Issue Time of Imaging Service Request"},
09295     {DCM_PRCPLACERORDERNUMBERIMAGINGSRVREQ, DCM_SH, "PRC Placer Order Number/Imaging Service Request"},
09296     {DCM_PRCFILLERORDERNUMBERIMAGINGSRVREQ, DCM_SH, "PRC Filler Order Number/Imaging Service Request"},
09297     {DCM_PRCORDERENTEREDBY, DCM_PN, "PRC Order Entered By"},
09298     {DCM_PRCORDERENTERERSLOCATION, DCM_SH, "PRC Order Enterer's Location"},
09299     {DCM_PRCORDERCALLBACKPHONENUMBER, DCM_SH, "PRC Order Callback Phone Number"},
09300     {DCM_MAKETAG(0x0040, 0x2016), DCM_LO, "PRC Placer Order Number/ISR"},
09301     {DCM_MAKETAG(0x0040, 0x2017), DCM_LO, "PRC Filler Order Number/ISR"},
09302 
09303     {DCM_PRCIMAGINGSERVICEREQCOMMENTS, DCM_LT, "PRC Imaging Service Request Comments"},
09304     {DCM_PRCCONFIDIENTIALITYCONSTRAINTPATIENTDATADES, DCM_LO, "PRC Confidientiality Constraint Patient Data..."},
09305 
09306     {DCM_PRCGPSPSSTATUS, DCM_CS, "PRC General Purpose Sched Procedure Step Status"},
09307     {DCM_PRCGPPPSSTATUS, DCM_CS, "PRC Gen. Purpose Perf Procedure Step Status"},
09308     {DCM_PRCGPSPSPRIORITY, DCM_CS, "PRC Gen. Purpose Sched Procedure Step Priority"},
09309     {DCM_PRCSCHEDULEDPROCAPPCODESEQ, DCM_SQ, "PRC Scheduled Proccessing Application Code Seq"},
09310     {DCM_PRCGPSPSSTARTDATETIME, DCM_DT, "PRC Sched Procedure Step Start Date and Time"},
09311     {DCM_PRCGPSPSMULTIPLECOPIESFLAG, DCM_CS, "PRC Multiple Copies Flag"},
09312     {DCM_PRCPERFORMEDPROCAPPCODESEQ, DCM_SQ, "PRC Performed Proccessing Applications Code Seq"},
09313     {DCM_PRCHUMANPERFORMERCODESEQ, DCM_SQ, "PRC Human Performer Code Sequence"},
09314     {DCM_PRCGPSPSEXPECTEDCOMPLETEDATETIME, DCM_DT, "PRC Expected Completion Date and Time"},
09315     {DCM_PRCRESULTINGGPPERFPROCSTEPSEQ, DCM_SQ, "PRC Resulting Gen Purpose Perf Proc Steps Seq"},
09316     {DCM_PRCREFERENCEDGPSCHEDPROCSTEPSEQ, DCM_SQ, "PRC Referenced Gen Purp Sched Proc Steps Seq"},
09317     {DCM_PRCSCHEDWORKITEMCODESEQ, DCM_SQ, "PRC Scheduled Workitem Code Sequence"},
09318     {DCM_PRCPERFORMEDWORKITEMCODESEQ, DCM_SQ, "PRC Performed Workitem Code Sequence"},
09319     {DCM_PRCINPUTAVAILFLAG, DCM_CS, "PRC Input Availability Flag"},
09320     {DCM_PRCINPUTINFOSEQ, DCM_SQ, "PRC Input Information Sequence"},
09321     {DCM_PRCRELEVANTINFOSEQ, DCM_SQ, "PRC Relevant Information Sequence"},
09322     {DCM_PRCREFERENCEDGPSPSTRANSACTIONUID, DCM_UI, "PRC Referenced Gen Purp SPS Transaction UID"},
09323     {DCM_PRCSCHEDSTATIONNAMECODESEQ, DCM_SQ, "PRC Scheduled Station Name Code Sequence"},
09324     {DCM_PRCSCHEDSTATIONCLASSCODESEQ, DCM_SQ, "PRC Scheduled Station Class Code Sequence"},
09325     {DCM_PRCSCHEDSTATIONLOCCODESEQ, DCM_SQ, "PRC Sched Station Geographic Location Code Seq"},
09326     {DCM_PRCPERFORMEDSTATIONNAMECODESEQ, DCM_SQ, "PRC Performed Station Name Code Seq"},
09327     {DCM_PRCPERFORMEDSTATIONCLASSCODESEQ, DCM_SQ, "PRC Performed Station Class Code Sequence"},
09328     {DCM_PRCPERFORMEDSTATIONLOCCODESEQ, DCM_SQ, "PRC Perf Station Geographic Location Code Seq"},
09329     {DCM_PRCREQSUBSWORKITEMCODESEQ, DCM_SQ, "PRC Requested Subsequent Workitem Code Sequence"},
09330     {DCM_PRCNONDICOMOUTPUTCODESEQ, DCM_SQ, "PRC Non-DICOM Output Code Sequence"},
09331     {DCM_PRCOUTPUTINFOSEQ, DCM_SQ, "PRC Output Information Sequence"},
09332     {DCM_PRCSCHEDHUMANPERFORMERSSEQ, DCM_SQ, "PRC Scheduled Human Performers Sequence"},
09333     {DCM_PRCHUMANPERFORMERSORG, DCM_LO, "PRC Human Performer's Organization"},
09334     {DCM_PRCHUMANPERFORMERSNAME, DCM_PN, "PRC Human Performer's Name"},
09335 
09336 
09337     {DCM_MAKETAG(0x0040, 0xa010), DCM_CS, "PRC Relationship Type"}, /* Sup 23*/
09338     {DCM_MAKETAG(0x0040, 0xa027), DCM_LO, "PRC Verifying Organization"}, /* Sup 23*/
09339     {DCM_MAKETAG(0x0040, 0xa030), DCM_DT, "PRC Verification DateTime"}, /* Sup 23*/
09340     {DCM_MAKETAG(0x0040, 0xa032), DCM_DT, "PRC Observation DateTime"}, /* Sup 23*/
09341     {DCM_MAKETAG(0x0040, 0xa040), DCM_CS, "PRC Value Type"}, /* Sup 23*/
09342 
09343     {DCM_MAKETAG(0x0040, 0xa043), DCM_SQ, "PRC Concept-name Code Sequence"},    /* Sup 23 */
09344     {DCM_MAKETAG(0x0040, 0xa050), DCM_CS, "PRC Continuity of Content"}, /* Sup 23*/
09345     {DCM_MAKETAG(0x0040, 0xa073), DCM_SQ, "PRC Verifying Observer Sequence"}, /* Sup 23*/
09346     {DCM_MAKETAG(0x0040, 0xa075), DCM_PN, "PRC Verifying Observer Name"}, /* Sup 23*/
09347     {DCM_MAKETAG(0x0040, 0xa088), DCM_SQ, "PRC Verifying Observer Identification Code Seq"}, /* Sup 23*/
09348     {DCM_MAKETAG(0x0040, 0xa0a0), DCM_CS, "PRC Referenced Type of Data"},       /* Sup 30 0.6 */
09349     {DCM_MAKETAG(0x0040, 0xa0b0), DCM_US, "PRC Referenced Waveform Channels"},  /* Sup 30 0.6 */
09350     {DCM_MAKETAG(0x0040, 0xa120), DCM_DT, "PRC Date Time"}, /* Sup 23*/
09351     {DCM_MAKETAG(0x0040, 0xa121), DCM_DA, "PRC Date"},  /* Sup 15 */
09352     {DCM_MAKETAG(0x0040, 0xa122), DCM_TM, "PRC Time"},  /* Sup 15 */
09353     {DCM_MAKETAG(0x0040, 0xa123), DCM_PN, "PRC Person Name"},   /* Sup 15 */
09354     {DCM_MAKETAG(0x0040, 0xa124), DCM_UI, "PRC UID"}, /* Sup 23*/
09355     {DCM_MAKETAG(0x0040, 0xa130), DCM_CS, "PRC Temporal Range Type"},   /* Sup 30 0.6 */
09356     {DCM_MAKETAG(0x0040, 0xa132), DCM_UL, "PRC Referenced Sample Offsets"},     /* Sup 30 0.6 */
09357     {DCM_MAKETAG(0x0040, 0xa138), DCM_DS, "PRC Referenced Time Offsets"},       /* Sup 30 0.6 */
09358     {DCM_MAKETAG(0x0040, 0xa13a), DCM_DT, "PRC Referenced Datetime"},   /* Sup 30 0.6 */
09359     {DCM_MAKETAG(0x0040, 0xa160), DCM_UT, "PRC Text Value"},    /* */
09360     {DCM_MAKETAG(0x0040, 0xa168), DCM_SQ, "PRC Concept Code Sequence"}, /* Sup 15 */
09361     {DCM_MAKETAG(0x0040, 0xa16a), DCM_ST, "PRC Bibliographics Citation"},       /* Sup 15 */
09362     {DCM_MAKETAG(0x0040, 0xa180), DCM_US, "PRC Annotation Group Number"},       /* Sup 30 0.6 */
09363     {DCM_MAKETAG(0x0040, 0xa195), DCM_SQ, "PRC Concept-name Code Sequence Modifier"},   /* Sup 15 */
09364 
09365     {DCM_MAKETAG(0x0040, 0xa300), DCM_SQ, "PRC Measured Value Sequence"}, /* Sup 23 */
09366     {DCM_MAKETAG(0x0040, 0xa30a), DCM_DS, "PRC Numeric Value"}, /* Sup 15 */
09367     {DCM_MAKETAG(0x0040, 0xa353), DCM_ST, "PRC Address"},       /* Sup 15 */
09368     {DCM_MAKETAG(0x0040, 0xa354), DCM_LO, "PRC Telephone Number"},      /* Sup 15 */
09369     {DCM_MAKETAG(0x0040, 0xa360), DCM_SQ, "PRC Predecessor Documents Sequence"}, /* Sup 23 */
09370     {DCM_MAKETAG(0x0040, 0xa370), DCM_SQ, "PRC Referenced Request Sequence"}, /* Sup 23 */
09371     {DCM_MAKETAG(0x0040, 0xa372), DCM_SQ, "PRC Performed Procedure Code Sequence"}, /* Sup 23 */
09372     {DCM_MAKETAG(0x0040, 0xa375), DCM_SQ, "PRC Current Reqeusted Procedure Evidence Seq"}, /* Sup 23 */
09373     {DCM_MAKETAG(0x0040, 0xa385), DCM_SQ, "PRC Pertinent Other Evidence Sequence"}, /* Sup 23 */
09374     {DCM_MAKETAG(0x0040, 0xa491), DCM_CS, "PRC Completion Flag"}, /* Sup 23 */
09375     {DCM_MAKETAG(0x0040, 0xa492), DCM_LO, "PRC Completion Flag Description"}, /* Sup 23 */
09376     {DCM_MAKETAG(0x0040, 0xa493), DCM_CS, "PRC Verification Flag"}, /* Sup 23 */
09377     {DCM_MAKETAG(0x0040, 0xa504), DCM_SQ, "PRC Content Template Sequence"}, /* Sup 23 */
09378     {DCM_MAKETAG(0x0040, 0xa525), DCM_SQ, "PRC Identical Documents Sequence"}, /* Sup 23 */
09379     {DCM_MAKETAG(0x0040, 0xa730), DCM_SQ, "PRC Content Sequence"}, /* Sup 23 */
09380     {DCM_MAKETAG(0x0040, 0xa992), DCM_ST, "PRC Uniform Resource Locator"},      /* Sup 15 */
09381     {DCM_MAKETAG(0x0040, 0xb020), DCM_SQ, "PRC Annotation Sequence"},   /* Sup 30 0.6 */
09382     {DCM_MAKETAG(0x0040, 0xadb00), DCM_CS, "PRC Template Identifier"}, /* Sup 23 */
09383     {DCM_MAKETAG(0x0040, 0xadb06), DCM_DT, "PRC Template Version"}, /* Sup 23 */
09384     {DCM_MAKETAG(0x0040, 0xadb07), DCM_DT, "PRC Template Local Version"}, /* Sup 23 */
09385     {DCM_MAKETAG(0x0040, 0xadb0b), DCM_CS, "PRC Template Extension Flag"}, /* Sup 23 */
09386     {DCM_MAKETAG(0x0040, 0xadb0c), DCM_UI, "PRC Template Extension Organization UID"}, /* Sup 23 */
09387     {DCM_MAKETAG(0x0040, 0xadb0d), DCM_UI, "PRC Template Extension Creator UID"}, /* Sup 23 */
09388     {DCM_MAKETAG(0x0040, 0xadb73), DCM_UL, "PRC Referenced Content Item Identifier"} /* Sup 23 */
09389 };
09390 
09391 /* Define the entries for the DEVICE group, 0050
09392 */
09393 static DCMDICT DEV_dictionary[] = {
09394     {DCM_DEVCALIBRATIONOBJECT, DCM_CS, "DEV Calibration Object"},
09395     {DCM_DEVDEVICESEQUENCE, DCM_SQ, "DEV Device Sequence"},
09396     {DCM_DEVDEVICELENGTH, DCM_DS, "DEV Device Length"},
09397     {DCM_DEVDEVICEDIAMETER, DCM_DS, "DEV Device Diameter"},
09398     {DCM_DEVDEVICEDIAMETERUNITS, DCM_CS, "DEV Device Diameter Units"},
09399     {DCM_DEVDEVICEVOLUME, DCM_DS, "DEV Device Volume"},
09400     {DCM_DEVINTERMARKERDISTANCE, DCM_DS, "DEV Inter-Marker Distance"},
09401     {DCM_DEVDEVICEDESCRIPTION, DCM_LO, "DEV Device Description"},
09402 };
09403 
09404 /* Define the entries for the RESULTS group, 4008
09405 */
09406 static DCMDICT RES_dictionary[] = {
09407     {DCM_RESGROUPLENGTH, DCM_UL, "RES Group Length"},
09408     {DCM_RESID, DCM_SH, "RES Results ID"},
09409     {DCM_RESIDISSUER, DCM_LO, "RES Results ID Issuer"},
09410     {DCM_RESREFERENCEDINTERPSEQ, DCM_SQ, "RES Referenced Interpretation Sequence"},
09411     {DCM_RESINTERPRECORDEDDATE, DCM_DA, "RES Interpretation Recorded Date"},
09412     {DCM_RESINTERPRECORDEDTIME, DCM_TM, "RES Interpretation Recorded Time"},
09413     {DCM_RESINTERPRECORDER, DCM_PN, "RES Interpretation Recorder"},
09414     {DCM_RESREFERENCETORECORDEDSOUND, DCM_LO, "RES Reference to Recorded Sound"},
09415     {DCM_RESINTERPTRANSCRIPTIONDATE, DCM_DA, "RES Interpretation Transcription Date"},
09416     {DCM_RESINTERPTRANSCRIPTIONTIME, DCM_TM, "RES Interpretation Transcription Time"},
09417     {DCM_RESINTERPTRANSCRIBER, DCM_PN, "RES Interpretation Transcriber"},
09418     {DCM_RESINTERPTEXT, DCM_ST, "RES Interpretation Text"},
09419     {DCM_RESINTERPAUTHOR, DCM_PN, "RES Interpretation Author"},
09420     {DCM_RESINTERPAPPROVERSEQUENCE, DCM_SQ, "RES Interpretation Approver Sequence"},
09421     {DCM_RESINTERPAPPROVALDATE, DCM_DA, "RES Interpretation Approval Date"},
09422     {DCM_RESINTERPAPPROVALTIME, DCM_TM, "RES Interpretation Approval Time"},
09423     {DCM_RESPHYSICIANAPPROVINGINTERP, DCM_PN, "RES Physician Approving Interpretation"},
09424     {DCM_RESDIAGNOSIS, DCM_LT, "RES Diagnosis"},
09425     {DCM_RESDIAGNOSISCODESEQ, DCM_SQ, "RES Diagnosis Code Sequence"},
09426     {DCM_RESDISTRIBUTIIONLISTSEQUENCE, DCM_SQ, "RES Results Distribution List Sequence"},
09427     {DCM_RESDISTRIBUTIONNAME, DCM_PN, "RES Distribution Name"},
09428     {DCM_RESDISTRIBUTIONADDRESS, DCM_LO, "RES Distribution Address"},
09429     {DCM_RESINTERPID, DCM_SH, "RES Interpretation ID"},
09430     {DCM_RESINTERPIDISSUER, DCM_LO, "RES Interpretation ID Issuer"},
09431     {DCM_RESINTERPTYPEID, DCM_CS, "RES Interpretation Type ID"},
09432     {DCM_RESINTERPSTATUSID, DCM_CS, "RES Interpretation Status ID"},
09433     {DCM_RESIMPRESSIONS, DCM_ST, "RES Impressions"},
09434     {DCM_RESCOMMENTS, DCM_ST, "RES Comments"}
09435 };
09436 
09437 /* Define entries for the CURVE group */
09438 static DCMDICT CRV_dictionary[] = {
09439     {DCM_CURVEGROUPLENGTH, DCM_UL, "CRV Group Length"},
09440     {DCM_CURVEDIMENSIONS, DCM_US, "CRV Curve Dimensions"},
09441     {DCM_CURVENUMBEROFPOINTS, DCM_US, "CRV Number of points"},
09442     {DCM_CURVETYPEOFDATA, DCM_CS, "CRV Type of Data"},
09443     {DCM_CURVEDESCRIPTION, DCM_LO, "CRV Curve Description"},
09444     {DCM_CURVEAXISUNITS, DCM_SH, "CRV Axis Units"},
09445     {DCM_CURVEAXISLABELS, DCM_SH, "CRV Axis Labels"},
09446     {DCM_CURVEDATAVALUEREPRESENTATION, DCM_US, "CRV Data Value Representation"},
09447     {DCM_CURVEMINCOORDINATEVALUE, DCM_US, "CRV Minimum Coordinate Value"},
09448     {DCM_CURVEMAXCOORDINATEVALUE, DCM_US, "CRV Maximum Coordinate Value"},
09449     {DCM_CURVERANGE, DCM_SH, "CRV Curve Range"},
09450     {DCM_CURVEDATADESCRIPTOR, DCM_US, "CRV Data Descriptor"},
09451     {DCM_CURVECOORDINATESTARTVALUE, DCM_US, "CRV Coordinate Start Value"},
09452     {DCM_CURVECOORDINATESTEPVALUE, DCM_US, "CRV Coordinate Step Value"},
09453     {DCM_CURVEAUDIOTYPE, DCM_US, "CRV Audio Type"},
09454     {DCM_CURVEAUDIOSAMPLEFORMAT, DCM_US, "CRV Audio Sample Format"},
09455     {DCM_CURVENUMBEROFCHANNELS, DCM_US, "CRV Number of Channels"},
09456     {DCM_CURVENUMBEROFSAMPLES, DCM_UL, "CRV Number of Samples"},
09457     {DCM_CURVESAMPLERATE, DCM_UL, "CRV Sample Rate"},
09458     {DCM_CURVETOTALTIME, DCM_UL, "CRV Total Time"},
09459     {DCM_CURVEAUDIOSAMPLEDATA, DCM_OW, "CRV Audio Sample Data"},
09460     {DCM_CURVEAUDIOCOMMENTS, DCM_LT, "CRV Audio Comments"},
09461     {DCM_CURVELABEL, DCM_LO, "CRV Curve Label"},
09462     {DCM_CURVEREFOVERLAYSEQUENCE, DCM_SQ, "CRV Referenced Overlay Sequence"},
09463     {DCM_CURVEREFOVERLAYGROUP, DCM_US, "CRV Referenced Overlay Group"},
09464     {DCM_CURVEDATA, DCM_OW, "CRV Curve Data"}
09465 };
09466 
09467 /* Define the entries for the NMI (nuclear medicine image) group, 0054 */
09468 static DCMDICT NMI_dictionary[] = {
09469     {DCM_NMIGROUPLENGTH, DCM_UL, "NMI Group Length"},
09470     {DCM_NMIENERGYWINDOWVECTOR, DCM_US, "NMI Energy Window Vector"},
09471     {DCM_NMINUMBEROFENERGYWINDOWS, DCM_US, "NMI Number of Energy Windows"},
09472     {DCM_NMIENERGYWINDOWINFOSEQ, DCM_SQ, "NMI Energy Window Information Sequence"},
09473     {DCM_NMIENERGYWINDOWRANGESEQ, DCM_SQ, "NMI Energy Window Range Sequence"},
09474     {DCM_NMIENERGYWINDOWLOWERLIMIT, DCM_DS, "NMI Energy Window Lower Limit"},
09475     {DCM_NMIENERGYWINDOWUPPERLIMIT, DCM_DS, "NMI Energy Window Upper Limit"},
09476     {DCM_NMIRADIOPHARMINFOSEQ, DCM_SQ, "NMI Radiopharmaceutical Information Sequence"},
09477     {DCM_NMIRESIDUALSYRINGECOUNTS, DCM_IS, "NMI Residual Syringe Counts"},
09478     {DCM_NMIENERGYWINDOWNAME, DCM_SH, "NMI Energy Window Name"},
09479     {DCM_NMIDETECTORVECTOR, DCM_US, "NMI Detector Vector"},
09480     {DCM_NMINUMBEROFDETECTORS, DCM_US, "NMI Number of Detectors"},
09481     {DCM_NMIDETECTORINFOSEQUENCE, DCM_SQ, "NMI Detector Information Sequence"},
09482     {DCM_NMIPHASEVECTOR, DCM_US, "NMI Phase Vector"},
09483     {DCM_NMINUMBEROFPHASES, DCM_US, "NMI Number of Phases"},
09484     {DCM_NMIPHASEINFOSEQUENCE, DCM_SQ, "NMI Phase Information Sequence"},
09485     {DCM_NMINUMBEROFFRAMESINPHASE, DCM_US, "NMI Number of Frames in Phase"},
09486     {DCM_NMIPHASEDELAY, DCM_IS, "NMI Phase Delay"},
09487     {DCM_NMIPAUSEBETWEENFRAMES, DCM_IS, "NMI Pause between Frames"},
09488     {DCM_NMIROTATIONVECTOR, DCM_US, "NMI Rotation Vector"},
09489     {DCM_NMINUMBEROFROTATIONS, DCM_US, "NMI Number of rotations"},
09490     {DCM_NMIROTATIONINFOSEQUENCE, DCM_SQ, "NMI Rotation Information Sequence"},
09491     {DCM_NMINUMBEROFFRAMESINROTATION, DCM_US, "NMI Number of frames in rotation"},
09492     {DCM_NMIRRINTERVALVECTOR, DCM_US, "NMI R-R Interval Vector"},
09493     {DCM_NMINUMBEROFRRINTERVALS, DCM_US, "NMI Number of R-R Intervals"},
09494     {DCM_NMIGATEDINFOSEQUENCE, DCM_SQ, "NMI Gated Information Sequence"},
09495     {DCM_NMIDATAINFORMATIONSEQUENCE, DCM_SQ, "NMI Data Information Sequence"},
09496     {DCM_NMITIMESLOTVECTOR, DCM_US, "NMI Time Slot Vector"},
09497     {DCM_NMINUMBEROFTIMESLOTS, DCM_US, "NMI Number of Time Slots"},
09498     {DCM_NMITIMESLOTINFOSEQUENCE, DCM_SQ, "NMI Time Slot Information Sequence"},
09499     {DCM_NMITIMESLOTTIME, DCM_DS, "NMI Time Slot Time"},
09500     {DCM_NMISLICEVECTOR, DCM_US, "NMI Slice Vector"},
09501     {DCM_NMINUMBEROFSLICES, DCM_US, "NMI Number of Slices"},
09502     {DCM_NMIANGULARVIEWVECTOR, DCM_US, "NMI Angular View Vector"},
09503     {DCM_NMITIMESLICEVECTOR, DCM_US, "NMI Time Slice Vector"},
09504     {DCM_NMINUMBEROFTIMESLICES, DCM_US, "NMI Number of Time Slices"},
09505     {DCM_NMISTARTANGLE, DCM_DS, "NMI Start Angle"},
09506     {DCM_NMITYPEOFDETECTORMOTION, DCM_CS, "NMI Type of Detector Motion"},
09507     {DCM_NMITRIGGERVECTOR, DCM_IS, "NMI Trigger Vector"},
09508     {DCM_NMINUMBEROFTRIGGERSINPHASE, DCM_US, "NMI Number of Triggers in Phase"},
09509     {DCM_NMIVIEWCODESEQUENCE, DCM_SQ, "NMI View Code Sequence"},
09510     {DCM_NMIVIEWANGULATIONMODIFIERCODESEQ, DCM_SQ, "NMI View Angulation Modifer Code Sequence"},
09511     {DCM_NMIRADIONUCLIDECODESEQUENCE, DCM_SQ, "NMI Radionuclide Code Sequence"},
09512     {DCM_NMIRADIOPHARMROUTECODESEQUENCE, DCM_SQ, "NMI Radiopharmaceutical Route Code Sequence"},
09513     {DCM_NMIRADIOPHARMCODESEQUENCE, DCM_SQ, "NMI Radiopahrmaceutical Code Sequence"},
09514     {DCM_NMICALIBRATIONDATASEQUENCE, DCM_SQ, "NMI Calibration Data Sequence"},
09515     {DCM_NMIENERGYWINDOWNUMBER, DCM_US, "NMI Energy Window Number"},
09516     {DCM_NMIIMAGEID, DCM_SH, "NMI Image ID"},
09517     {DCM_NMIPATIENTORIENTATIONCODESEQ, DCM_SQ, "NMI Patient Orientation Code Sequence"},
09518     {DCM_NMIPATIENTORIENTATIONMODIFIERCODESEQ, DCM_SQ, "NMI Patient Orientation Modifier Code Sequence"},
09519     {DCM_NMIPATIENTGANTRYRELATIONSHIPCODESEQ, DCM_SQ, "NMI Patient Gantry Relationship Code Sequence"},
09520     {DCM_NMISERIESTYPE, DCM_CS, "NMI Series Type"},
09521     {DCM_NMIUNITS, DCM_CS, "NMI Units"},
09522     {DCM_NMICOUNTSSOURCE, DCM_CS, "NMI Counts Source"}, /* 1002 */
09523     {DCM_NMIREPROJECTIONMETHOD, DCM_CS, "NMI Reprojection Method"},     /* 1004 */
09524     {DCM_NMIRANDOMSCORRECTIONMETHOD, DCM_CS,
09525     "NMI Randoms Correction Method"},   /* 1100 */
09526     {DCM_NMIATTENUATIONCORRECTIONMETHOD, DCM_LO,
09527     "NMI Attenuation Correction Method"},       /* 1101 */
09528     {DCM_NMIDECAYCORRECTION, DCM_CS, "NMI Decay Correction"},   /* 1102 */
09529     {DCM_NMIRECONSTRUCTIONMETHOD, DCM_LO, "NMI Reconstruction Method"}, /* 1103 */
09530     {DCM_NMIDETECTORLINESRESPONSEUSED, DCM_LO,
09531     "NMI Detector Lines of Response Used"},     /* 1104 */
09532     {DCM_NMISCATTERCORRECTIONMETHOD, DCM_LO, "NMI Scatter Correction Method"},  /* 1105 */
09533     {DCM_NMIAXIALACCEPTANCE, DCM_DS, "NMI Axial Acceptance"},   /* 1200 */
09534     {DCM_NMIAXIALMASH, DCM_IS, "NMI Axial Mash"},       /* 1201 */
09535     {DCM_NMITRANSVERSEMASH, DCM_IS, "NMI Transverse Mash"},     /* 1202 */
09536     {DCM_NMIDETECTORELEMENTSIZE, DCM_DS, "NMI Detector Element Size"},  /* 1203 */
09537     {DCM_NMICOINCIDENCEWINDOWWIDTH, DCM_DS, "NMI Coincidence Window Width"},    /* 1210 */
09538     {DCM_NMISECONDARYCOUNTSTYPE, DCM_CS, "NMI Secondary Counts Type"},  /* 1220 */
09539     {DCM_NMIFRAMEREFERENCETIME, DCM_DS, "NMI Frame Reference Time"},    /* 1300 */
09540     {DCM_NMIPRIMARYCOUNTSACCUMULATED, DCM_IS,
09541     "NMI Primary (Prompts) Counts Accumulated"},        /* 1310 */
09542     {DCM_NMISECONDARYCOUNTSACCUMULATED, DCM_IS,
09543     "NMI Secondary Counts Accumulated"},        /* 1311 */
09544     {DCM_NMISLICESENSITIVITYFACTOR, DCM_DS, "NMI Slice Sensitivity Factor"},    /* 1320 */
09545     {DCM_NMIDECAYFACTOR, DCM_DS, "NMI Decay Factor"},   /* 1321 */
09546     {DCM_NMIDOSECALIBRATIONFACTOR, DCM_DS, "NMI Dose Calibration Factor"},      /* 1322 */
09547     {DCM_NMISCATTERFRACTIONFACTOR, DCM_DS, "NMI Scatter Fraction Factor"},      /* 1323 */
09548     {DCM_NMIDEADTIMEFACTOR, DCM_DS, "NMI Dead Time Factor"},    /* 1324 */
09549     {DCM_NMIIMAGEINDEX, DCM_US, "NMI Image Index"},     /* 1330 */
09550     {DCM_NMICOUNTSINCLUDED, DCM_CS, "NMI Counts Included"},     /* 1400 */
09551     {DCM_NMIDEADTIMECORRECTIONFLAG, DCM_CS,
09552     "NMI Dead Time Correction Flag"},   /* 1401 */
09553 };
09554 
09555 /* Define the entries for the Graphics group, 0070 */
09556 static DCMDICT GRP_dictionary[] = {
09557     {DCM_MAKETAG(0x0070, 0x0000), DCM_UL, "GRP Group Length"},
09558     {DCM_MAKETAG(0x0070, 0x0022), DCM_FL, "GRP Graphic Data"}, /* Sup 33 */
09559     {DCM_MAKETAG(0x0070, 0x0023), DCM_CS, "GRP Graphic Type"}, /* Sup 33 */
09560     {DCM_MAKETAG(0x0070, 0x0024), DCM_CS, "GRP Graphic Filled"}, /* Sup 33 */
09561     {DCM_MAKETAG(0x0070, 0x0041), DCM_CS, "GRP Image Horizontal Flip"}, /* Sup 33*/
09562     {DCM_MAKETAG(0x0070, 0x0042), DCM_US, "GRP Image Rotation"}, /* Sup 33 */
09563     {DCM_MAKETAG(0x0070, 0x0052), DCM_SL, "GRP Displayed Area Top LH Corner"},
09564     {DCM_MAKETAG(0x0070, 0x0053), DCM_SL, "GRP Displayed Area Bottom RH Corner"},
09565     {DCM_MAKETAG(0x0070, 0x005a), DCM_SQ, "GRP Display Area Selection Seq"},
09566     {DCM_MAKETAG(0x0070, 0x0060), DCM_SQ, "GRP Graphic Layer Sequence"},
09567     {DCM_MAKETAG(0x0070, 0x0062), DCM_IS, "GRP Graphic Layer Order"},
09568     {DCM_MAKETAG(0x0070, 0x0066), DCM_US, "GRP Graphic Layer Rec Disp GS Val"},
09569     {DCM_MAKETAG(0x0070, 0x0067), DCM_US, "GRP Graphic Layer Rec Disp RGB Val"},
09570     {DCM_MAKETAG(0x0070, 0x0068), DCM_LO, "GRP Graphic Layer Description"},
09571 
09572     {DCM_MAKETAG(0x0070, 0x0080), DCM_CS, "GRP Presentation Label"}, /* Sup 33 */
09573     {DCM_MAKETAG(0x0070, 0x0081), DCM_LO, "GRP Presentation Description"}, /* Sup 33 */
09574     {DCM_MAKETAG(0x0070, 0x0082), DCM_DA, "GRP Presentation Creation Date"}, /* Sup 33 */
09575     {DCM_MAKETAG(0x0070, 0x0083), DCM_TM, "GRP Presentation Creation Time"}, /* Sup 33 */
09576     {DCM_MAKETAG(0x0070, 0x0084), DCM_PN, "GRP Presentation Creators Name"}, /* Sup 33 */
09577     {DCM_MAKETAG(0x0070, 0x0100), DCM_CS, "GRP Presentation Size Mode"}, /* Sup 33 */
09578     {DCM_MAKETAG(0x0070, 0x0101), DCM_DS, "GRP Presentation Pixel Spacing"}, /* Sup 33 */
09579     {DCM_MAKETAG(0x0070, 0x0102), DCM_IS, "GRP Presentation Pixel Aspect Ratio"}, /* Sup 33 */
09580     {DCM_MAKETAG(0x0070, 0x0103), DCM_FL, "GRP Presentation Pixel Magnification Ratio"}, /* Sup 33 */
09581 };
09582 
09583 /* Define the entries for the OLY (Overlay) group */
09584 static DCMDICT OLY_dictionary[] = {
09585     {DCM_OLYGROUPLENGTH, DCM_UL, "OLY Group Length"},
09586     {DCM_OLYROWS, DCM_US, "OLY Rows"},
09587     {DCM_OLYCOLUMNS, DCM_US, "OLY Columns"},
09588     {DCM_OLYPLANES, DCM_US, "OLY Planes"},
09589     {DCM_OLYNUMBEROFFRAMESINOVERLAY, DCM_IS, "OLY Number of frames in Overlay"},
09590     {DCM_OLYOVERLAYDESCRIPTION, DCM_LO, "OLY Overlay Description"},
09591     {DCM_OLYTYPE, DCM_CS, "OLY Type"},
09592     {DCM_OLYSUBTYPE, DCM_LO, "OLY Subtype"},
09593     {DCM_OLYORIGIN, DCM_SS, "OLY Origin"},
09594     {DCM_OLYIMAGEFRAMEORIGIN, DCM_US, "OLY Image Frame Origin"},
09595     {DCM_OLYOVERLAYPLANEORIGIN, DCM_US, "OLY Overlay Plane Origin"},
09596     {DCM_OLYCOMPRESSIONCODE, DCM_LO, "OLY Compression Code (RET)"},
09597     {DCM_OLYBITSALLOCATED, DCM_US, "OLY Overlay Bits Allocated"},
09598     {DCM_OLYBITPOSITION, DCM_US, "OLY Overlay Bit Position"},
09599     {DCM_OLYOVERLAYFORMAT, DCM_LO, "OLY Overlay Format (RET)"},
09600     {DCM_OLYOVERLAYLOCATION, DCM_US, "OLY Overlay Location (RET)"},
09601     {DCM_OLYDESCRIPTORGRAY, DCM_US, "OLY Overlay Descriptor - Gray"},
09602     {DCM_OLYDESCRIPTORRED, DCM_US, "OLY Overlay Descriptor - Red"},
09603     {DCM_OLYDESCRIPTORGREEN, DCM_US, "OLY Overlay Descriptor - Green"},
09604     {DCM_OLYDESCRIPTORBLUE, DCM_US, "OLY Overlay Descriptor - Blue"},
09605     {DCM_OLYGRAY, DCM_US, "OLY Overlays - Gray"},
09606     {DCM_OLYRED, DCM_US, "OLY Overlays - Red"},
09607     {DCM_OLYGREEN, DCM_US, "OLY Overlays - Green"},
09608     {DCM_OLYBLUE, DCM_US, "OLY Overlays - Blue"},
09609     {DCM_OLYROIAREA, DCM_IS, "OLY ROI Area"},
09610     {DCM_OLYROIMEAN, DCM_DS, "OLY ROI Mean"},
09611     {DCM_OLYROISTANDARDDEVIATION, DCM_DS, "OLY ROI Standard Deviation"},
09612     {DCM_OLYOVERLAYLABEL, DCM_LO, "OLY Overlay Label"},
09613     {DCM_OLYDATA, DCM_OW, "OLY Data"},
09614     {DCM_OLYCOMMENTS, DCM_LO, "OLY Comments (RET)"}
09615 };
09616 
09617 /* Define the entries for the PIXEL group (7FE0)
09618 */
09619 static DCMDICT PXL_dictionary[] = {
09620     {DCM_PXLGROUPLENGTH, DCM_UL, "PXL Group Length"},
09621     {DCM_PXLPIXELDATA, DCM_OT, "PXL Pixel Data"}
09622 };
09623 
09624 /* Define the elements for the MEDIA group (0088) */
09625 static DCMDICT MED_dictionary[] = {
09626     {DCM_MEDIAGROUPLENGTH, DCM_UL, "MED Media Group Length "},
09627     {DCM_MEDIASTORAGEFILESETID, DCM_SH, "MED Storage Media File-set ID"},
09628     {DCM_MEDIASTORAGEFILESETUID, DCM_UI, "MED Storage Media File-setUID"},
09629     {DCM_MEDIAICONIMAGE, DCM_SQ, "MED Icon Image Sequence"},
09630     {DCM_MEDIATOPICTITLE, DCM_LO, "MED Topic Title"},
09631     {DCM_MEDIATOPICSUBJECT, DCM_ST, "MED Topic Subject"},
09632     {DCM_MEDIATOPICAUTHOR, DCM_LO, "MED Topic Author"},
09633     {DCM_MEDIATOPICKEYWORD, DCM_LO, "MED Topic Keywords"}
09634 };
09635 
09636 /* Define the entries in the BASICFILMSESSION group (2000)
09637 */
09638 static DCMDICT BFS_dictionary[] = {
09639     {DCM_BFSGROUPLENGTH, DCM_UL, "BFS Group Length"},
09640     {DCM_BFSCOPIES, DCM_IS, "BFS Number of copies printed for each film"},
09641     {DCM_BFSPRINTPRIORITY, DCM_CS, "BFS Specifies priority of print job"},
09642     {DCM_BFSMEDIUMTYPE, DCM_CS, "BFS Medium on which page will be printed"},
09643     {DCM_BFSFILMDESTINATION, DCM_CS, "BFS Film destination"},
09644     {DCM_BFSFILMSESSIONLABEL, DCM_LO, "BFS Human readable label to identify film"},
09645     {DCM_BFSMEMORYALLOCATION, DCM_IS, "BFS Amount of mem allocated for film session"},
09646     {DCM_BFSREFERENCEDFILMBOXSEQ, DCM_SQ, "BFS seq of UIDs of diff FILMBOX instances"}
09647 };
09648 
09649 /* Define the entries in the BASICFILMBOX group (2010)
09650 */
09651 static DCMDICT BFB_dictionary[] = {
09652     {DCM_BFBGROUPLENGTH, DCM_UL, "BFB Group Length"},
09653     {DCM_BFBIMAGEDISPLAYFORMAT, DCM_ST, "BFB Type of image display format"},
09654     {DCM_BFBANNOTATIONDISPLAYFORMAT, DCM_CS, "BFB Id of annotation display format"},
09655     {DCM_BFBFILMORIENTATION, DCM_CS, "BFB Film orientation"},
09656     {DCM_BFBFILMSIZEID, DCM_CS, "BFB Film size identification"},
09657     {DCM_BFBMAGNIFICATIONTYPE, DCM_CS, "BFB Interpol. type by which printer mag image"},
09658     {DCM_BFBSMOOTHINGTYPE, DCM_CS, "BFB Specifies type of interpolation function"},
09659     {DCM_BFBBORDERDENSITY, DCM_CS, "BFB density of film areas around/between images"},
09660     {DCM_BFBEMPTYIMAGEDENSITY, DCM_CS, "BFB density of image box area having no image"},
09661     {DCM_BFBMINDENSITY, DCM_US, "BFB Minimum density of images on the film"},
09662     {DCM_BFBMAXDENSITY, DCM_US, "BFB Maximum density of images on the film"},
09663     {DCM_BFBTRIM, DCM_CS, "BFB specifies whether to trim or not"},
09664     {DCM_BFBCONFIGURATIONINFO, DCM_ST, "BFB ID of configuration table"},
09665     {DCM_BFBREFBASICFILMSESSIONSEQ, DCM_SQ, "BFB seq. of film session instance"},
09666     {DCM_BFBREFBASICIMAGEBOXSEQ, DCM_SQ, "BFB seq. of basic image box SOP instance"},
09667     {DCM_BFBREFBASICANNOTBOXSEQ, DCM_SQ, "BFB seq. of basic annotation box SOP instance"},
09668 };
09669 
09670 /* Defines the entries in the BASICIMAGEBOX (2020)
09671 */
09672 static DCMDICT BIB_dictionary[] = {
09673     {DCM_BIBGROUPLENGTH, DCM_UL, "BIB Group Length"},
09674     {DCM_BIBIMAGEPOSITION, DCM_US, "BIB Specifies position of the image in the film"},
09675     {DCM_BIBPOLARITY, DCM_CS, "BIB Specifies image polarity"},
09676     {DCM_BIBREQUESTEDIMAGESIZE, DCM_DS, "BIB Requested image size"},
09677     {DCM_BIBPREFORMATGREYSCALEIMAGESEQ, DCM_SQ, "BIB Preformatted Greyscale image"},
09678     {DCM_BIBPREFORMATCOLORIMAGESEQ, DCM_SQ, "BIB Preformatted Color image"},
09679     {DCM_BIBREFIMAGEOVERLAYBOXSEQ, DCM_SQ, "BIB Referenced Image Overlay Box seq"},
09680     {DCM_BIBREFVOILUTSEQ, DCM_SQ, "BIB Referenced VOI LUT seq."}
09681 };
09682 
09683 /* Defines the entries in the BASICANNOTATIONBOX group (2030)
09684 */
09685 static DCMDICT BAB_dictionary[] = {
09686     {DCM_BABGROUPLENGTH, DCM_UL, "BAB Group Length"},
09687     {DCM_BABANNOTATIONPOSITION, DCM_US, "BAB posn of the annot. box in parent film box"},
09688     {DCM_BABTEXTSTRING, DCM_LO, "BAB text string"}
09689 };
09690 
09691 /* Defines entries for BASICIMAGEOVERLAYBOX group (2040)
09692 */
09693 static DCMDICT IOB_dictionary[] = {
09694     {DCM_IOBGROUPLENGTH, DCM_UL, "IOB Group Length"},
09695     {DCM_IOBREFOVERLAYPLANESEQ, DCM_SQ, "IOB Ref Overlay Plane Sequence"},
09696     {DCM_IOBREFOVERLAYPLANEGROUPS, DCM_US, "IOB Ref Overlay Plane Groups"},
09697     {DCM_IOBOVERLAYMAGNIFICATIONTYPE, DCM_CS, "IOB Overlay Magnification Type"},
09698     {DCM_IOBOVERLAYSMOOTHINGTYPE, DCM_CS, "IOB Overlay Smoothing Type"},
09699     {DCM_IOBOVERLAYFOREGROUNDDENSITY, DCM_CS, "IOB Overlay Foreground Density"},
09700     {DCM_IOBOVERLAYMODE, DCM_CS, "IOB Overlay Mode"},
09701     {DCM_IOBTHRESHOLDDENSITY, DCM_CS, "IOB Threshold Density"},
09702     {DCM_IOBREFIMAGEBOXSEQUENCE, DCM_SQ, "IOB Ref Image Box Sequence (RET)"}
09703 };
09704 
09705 /* Defines entries for Presentation LUT Group (2050)
09706 */
09707 static DCMDICT PLUT_dictionary[] = {
09708     {DCM_MAKETAG(0x2050, 0x0000), DCM_UL, "PLUT Group Length"},
09709     {DCM_MAKETAG(0x2050, 0x0010), DCM_SQ, "PLUT Presentation LUT Sequence"},
09710     {DCM_MAKETAG(0x2050, 0x0020), DCM_CS, "PLUT Presentation LUT Shape"},
09711     {DCM_MAKETAG(0x2050, 0x0500), DCM_SQ, "PLUT Referenced Presentation LUT Sequence"}
09712 };
09713 
09714 /* Defines the entries in the PRINTJOB group (2100)
09715 */
09716 static DCMDICT PJ_dictionary[] = {
09717     {DCM_PJGROUPLENGTH, DCM_UL, "PJ Group Length"},
09718     {DCM_PJEXECUTIONSTATUS, DCM_CS, "PJ execution status of print job"},
09719     {DCM_PJEXECUTIONSTATUSINFO, DCM_CS, "PJ additional information"},
09720     {DCM_PJCREATIONDATE, DCM_DA, "PJ date of print job creation"},
09721     {DCM_PJCREATIONTIME, DCM_TM, "PJ time of print job creation"},
09722     {DCM_PJORIGINATOR, DCM_AE, "PJ Appln entity title that issued the print opn"},
09723     {DCM_PJREFPRINTJOBSEQ, DCM_SQ, "PJ Referenced print job seq."}
09724 };
09725 
09726 /* Defines the entries in the PRINTER group (2110)
09727 */
09728 static DCMDICT PRN_dictionary[] = {
09729     {DCM_PRINTERGROUPLENGTH, DCM_UL, "PRINTER Group Length"},
09730     {DCM_PRINTERSTATUS, DCM_CS, "PRINTER printer device status"},
09731     {DCM_PRINTERSTATUSINFO, DCM_CS, "PRINTER additional information"},
09732     {DCM_PRINTERNAME, DCM_LO, "PRINTER printer name"},
09733     {DCM_PRINTERQUEUEID, DCM_SH, "Printer Queue ID"}
09734 };
09735 
09736 /* Define the entries in the 0x3002 group, used for RT planning
09737 */
09738 static DCMDICT G3002_dictionary[] = {
09739     {DCM_MAKETAG(0x3002, 0x0000), DCM_UL, "RT Group Length"},
09740     {DCM_MAKETAG(0x3002, 0x0002), DCM_SH, "RT Image Label"},
09741     {DCM_MAKETAG(0x3002, 0x0003), DCM_LO, "RT Image Name"},
09742     {DCM_MAKETAG(0x3002, 0x0004), DCM_ST, "RT Image Description"},
09743     {DCM_MAKETAG(0x3002, 0x000a), DCM_CS, "RT Reported Values Origin"},
09744     {DCM_MAKETAG(0x3002, 0x000c), DCM_CS, "RT Image Plane"},
09745     {DCM_MAKETAG(0x3002, 0x000e), DCM_DS, "RT X-Ray Image Receptor Angle"},
09746     {DCM_MAKETAG(0x3002, 0x0010), DCM_DS, "RT Image Orientation"},
09747     {DCM_MAKETAG(0x3002, 0x0011), DCM_DS, "RT Image Plane Pixel Spacing"},
09748     {DCM_MAKETAG(0x3002, 0x0012), DCM_DS, "RT Image Position"},
09749     {DCM_MAKETAG(0x3002, 0x0020), DCM_SH, "RT Radiation Machine Name"},
09750     {DCM_MAKETAG(0x3002, 0x0022), DCM_DS, "RT Radiation Machine SAD"},
09751     {DCM_MAKETAG(0x3002, 0x0024), DCM_DS, "RT Radiation Machine SSD"},
09752     {DCM_MAKETAG(0x3002, 0x0026), DCM_DS, "RT Image SID"},
09753     {DCM_MAKETAG(0x3002, 0x0028), DCM_DS, "RT Source to Reference Object Distance"},
09754     {DCM_MAKETAG(0x3002, 0x0029), DCM_IS, "RT Fraction Number"},
09755     {DCM_MAKETAG(0x3002, 0x0030), DCM_SQ, "RT Exposure Sequence"},
09756     {DCM_MAKETAG(0x3002, 0x0032), DCM_DS, "RT Meterset Exposure"}
09757 };
09758 
09759 /* Define the entries in the 0x3004 group, Dose Volume Histogram (DVH),
09760 ** used in RT planning.
09761 */
09762 static DCMDICT DVH_dictionary[] = {
09763     {DCM_MAKETAG(0x3004, 0x0000), DCM_UL, "DVH Group Length"},
09764     {DCM_MAKETAG(0x3004, 0x0001), DCM_CS, "DVH Type"},
09765     {DCM_MAKETAG(0x3004, 0x0002), DCM_CS, "DVH Dose Units"},
09766     {DCM_MAKETAG(0x3004, 0x0004), DCM_CS, "DVH Dose Type"},
09767     {DCM_MAKETAG(0x3004, 0x0006), DCM_LO, "DVH Dose Comment"},
09768     {DCM_MAKETAG(0x3004, 0x0008), DCM_DS, "DVH Normalization Point"},
09769     {DCM_MAKETAG(0x3004, 0x000a), DCM_CS, "DVH Dose Summation Type"},
09770     {DCM_MAKETAG(0x3004, 0x000c), DCM_DS, "DVH Grid Frame Offset Vector"},
09771     {DCM_MAKETAG(0x3004, 0x000e), DCM_DS, "DVH Dose Grid Scaling"},
09772     {DCM_MAKETAG(0x3004, 0x0010), DCM_SQ, "DVH RT Dose ROI Sequence"},
09773     {DCM_MAKETAG(0x3004, 0x0012), DCM_DS, "DVH Dose Value"},
09774     {DCM_MAKETAG(0x3004, 0x0040), DCM_DS, "DVH Normalization Point"},
09775     {DCM_MAKETAG(0x3004, 0x0042), DCM_DS, "DVH Normalization Dose Value"},
09776     {DCM_MAKETAG(0x3004, 0x0050), DCM_SQ, "DVH Sequence"},
09777     {DCM_MAKETAG(0x3004, 0x0052), DCM_DS, "DVH Dose Scaling"},
09778     {DCM_MAKETAG(0x3004, 0x0054), DCM_CS, "DVH Volume Units"},
09779     {DCM_MAKETAG(0x3004, 0x0056), DCM_IS, "DVH Number of Bins"},
09780     {DCM_MAKETAG(0x3004, 0x0058), DCM_DS, "DVH Data"},
09781     {DCM_MAKETAG(0x3004, 0x0060), DCM_SQ, "DVH Referenced ROI Sequence"},
09782     {DCM_MAKETAG(0x3004, 0x0062), DCM_CS, "DVH ROI Contribution Type"},
09783     {DCM_MAKETAG(0x3004, 0x0070), DCM_DS, "DVH Minimum Dose"},
09784     {DCM_MAKETAG(0x3004, 0x0072), DCM_DS, "DVH Maximum Dose"},
09785     {DCM_MAKETAG(0x3004, 0x0074), DCM_DS, "DVH Mean Dose"}
09786 };
09787 
09788 /* Define the entries in the 0x3006 group, Structure Set,
09789 ** used in RT planning.
09790 */
09791 static DCMDICT SSET_dictionary[] = {
09792     {DCM_MAKETAG(0x3006, 0x0000), DCM_UL, "SSET Group Length"},
09793     {DCM_MAKETAG(0x3006, 0x0002), DCM_SH, "SSET Structure Set Label"},
09794     {DCM_MAKETAG(0x3006, 0x0004), DCM_LO, "SSET Structure Set Name"},
09795     {DCM_MAKETAG(0x3006, 0x0006), DCM_ST, "SSET Structure Set Description"},
09796     {DCM_MAKETAG(0x3006, 0x0008), DCM_DA, "SSET Structure Set Date"},
09797     {DCM_MAKETAG(0x3006, 0x0009), DCM_TM, "SSET Structure Set Time"},
09798     {DCM_MAKETAG(0x3006, 0x0010), DCM_SQ, "SSET Referenced Frame of Reference Sequence"},
09799     {DCM_MAKETAG(0x3006, 0x0012), DCM_SQ, "SSET RT Referenced Study Sequence"},
09800     {DCM_MAKETAG(0x3006, 0x0014), DCM_SQ, "SSET RT Referenced Series Sequence"},
09801     {DCM_MAKETAG(0x3006, 0x0016), DCM_SQ, "SSET Contour Image Sequence"},
09802     {DCM_MAKETAG(0x3006, 0x0020), DCM_SQ, "SSET Structure Set ROI Sequence"},
09803     {DCM_MAKETAG(0x3006, 0x0022), DCM_IS, "SSET ROI Number"},
09804     {DCM_MAKETAG(0x3006, 0x0024), DCM_UI, "SSET Referenced Frame of Reference UID"},
09805     {DCM_MAKETAG(0x3006, 0x0026), DCM_LO, "SSET ROI Name"},
09806     {DCM_MAKETAG(0x3006, 0x0028), DCM_ST, "SSET ROI Description"},
09807     {DCM_MAKETAG(0x3006, 0x002a), DCM_IS, "SSET ROI Display Color"},
09808     {DCM_MAKETAG(0x3006, 0x002c), DCM_DS, "SSET ROI Volume"},
09809     {DCM_MAKETAG(0x3006, 0x0030), DCM_SQ, "SSET RT Related ROI Sequence"},
09810     {DCM_MAKETAG(0x3006, 0x0033), DCM_CS, "SSET RT ROI Relationship"},
09811     {DCM_MAKETAG(0x3006, 0x0036), DCM_CS, "SSET ROI Generation Algorithm"},
09812     {DCM_MAKETAG(0x3006, 0x0038), DCM_LO, "SSET ROI Generation Description"},
09813     {DCM_MAKETAG(0x3006, 0x0039), DCM_SQ, "SSET ROI Contour Sequence"},
09814     {DCM_MAKETAG(0x3006, 0x0040), DCM_SQ, "SSET Contour Sequence"},
09815     {DCM_MAKETAG(0x3006, 0x0042), DCM_CS, "SSET Contour Geometric Type"},
09816     {DCM_MAKETAG(0x3006, 0x0044), DCM_DS, "SSET Contour Slab Thickness"},
09817     {DCM_MAKETAG(0x3006, 0x0045), DCM_DS, "SSET Contour Offset Vector"},
09818     {DCM_MAKETAG(0x3006, 0x0046), DCM_IS, "SSET Number of Contour Points"},
09819     {DCM_MAKETAG(0x3006, 0x0050), DCM_DS, "SSET Contour Data"},
09820     {DCM_MAKETAG(0x3006, 0x0080), DCM_SQ, "SSET RT ROI Observations Sequence"},
09821     {DCM_MAKETAG(0x3006, 0x0082), DCM_IS, "SSET Observation Number"},
09822     {DCM_MAKETAG(0x3006, 0x0084), DCM_IS, "SSET Referenced ROI Number"},
09823     {DCM_MAKETAG(0x3006, 0x0085), DCM_SH, "SSET ROI Observation Label"},
09824     {DCM_MAKETAG(0x3006, 0x0086), DCM_SQ, "SSET RT ROI Identification Code Sequence"},
09825     {DCM_MAKETAG(0x3006, 0x0088), DCM_ST, "SSET ROI Observation Description"},
09826     {DCM_MAKETAG(0x3006, 0x00a0), DCM_SQ, "SSET Relation RT ROI Observations Sequence"},
09827     {DCM_MAKETAG(0x3006, 0x00a4), DCM_CS, "SSET RT ROI Interpreted Type"},
09828     {DCM_MAKETAG(0x3006, 0x00a6), DCM_PN, "SSET ROI Interpreter"},
09829     {DCM_MAKETAG(0x3006, 0x00b0), DCM_SQ, "SSET ROI Physical Properties Sequence"},
09830     {DCM_MAKETAG(0x3006, 0x00b2), DCM_CS, "SSET ROI Physical Property"},
09831     {DCM_MAKETAG(0x3006, 0x00b4), DCM_DS, "SSET ROI Physical Property Value"},
09832     {DCM_MAKETAG(0x3006, 0x00c0), DCM_SQ, "SSET Frame of Referenced Relationship Sequence"},
09833     {DCM_MAKETAG(0x3006, 0x00c2), DCM_UI, "SSET Related Frame of Reference UID"},
09834     {DCM_MAKETAG(0x3006, 0x00c4), DCM_CS, "SSET Frame of Reference Transformation Type"},
09835     {DCM_MAKETAG(0x3006, 0x00c6), DCM_DS, "SSET Frame of Reference Transformation Matrix"},
09836     {DCM_MAKETAG(0x3006, 0x00c8), DCM_LO, "SSET Frame of Reference Transformation Comment"}
09837 };
09838 
09839 /* Define the entries in the 0x300A group, used in RT planning.
09840 */
09841 static DCMDICT G300A_dictionary[] = {
09842     {DCM_MAKETAG(0x300a, 0x0000), DCM_UL, "     Group Length"},
09843     {DCM_MAKETAG(0x300a, 0x0002), DCM_SH, "     RT Plan Label"},
09844     {DCM_MAKETAG(0x300a, 0x0003), DCM_LO, "     RT Plan Name"},
09845     {DCM_MAKETAG(0x300a, 0x0004), DCM_ST, "     RT Plan Description"},
09846     {DCM_MAKETAG(0x300a, 0x0006), DCM_DA, "     RT Plan Date"},
09847     {DCM_MAKETAG(0x300a, 0x0007), DCM_TM, "     RT Plan Time"},
09848     {DCM_MAKETAG(0x300a, 0x0009), DCM_LO, "     RT Treatment Protocols"},
09849     {DCM_MAKETAG(0x300a, 0x000a), DCM_CS, "     Treatment Intent"},
09850     {DCM_MAKETAG(0x300a, 0x000b), DCM_LO, "     Treatment Sites"},
09851     {DCM_MAKETAG(0x300a, 0x000c), DCM_CS, "     RT Plan Geometry"},
09852     {DCM_MAKETAG(0x300a, 0x000e), DCM_ST, "     Prescription Description"},
09853     {DCM_MAKETAG(0x300a, 0x0010), DCM_SQ, "     Dose Reference Sequence"},
09854     {DCM_MAKETAG(0x300a, 0x0012), DCM_IS, "     Dose Reference Number"},
09855     {DCM_MAKETAG(0x300a, 0x0014), DCM_CS, "     Dose Reference Structure Type"},
09856     {DCM_MAKETAG(0x300a, 0x0016), DCM_LO, "     Dose Reference Description"},
09857     {DCM_MAKETAG(0x300a, 0x0018), DCM_DS, "     Dose Reference Point Coordinates"},
09858     {DCM_MAKETAG(0x300a, 0x001a), DCM_DS, "     Nominal Prior Dose"},
09859     {DCM_MAKETAG(0x300a, 0x0020), DCM_CS, "     Dose Reference Type"},
09860     {DCM_MAKETAG(0x300a, 0x0021), DCM_DS, "     Constraint Weight"},
09861     {DCM_MAKETAG(0x300a, 0x0022), DCM_DS, "     Delivery Warning Dose"},
09862     {DCM_MAKETAG(0x300a, 0x0023), DCM_DS, "     Delivery Maximum Dose"},
09863     {DCM_MAKETAG(0x300a, 0x0025), DCM_DS, "     Target Minimum Dose"},
09864     {DCM_MAKETAG(0x300a, 0x0026), DCM_DS, "     Target Prescription Dose"},
09865     {DCM_MAKETAG(0x300a, 0x0027), DCM_DS, "     Target Maximum Dose"},
09866     {DCM_MAKETAG(0x300a, 0x0028), DCM_DS, "     Target Underdose Volume Fraction"},
09867     {DCM_MAKETAG(0x300a, 0x002a), DCM_DS, "     Organ at Risk Full-volume Dose"},
09868     {DCM_MAKETAG(0x300a, 0x002b), DCM_DS, "     Organ at Risk Limit Dose"},
09869     {DCM_MAKETAG(0x300a, 0x002c), DCM_DS, "     Organ at Risk Maximum Dose"},
09870     {DCM_MAKETAG(0x300a, 0x002d), DCM_DS, "     Organ at Risk Overdose Volume Fraction"},
09871     {DCM_MAKETAG(0x300a, 0x0040), DCM_SQ, "     Tolerance Table Sequence"},
09872     {DCM_MAKETAG(0x300a, 0x0042), DCM_IS, "     Tolerance Table Number"},
09873     {DCM_MAKETAG(0x300a, 0x0043), DCM_SH, "     Tolerance Table Label"},
09874     {DCM_MAKETAG(0x300a, 0x0044), DCM_DS, "     Gantry Angle Tolerance"},
09875     {DCM_MAKETAG(0x300a, 0x0046), DCM_DS, "     Beam Limiting Device Angle Tolerance"},
09876     {DCM_MAKETAG(0x300a, 0x0048), DCM_SQ, "     Beam Limiting Device Tolerance Sequence"},
09877     {DCM_MAKETAG(0x300a, 0x004a), DCM_DS, "     Beam Limiting Device Position Tolerance"},
09878     {DCM_MAKETAG(0x300a, 0x004c), DCM_DS, "     Patient Support Angle Tolerance"},
09879     {DCM_MAKETAG(0x300a, 0x004e), DCM_DS, "     Table Top Eccentric Angle Tolerance"},
09880     {DCM_MAKETAG(0x300a, 0x0051), DCM_DS, "     Table Top Vertical Position Tolerance"},
09881     {DCM_MAKETAG(0x300a, 0x0052), DCM_DS, "     Table Top Longitudinal Position Tolerance"},
09882     {DCM_MAKETAG(0x300a, 0x0053), DCM_DS, "     Table Top Lateral Position Tolerance"},
09883     {DCM_MAKETAG(0x300a, 0x0055), DCM_CS, "     RT Plan Relationship"},
09884     {DCM_MAKETAG(0x300a, 0x0070), DCM_SQ, "     Fraction Group Sequence"},
09885     {DCM_MAKETAG(0x300a, 0x0071), DCM_IS, "     Fraction Group Number"},
09886     {DCM_MAKETAG(0x300a, 0x0078), DCM_IS, "     Number of Fractions Planned"},
09887     {DCM_MAKETAG(0x300a, 0x0079), DCM_IS, "     Number of Fractions Per Day"},
09888     {DCM_MAKETAG(0x300a, 0x007a), DCM_IS, "     Repeat Fraction Cycle Length"},
09889     {DCM_MAKETAG(0x300a, 0x007b), DCM_LT, "     Fraction Pattern"},
09890     {DCM_MAKETAG(0x300a, 0x0080), DCM_IS, "     Number of Beams"},
09891     {DCM_MAKETAG(0x300a, 0x0082), DCM_DS, "     Beam Dose Specification Point"},
09892     {DCM_MAKETAG(0x300a, 0x0084), DCM_DS, "     Beam Dose"},
09893     {DCM_MAKETAG(0x300a, 0x0086), DCM_DS, "     Beam Meterset"},
09894     {DCM_MAKETAG(0x300a, 0x00a0), DCM_IS, "     Number of Brachy Application Setups"},
09895     {DCM_MAKETAG(0x300a, 0x00a2), DCM_DS, "     Brachy App Setup Dose Specification Point"},
09896     {DCM_MAKETAG(0x300a, 0x00a4), DCM_DS, "     Brachy Application Setup Dose"},
09897     {DCM_MAKETAG(0x300a, 0x00b0), DCM_SQ, "     Beam Sequence"},
09898     {DCM_MAKETAG(0x300a, 0x00b2), DCM_SH, "     Treatment Machine Name"},
09899     {DCM_MAKETAG(0x300a, 0x00b3), DCM_CS, "     Primary Dosimeter Unit"},
09900     {DCM_MAKETAG(0x300a, 0x00b4), DCM_DS, "     Source-Axis Distance"},
09901     {DCM_MAKETAG(0x300a, 0x00b6), DCM_SQ, "     Beam Limiting Device Sequence"},
09902     {DCM_MAKETAG(0x300a, 0x00b8), DCM_CS, "     RT Beam Limiting Device Type"},
09903     {DCM_MAKETAG(0x300a, 0x00ba), DCM_DS, "     Source to Beam Limiting Device Distance"},
09904     {DCM_MAKETAG(0x300a, 0x00bc), DCM_IS, "     Number of Leaf/Jaw Pairs"},
09905     {DCM_MAKETAG(0x300a, 0x00be), DCM_DS, "     Leaf Position Boundaries"},
09906     {DCM_MAKETAG(0x300a, 0x00c0), DCM_IS, "     Beam Number"},
09907     {DCM_MAKETAG(0x300a, 0x00c2), DCM_LO, "     Beam Name"},
09908     {DCM_MAKETAG(0x300a, 0x00c3), DCM_ST, "     Beam Description"},
09909     {DCM_MAKETAG(0x300a, 0x00c4), DCM_CS, "     Beam Type"},
09910     {DCM_MAKETAG(0x300a, 0x00c6), DCM_CS, "     Radiation Type"},
09911     {DCM_MAKETAG(0x300a, 0x00c8), DCM_IS, "     Reference Image Number"},
09912     {DCM_MAKETAG(0x300a, 0x00ca), DCM_SQ, "     Planned Verification Image Sequence"},
09913     {DCM_MAKETAG(0x300a, 0x00cc), DCM_LO, "     Imaging Device-Specific Acq Parameters"},
09914     {DCM_MAKETAG(0x300a, 0x00ce), DCM_CS, "     Treatment Delivery Type"},
09915     {DCM_MAKETAG(0x300a, 0x00d0), DCM_IS, "     Number of Wedges"},
09916     {DCM_MAKETAG(0x300a, 0x00d1), DCM_SQ, "     Wedge Sequence"},
09917     {DCM_MAKETAG(0x300a, 0x00d2), DCM_IS, "     Wedge Number"},
09918     {DCM_MAKETAG(0x300a, 0x00d3), DCM_CS, "     Wedge Type"},
09919     {DCM_MAKETAG(0x300a, 0x00d4), DCM_SH, "     Wedge ID"},
09920     {DCM_MAKETAG(0x300a, 0x00d5), DCM_IS, "     Wedge Angle"},
09921     {DCM_MAKETAG(0x300a, 0x00d6), DCM_DS, "     Wedge Factor"},
09922     {DCM_MAKETAG(0x300a, 0x00d8), DCM_DS, "     Wedge Orientation"},
09923     {DCM_MAKETAG(0x300a, 0x00da), DCM_DS, "     Source to Wedge Tray Distance"},
09924     {DCM_MAKETAG(0x300a, 0x00e0), DCM_IS, "     Number of Compensators"},
09925     {DCM_MAKETAG(0x300a, 0x00e1), DCM_SH, "     Material ID"},
09926     {DCM_MAKETAG(0x300a, 0x00e2), DCM_DS, "     Total Compensator Tray Factor"},
09927     {DCM_MAKETAG(0x300a, 0x00e3), DCM_SQ, "     Compensator Sequence"},
09928     {DCM_MAKETAG(0x300a, 0x00e4), DCM_IS, "     Compensator Number"},
09929     {DCM_MAKETAG(0x300a, 0x00e5), DCM_SH, "     Compensator ID"},
09930     {DCM_MAKETAG(0x300a, 0x00e6), DCM_DS, "     Source to Compensator Tray Distance"},
09931     {DCM_MAKETAG(0x300a, 0x00e7), DCM_IS, "     Compensator Rows"},
09932     {DCM_MAKETAG(0x300a, 0x00e8), DCM_IS, "     Compensator Columns"},
09933     {DCM_MAKETAG(0x300a, 0x00e9), DCM_DS, "     Compensator Pixel Spacing"},
09934     {DCM_MAKETAG(0x300a, 0x00ea), DCM_DS, "     Compensator Position"},
09935     {DCM_MAKETAG(0x300a, 0x00eb), DCM_DS, "     Compensator Transmission Data"},
09936     {DCM_MAKETAG(0x300a, 0x00ec), DCM_DS, "     Compensator Thickness Data"},
09937     {DCM_MAKETAG(0x300a, 0x00ed), DCM_IS, "     Number of Boli"},
09938     {DCM_MAKETAG(0x300a, 0x00f0), DCM_IS, "     Number of Blocks"},
09939     {DCM_MAKETAG(0x300a, 0x00f2), DCM_DS, "     Total Block Tray Factor"},
09940     {DCM_MAKETAG(0x300a, 0x00f4), DCM_SQ, "     Block Sequence"},
09941     {DCM_MAKETAG(0x300a, 0x00f5), DCM_SH, "     Block Tray ID"},
09942     {DCM_MAKETAG(0x300a, 0x00f6), DCM_DS, "     Source to Block Tray Distance"},
09943     {DCM_MAKETAG(0x300a, 0x00f8), DCM_CS, "     Block Type"},
09944     {DCM_MAKETAG(0x300a, 0x00fa), DCM_CS, "     Block Divergence"},
09945     {DCM_MAKETAG(0x300a, 0x00fc), DCM_IS, "     Block Number"},
09946     {DCM_MAKETAG(0x300a, 0x00fe), DCM_LO, "     Block Name"},
09947     {DCM_MAKETAG(0x300a, 0x0100), DCM_DS, "     Block Thickness"},
09948     {DCM_MAKETAG(0x300a, 0x0102), DCM_DS, "     Block Transmission"},
09949     {DCM_MAKETAG(0x300a, 0x0104), DCM_IS, "     Block Number of Points"},
09950     {DCM_MAKETAG(0x300a, 0x0106), DCM_DS, "     Block Data"},
09951     {DCM_MAKETAG(0x300a, 0x0107), DCM_SQ, "     Applicator Sequence"},
09952     {DCM_MAKETAG(0x300a, 0x0108), DCM_SH, "     Applicator ID"},
09953     {DCM_MAKETAG(0x300a, 0x0109), DCM_CS, "     Applicator Type"},
09954     {DCM_MAKETAG(0x300a, 0x010a), DCM_LO, "     Applicator Description"},
09955     {DCM_MAKETAG(0x300a, 0x010c), DCM_DS, "     Cumulative Dose Reference COefficient"},
09956     {DCM_MAKETAG(0x300a, 0x010e), DCM_DS, "     Final Cumulative Meterset Weight"},
09957     {DCM_MAKETAG(0x300a, 0x0110), DCM_IS, "     Number of Control Points"},
09958     {DCM_MAKETAG(0x300a, 0x0111), DCM_SQ, "     Control Point Sequence"},
09959     {DCM_MAKETAG(0x300a, 0x0112), DCM_IS, "     Control Point Index"},
09960     {DCM_MAKETAG(0x300a, 0x0114), DCM_DS, "     Nominal Beam Energy"},
09961     {DCM_MAKETAG(0x300a, 0x0115), DCM_DS, "     Dose Rate Set"},
09962     {DCM_MAKETAG(0x300a, 0x0116), DCM_SQ, "     Wedge Position Sequence"},
09963     {DCM_MAKETAG(0x300a, 0x0118), DCM_CS, "     Wedge Position"},
09964     {DCM_MAKETAG(0x300a, 0x011a), DCM_SQ, "     Beam Limiting Device Position Sequence"},
09965     {DCM_MAKETAG(0x300a, 0x011c), DCM_DS, "     Leaf/Jaw Positions"},
09966     {DCM_MAKETAG(0x300a, 0x011e), DCM_DS, "     Gantry Angle"},
09967     {DCM_MAKETAG(0x300a, 0x011f), DCM_CS, "     Gantry Rotation Direction"},
09968     {DCM_MAKETAG(0x300a, 0x0120), DCM_DS, "     Beam Limiting Device Angle"},
09969     {DCM_MAKETAG(0x300a, 0x0121), DCM_CS, "     Beam Limiting Device Rotation Direction"},
09970     {DCM_MAKETAG(0x300a, 0x0122), DCM_DS, "     Patient Support Angle"},
09971     {DCM_MAKETAG(0x300a, 0x0123), DCM_CS, "     Patient Support Rotation Direction"},
09972     {DCM_MAKETAG(0x300a, 0x0124), DCM_DS, "     Table Top Eccentric Axis Distance"},
09973     {DCM_MAKETAG(0x300a, 0x0125), DCM_DS, "     Table Top Eccentric Angle"},
09974     {DCM_MAKETAG(0x300a, 0x0126), DCM_CS, "     Table Top Eccentric Rotation Direction"},
09975     {DCM_MAKETAG(0x300a, 0x0128), DCM_DS, "     Table Top Vertical Position"},
09976     {DCM_MAKETAG(0x300a, 0x0129), DCM_DS, "     Table Top Longitudinal Position"},
09977     {DCM_MAKETAG(0x300a, 0x012a), DCM_DS, "     Table Top Lateral Position"},
09978     {DCM_MAKETAG(0x300a, 0x012c), DCM_DS, "     Isocenter Position"},
09979     {DCM_MAKETAG(0x300a, 0x012e), DCM_DS, "     Surface Entry Point"},
09980     {DCM_MAKETAG(0x300a, 0x0130), DCM_DS, "     Source to Surface Distance"},
09981     {DCM_MAKETAG(0x300a, 0x0134), DCM_DS, "     Cumulative Meterset Weight"},
09982     {DCM_MAKETAG(0x300a, 0x0180), DCM_SQ, "     Patient Setup Sequence"},
09983     {DCM_MAKETAG(0x300a, 0x0182), DCM_IS, "     Patient Setup Number"},
09984     {DCM_MAKETAG(0x300a, 0x0184), DCM_LO, "     Patient Additional Position"},
09985     {DCM_MAKETAG(0x300a, 0x0190), DCM_SQ, "     Fixation Device Sequence"},
09986     {DCM_MAKETAG(0x300a, 0x0192), DCM_CS, "     Fixation Device Type"},
09987     {DCM_MAKETAG(0x300a, 0x0194), DCM_SH, "     Fixation Device Label"},
09988     {DCM_MAKETAG(0x300a, 0x0196), DCM_ST, "     Fixation Device Description"},
09989     {DCM_MAKETAG(0x300a, 0x0198), DCM_SH, "     Fixation Device Position"},
09990     {DCM_MAKETAG(0x300a, 0x01a0), DCM_SQ, "     Shielding Device Sequence"},
09991     {DCM_MAKETAG(0x300a, 0x01a2), DCM_CS, "     Shielding Device Type"},
09992     {DCM_MAKETAG(0x300a, 0x01a4), DCM_SH, "     Shielding Device Label"},
09993     {DCM_MAKETAG(0x300a, 0x01a6), DCM_ST, "     Shielding Device Description"},
09994     {DCM_MAKETAG(0x300a, 0x01a8), DCM_SH, "     Shielding Device Position"},
09995     {DCM_MAKETAG(0x300a, 0x01b0), DCM_CS, "     Setup Technique"},
09996     {DCM_MAKETAG(0x300a, 0x01b2), DCM_ST, "     Setup Technique Description"},
09997     {DCM_MAKETAG(0x300a, 0x01b4), DCM_SQ, "     Setup Device Sequence"},
09998     {DCM_MAKETAG(0x300a, 0x01b6), DCM_CS, "     Setup Device Type"},
09999     {DCM_MAKETAG(0x300a, 0x01b8), DCM_SH, "     Setup Device Label"},
10000     {DCM_MAKETAG(0x300a, 0x01ba), DCM_ST, "     Setup Device Description"},
10001     {DCM_MAKETAG(0x300a, 0x01bc), DCM_DS, "     Setup Device Parameter"},
10002     {DCM_MAKETAG(0x300a, 0x01d0), DCM_ST, "     Setup Reference Description"},
10003     {DCM_MAKETAG(0x300a, 0x01d2), DCM_DS, "     Table Top Vertical Setup Displacement"},
10004     {DCM_MAKETAG(0x300a, 0x01d4), DCM_DS, "     Table Top Longitudinal Setup Displacement"},
10005     {DCM_MAKETAG(0x300a, 0x01d6), DCM_DS, "     Table Top Lateral Setup Displacement"},
10006     {DCM_MAKETAG(0x300a, 0x0200), DCM_CS, "     Brachy Treatment Technique"},
10007     {DCM_MAKETAG(0x300a, 0x0202), DCM_CS, "     Brachy Treatment Type"},
10008     {DCM_MAKETAG(0x300a, 0x0206), DCM_SQ, "     Treatment Machine Sequence"},
10009     {DCM_MAKETAG(0x300a, 0x0210), DCM_SQ, "     Source Sequence"},
10010     {DCM_MAKETAG(0x300a, 0x0212), DCM_IS, "     Source Number"},
10011     {DCM_MAKETAG(0x300a, 0x0214), DCM_CS, "     Source Type"},
10012     {DCM_MAKETAG(0x300a, 0x0216), DCM_LO, "     Source Manufacturer"},
10013     {DCM_MAKETAG(0x300a, 0x0218), DCM_DS, "     Active Source Diameter"},
10014     {DCM_MAKETAG(0x300a, 0x021a), DCM_DS, "     Active Source Length"},
10015     {DCM_MAKETAG(0x300a, 0x0222), DCM_DS, "     Source Encapsulation Nominal Thickness"},
10016     {DCM_MAKETAG(0x300a, 0x0224), DCM_DS, "     Source Encapsulation Nominal Transmission"},
10017     {DCM_MAKETAG(0x300a, 0x0226), DCM_LO, "     Source Isotope Name"},
10018     {DCM_MAKETAG(0x300a, 0x0228), DCM_DS, "     Source Isotope Half Life"},
10019     {DCM_MAKETAG(0x300a, 0x022a), DCM_DS, "     Reference Air Kerma Rate"},
10020     {DCM_MAKETAG(0x300a, 0x022c), DCM_DA, "     Air Kerma Rate Reference Date"},
10021     {DCM_MAKETAG(0x300a, 0x022e), DCM_TM, "     Air Kerma Rate Reference Time"},
10022     {DCM_MAKETAG(0x300a, 0x0230), DCM_SQ, "     Application Setup Sequence"},
10023     {DCM_MAKETAG(0x300a, 0x0232), DCM_CS, "     Application Setup Type"},
10024     {DCM_MAKETAG(0x300a, 0x0234), DCM_IS, "     Application Setup Number"},
10025     {DCM_MAKETAG(0x300a, 0x0236), DCM_LO, "     Application Setup Name"},
10026     {DCM_MAKETAG(0x300a, 0x0238), DCM_LO, "     Application Setup Manufacturer"},
10027     {DCM_MAKETAG(0x300a, 0x0240), DCM_IS, "     Template Number"},
10028     {DCM_MAKETAG(0x300a, 0x0242), DCM_SH, "     Template Type"},
10029     {DCM_MAKETAG(0x300a, 0x0244), DCM_LO, "     Template Name"},
10030     {DCM_MAKETAG(0x300a, 0x0250), DCM_DS, "     Total Reference Air Kerma"},
10031     {DCM_MAKETAG(0x300a, 0x0260), DCM_SQ, "     Brachy Acessory Device Sequence"},
10032     {DCM_MAKETAG(0x300a, 0x0262), DCM_IS, "     Brachy Accessory Device Number"},
10033     {DCM_MAKETAG(0x300a, 0x0263), DCM_SH, "     Brachy Accessory Device ID"},
10034     {DCM_MAKETAG(0x300a, 0x0264), DCM_CS, "     Brachy Accessory Device Type"},
10035     {DCM_MAKETAG(0x300a, 0x0266), DCM_LO, "     Brachy Accessory Device Name"},
10036     {DCM_MAKETAG(0x300a, 0x026a), DCM_DS, "     Brachy Accessory Device Nominal Thickness"},
10037     {DCM_MAKETAG(0x300a, 0x026c), DCM_DS, "     Brachy Acc'ry Device Nominal Transmission"},
10038     {DCM_MAKETAG(0x300a, 0x0280), DCM_SQ, "     Channel Sequence"},
10039     {DCM_MAKETAG(0x300a, 0x0282), DCM_IS, "     Channel Number"},
10040     {DCM_MAKETAG(0x300a, 0x0284), DCM_DS, "     Channel Length"},
10041     {DCM_MAKETAG(0x300a, 0x0286), DCM_DS, "     Channel Total Time"},
10042     {DCM_MAKETAG(0x300a, 0x0288), DCM_CS, "     Source Movement Type"},
10043     {DCM_MAKETAG(0x300a, 0x028a), DCM_IS, "     Number of Pulses"},
10044     {DCM_MAKETAG(0x300a, 0x028c), DCM_DS, "     Pulse Repetition Interval"},
10045     {DCM_MAKETAG(0x300a, 0x0290), DCM_IS, "     Source Applicator Number"},
10046     {DCM_MAKETAG(0x300a, 0x0291), DCM_SH, "     Source Applicator ID"},
10047     {DCM_MAKETAG(0x300a, 0x0292), DCM_CS, "     Source Applicator Type"},
10048     {DCM_MAKETAG(0x300a, 0x0294), DCM_LO, "     Source Applicator Name"},
10049     {DCM_MAKETAG(0x300a, 0x0296), DCM_DS, "     Source Applicator Length"},
10050     {DCM_MAKETAG(0x300a, 0x0298), DCM_LO, "     Source Applicator Manufacturer"},
10051     {DCM_MAKETAG(0x300a, 0x029c), DCM_DS, "     Source Applicator Wall Nominal Thickness"},
10052     {DCM_MAKETAG(0x300a, 0x029e), DCM_DS, "     Src Applicator Wall Nominal Transmission"},
10053     {DCM_MAKETAG(0x300a, 0x02a0), DCM_DS, "     Source Applicator Step Size"},
10054     {DCM_MAKETAG(0x300a, 0x02a2), DCM_IS, "     Transfer Tube Number"},
10055     {DCM_MAKETAG(0x300a, 0x02a4), DCM_DS, "     Transfer Tube Length"},
10056     {DCM_MAKETAG(0x300a, 0x02b0), DCM_SQ, "     Channel Shield Sequence"},
10057     {DCM_MAKETAG(0x300a, 0x02b2), DCM_IS, "     Channel Shield Number"},
10058     {DCM_MAKETAG(0x300a, 0x02b3), DCM_SH, "     Channel Shield ID"},
10059     {DCM_MAKETAG(0x300a, 0x02b4), DCM_LO, "     Channel Shield Name"},
10060     {DCM_MAKETAG(0x300a, 0x02b8), DCM_DS, "     Channel Shield Nominal Thickness"},
10061     {DCM_MAKETAG(0x300a, 0x02ba), DCM_DS, "     Channel Shield Nominal Transmission"},
10062     {DCM_MAKETAG(0x300a, 0x02c8), DCM_DS, "     Final Cumulative Time Weight"},
10063     {DCM_MAKETAG(0x300a, 0x02d0), DCM_SQ, "     Brachy Control Point Sequence"},
10064     {DCM_MAKETAG(0x300a, 0x02d2), DCM_DS, "   Control Point Relative Position"},
10065     {DCM_MAKETAG(0x300a, 0x02d4), DCM_DS, "     Control Point 3D Position"},
10066     {DCM_MAKETAG(0x300a, 0x02d6), DCM_DS, "     Cumulative Time Weight"}
10067 };
10068 
10069 /* Define the entries in the 0x300C group, used in RT planning.
10070 */
10071 static DCMDICT G300C_dictionary[] = {
10072     {DCM_MAKETAG(0x300c, 0x0000), DCM_UL, "     Group Length"},
10073     {DCM_MAKETAG(0x300c, 0x0002), DCM_SQ, "     Referenced RT Plan Sequence"},
10074     {DCM_MAKETAG(0x300c, 0x0004), DCM_SQ, "     Referenced Beam Sequence"},
10075     {DCM_MAKETAG(0x300c, 0x0006), DCM_IS, "     Referenced Beam Number"},
10076     {DCM_MAKETAG(0x300c, 0x0007), DCM_IS, "     Referenced Reference Image Number"},
10077     {DCM_MAKETAG(0x300c, 0x0008), DCM_DS, "     Start Cumulative Meterset Weight"},
10078     {DCM_MAKETAG(0x300c, 0x0009), DCM_DS, "     End Cumulative Meterset Weight"},
10079     {DCM_MAKETAG(0x300c, 0x000a), DCM_SQ, "     Referenced Brachy Application Setup Seq"},
10080     {DCM_MAKETAG(0x300c, 0x000c), DCM_IS, "     Referenced Brachy Application Setup Number"},
10081     {DCM_MAKETAG(0x300c, 0x000e), DCM_IS, "     Referenced Source Number"},
10082     {DCM_MAKETAG(0x300c, 0x0020), DCM_SQ, "     Referenced Fraction Group Sequence"},
10083     {DCM_MAKETAG(0x300c, 0x0022), DCM_IS, "     Referenced Fraction Group Number"},
10084     {DCM_MAKETAG(0x300c, 0x0040), DCM_SQ, "     Referenced Verification Image Sequence"},
10085     {DCM_MAKETAG(0x300c, 0x0042), DCM_SQ, "     Referenced Reference Image Sequence"},
10086     {DCM_MAKETAG(0x300c, 0x0050), DCM_SQ, "     Referenced Dose Reference Sequence"},
10087     {DCM_MAKETAG(0x300c, 0x0051), DCM_IS, "     Referenced Dose Reference Numer"},
10088     {DCM_MAKETAG(0x300c, 0x0055), DCM_SQ, "     Brachy Referenced Dose Reference Sequence"},
10089     {DCM_MAKETAG(0x300c, 0x0060), DCM_SQ, "     Referenced Structure Set Sequence"},
10090     {DCM_MAKETAG(0x300c, 0x006a), DCM_IS, "     Referenced Patient Setup Number"},
10091     {DCM_MAKETAG(0x300c, 0x0080), DCM_SQ, "     Referenced Dose Sequence"},
10092     {DCM_MAKETAG(0x300c, 0x00a0), DCM_IS, "     Referenced Tolerance Table Number"},
10093     {DCM_MAKETAG(0x300c, 0x00b0), DCM_SQ, "     Referenced Bolus Sequence"},
10094     {DCM_MAKETAG(0x300c, 0x00c0), DCM_IS, "     Referenced Wedge Number"},
10095     {DCM_MAKETAG(0x300c, 0x00d0), DCM_IS, "     Referenced Compensator Number"},
10096     {DCM_MAKETAG(0x300c, 0x00e0), DCM_IS, "     Referenced Block Number"},
10097     {DCM_MAKETAG(0x300c, 0x00f0), DCM_IS, "     Referenced Control Point Index"}
10098 };
10099 
10100 
10101 /* Define the entries in the 0x300E group, used in RT planning.
10102 */
10103 static DCMDICT G300E_dictionary[] = {
10104     {DCM_MAKETAG(0x300e, 0x0000), DCM_UL, "     Group Length"},
10105     {DCM_MAKETAG(0x300e, 0x0002), DCM_CS, "     Approval Status"},
10106     {DCM_MAKETAG(0x300e, 0x0004), DCM_DA, "     Review Date"},
10107     {DCM_MAKETAG(0x300e, 0x0005), DCM_TM, "     Review Time"},
10108     {DCM_MAKETAG(0x300e, 0x0008), DCM_PN, "     Reviewer Name"}
10109 };
10110 
10111 /* Defines the entries in the Text group (4000)
10112 */
10113 #if 0
10114 static DCMDICT TXT_dictionary[] = {
10115 };
10116 #endif
10117 
10118 /* Define the entries in the PAD group, 0xfffc
10119 */
10120 
10121 static DCMDICT PAD_dictionary[] = {
10122     {DCM_PADITEM, DCM_OB, "Pad item"}
10123 };
10124 
10125 /* Define the entries in the DELIMITER group, 0xfffe
10126 */
10127 
10128 static DCMDICT DLM_dictionary[] = {
10129     {DCM_DLMITEM, DCM_DLM, "DELIMITER Item"},
10130     {DCM_DLMITEMDELIMITATIONITEM, DCM_DLM, "DELIMITER Item Delimitation Item"},
10131     {DCM_DLMSEQUENCEDELIMITATIONITEM, DCM_DLM, "DELIMITER Sequence Delimitation Item"}
10132 };
10133 
10134 /* Define the outer layer dictionary which contains group numbers and
10135 ** pointers to each of the individual group lists.
10136 */
10137 
10138 static GROUPPTR group_dictionary[] = {
10139     {DCM_GROUPCOMMAND, sizeof(CMD_dictionary) / sizeof(DCMDICT), CMD_dictionary},
10140     {DCM_GROUPFILEMETA, sizeof(META_dictionary) / sizeof(DCMDICT), META_dictionary},
10141     {DCM_GROUPBASICDIRINFO, sizeof(BASICDIR_dictionary) / sizeof(DCMDICT), BASICDIR_dictionary},
10142     {DCM_GROUPIDENTIFYING,
10143     sizeof(ID_dictionary) / sizeof(DCMDICT), ID_dictionary},
10144     {DCM_GROUPPATIENTINFO,
10145     sizeof(PAT_dictionary) / sizeof(DCMDICT), PAT_dictionary},
10146     {DCM_GROUPACQUISITION,
10147     sizeof(ACQ_dictionary) / sizeof(DCMDICT), ACQ_dictionary},
10148     {DCM_GROUPRELATIONSHIP,
10149     sizeof(REL_dictionary) / sizeof(DCMDICT), REL_dictionary},
10150     {DCM_GROUPIMAGE,
10151     sizeof(IMG_dictionary) / sizeof(DCMDICT), IMG_dictionary},
10152     {DCM_GROUPSTUDY,
10153     sizeof(SDY_dictionary) / sizeof(DCMDICT), SDY_dictionary},
10154     {DCM_GROUPVISIT,
10155     sizeof(VIS_dictionary) / sizeof(DCMDICT), VIS_dictionary},
10156     {DCM_GROUPWAVEFORM,
10157     sizeof(WAV_dictionary) / sizeof(DCMDICT), WAV_dictionary},
10158     {DCM_GRPPROCEDURE,
10159     sizeof(PRC_dictionary) / sizeof(DCMDICT), PRC_dictionary},
10160     {DCM_GROUPDEVICE,
10161     sizeof(DEV_dictionary) / sizeof(DCMDICT), DEV_dictionary},
10162     {DCM_GROUPNMIMAGE,
10163     sizeof(NMI_dictionary) / sizeof(DCMDICT), NMI_dictionary},
10164     {DCM_GROUPGRAPHICS,
10165     sizeof(GRP_dictionary) / sizeof(DCMDICT), GRP_dictionary},
10166     {DCM_GROUPMEDIA,
10167     sizeof(MED_dictionary) / sizeof(DCMDICT), MED_dictionary},
10168     {DCM_GROUPBASICFILMSESSION,
10169     sizeof(BFS_dictionary) / sizeof(DCMDICT), BFS_dictionary},
10170     {DCM_GROUPBASICFILMBOX,
10171     sizeof(BFB_dictionary) / sizeof(DCMDICT), BFB_dictionary},
10172     {DCM_GROUPBASICIMAGEBOX,
10173     sizeof(BIB_dictionary) / sizeof(DCMDICT), BIB_dictionary},
10174     {DCM_GROUPBASICANNOTATIONBOX,
10175     sizeof(BAB_dictionary) / sizeof(DCMDICT), BAB_dictionary},
10176 
10177     {DCM_GROUPBASICIMAGEOVERLAYBOX,
10178     sizeof(IOB_dictionary) / sizeof(DCMDICT), IOB_dictionary},
10179 
10180     {0x2050,
10181     sizeof(PLUT_dictionary) / sizeof(DCMDICT), PLUT_dictionary},
10182 
10183     {DCM_GROUPPRINTJOB,
10184     sizeof(PJ_dictionary) / sizeof(DCMDICT), PJ_dictionary},
10185 
10186     {DCM_GROUPPRINTER,
10187     sizeof(PRN_dictionary) / sizeof(DCMDICT), PRN_dictionary},
10188     {0x3002,
10189     sizeof(G3002_dictionary) / sizeof(DCMDICT), G3002_dictionary},
10190     {0x3004,
10191     sizeof(DVH_dictionary) / sizeof(DCMDICT), DVH_dictionary},
10192     {0x3006,
10193     sizeof(SSET_dictionary) / sizeof(DCMDICT), SSET_dictionary},
10194     {0x300a,
10195     sizeof(G300A_dictionary) / sizeof(DCMDICT), G300A_dictionary},
10196     {0x300c,
10197     sizeof(G300C_dictionary) / sizeof(DCMDICT), G300C_dictionary},
10198     {0x300e,
10199     sizeof(G300E_dictionary) / sizeof(DCMDICT), G300E_dictionary},
10200 
10201 /*  Add this entry in when we define retired attributes
10202 **  in text group.
10203 */
10204 #if 0
10205     {DCM_GROUPTEXT,
10206     sizeof(TXT_dictionary) / sizeof(DCMDICT), TXT_dictionary},
10207 #endif
10208     {DCM_GROUPRESULTS,
10209     sizeof(RES_dictionary) / sizeof(DCMDICT), RES_dictionary},
10210     {DCM_GROUPCURVE,
10211     sizeof(CRV_dictionary) / sizeof(DCMDICT), CRV_dictionary},
10212     {DCM_GROUPOVERLAY,
10213     sizeof(OLY_dictionary) / sizeof(DCMDICT), OLY_dictionary},
10214     {DCM_GROUPPIXEL,
10215     sizeof(PXL_dictionary) / sizeof(DCMDICT), PXL_dictionary},
10216     {DCM_GROUPPAD,
10217     sizeof(PAD_dictionary) / sizeof(DCMDICT), PAD_dictionary},
10218     {DCM_GROUPDELIMITER,
10219     sizeof(DLM_dictionary) / sizeof(DCMDICT), DLM_dictionary}
10220 };
10221 
10222 
10223 /* DCM_LookupElement
10224 **
10225 ** Purpose:
10226 **      Lookup an element in the DICOM dictionary and return information
10227 **      about the element, including representation, type and english
10228 **      description.
10229 **
10230 ** Parameter Dictionary:
10231 **      element         Pointer to an DCM element (group, element) to
10232 **                      be found in the dictionary.
10233 **
10234 ** Return Values:
10235 **      DCM_NORMAL
10236 **      DCM_UNRECOGNIZEDGROUP
10237 **      DCM_UNRECOGNIZEDELEMENT
10238 **
10239 ** Algorithm:
10240 **      Set representation, type, englishDescription fields of caller's
10241 **      element to NULL values
10242 **      Search group_dictionary to find caller's group.
10243 **      If group not found,
10244 **          return DCM_UNRECOGNIZEDGROUP
10245 **      Search particular group list to find caller's element.
10246 **      If element not found,
10247 **          return DCM_UNRECOGNIZEDELEMENT
10248 **      Else
10249 **          Copy representation, type, englishDescription from dictionary
10250 **          to caller's element
10251 **          return DCM_NORMAL
10252 **      EndIf
10253 */
10254 
10255 CONDITION
10256 DCM_LookupElement(DCM_ELEMENT * element)
10257 {
10258     int
10259         found;
10260     unsigned long
10261         index,
10262         entries;
10263     GROUPPTR
10264         * p;
10265     DCMDICT
10266         * dictionaryPtr;
10267 
10268     element->representation = DCM_UN;
10269     (void) strcpy(element->description, "");
10270 
10271     for (index = 0, p = NULL;
10272          index < sizeof(group_dictionary) / sizeof(group_dictionary[0]) && p == NULL;
10273          index++)
10274         if (DCM_TAG_GROUP(element->tag) == group_dictionary[index].group)
10275             p = &group_dictionary[index];
10276 
10277     if (p == NULL) {
10278         if (DCM_TAG_ELEMENT(element->tag) == 0x0000) {
10279             element->representation = DCM_UL;
10280             (void) strcpy(element->description, "Unknown group length");
10281             return DCM_NORMAL;
10282         }
10283         return COND_PushCondition(DCM_UNRECOGNIZEDGROUP,
10284                                   DCM_Message(DCM_UNRECOGNIZEDGROUP),
10285                                   DCM_TAG_GROUP(element->tag),
10286                                   "DCM_LookupElement");
10287     }
10288     entries = p->entries;
10289     dictionaryPtr = p->dict;
10290 
10291     for (found = 0; !found && entries > 0; entries--)
10292         if (element->tag == dictionaryPtr->tag)
10293             found++;
10294         else
10295             dictionaryPtr++;
10296 
10297     if (!found)
10298         return COND_PushCondition(DCM_UNRECOGNIZEDELEMENT,
10299                                   DCM_Message(DCM_UNRECOGNIZEDELEMENT),
10300                                   DCM_TAG_GROUP(element->tag),
10301                                   DCM_TAG_ELEMENT(element->tag),
10302                                   "DCM_LookupElement");
10303 
10304 
10305     element->representation = dictionaryPtr->representation;
10306     (void) strcpy(element->description, dictionaryPtr->englishDescription);
10307     return DCM_NORMAL;
10308 }
10309 
10310 typedef struct {
10311     unsigned short group;
10312     char *description;
10313 }   GROUP_DESCRIPTION;
10314 
10315 static GROUP_DESCRIPTION groupTable[] = {
10316     {0x0000, "Command"},
10317     {0x0002, "File Meta"},
10318     {0x0004, "Basic Directory Information"},
10319     {0x0008, "Identifying"},
10320     {0x0010, "Patient Information"},
10321     {0x0018, "Acquisition"},
10322     {0x0020, "Relationship"},
10323     {0x0028, "Image"},
10324     {0x0032, "Study"},
10325     {0x0038, "Visit"},
10326     {0x003a, "Waveform"},
10327     {0x0040, "Procedure Step"},
10328     {0x0050, "Device"},
10329     {0x0054, "NM Image"},
10330     {0x0070, "Graphics"},
10331     {0x0088, "Media"},
10332     {0x2000, "Basic Film Session"},
10333     {0x2010, "Basic Film Box"},
10334     {0x2020, "Basic Image Box"},
10335     {0x2030, "Basic Annotation Box"},
10336     {0x2040, "Basic Image Overlay Box"},
10337     {0x2050, "Presentation LUT"},
10338     {0x2100, "Print Job"},
10339     {0x2110, "Printer"},
10340     {0x3002, "RT"},
10341     {0x3004, "Dose Volume Histogram"},
10342     {0x3006, "Structure Set"},
10343     {0x300a, "300a"},
10344     {0x300c, "300c"},
10345     {0x300e, "300e"},
10346 #if 0
10347     {0x4000, "Text"},
10348 #endif
10349     {0x4008, "Results"},
10350     {0x5000, "Curve"},
10351     {0x6000, "Overlay"},
10352     {0x7fe0, "Pixel"}
10353 };
10354 
10355 
10356 /* DCM_GroupDictionary
10357 **
10358 ** Purpose:
10359 **      DCM_GroupDictionary is used to lookup descriptions of groups in
10360 **      the internal DCM group dictionary.  Caller specifies one group
10361 **      with a group number or all groups by passing 0xffff.  For each
10362 **      group that matches (the one group or wildcard), this function
10363 **      invokes the caller's callback function.
10364 **      When the callback function is invoked, the arguments are the
10365 **      group number, an ASCII description of the group and user context
10366 **      information that was passed by the caller originally.
10367 **
10368 ** Parameter Dictionary:
10369 **      group           The number of the group to be found in the dictionary.
10370 **      ctx             User context information to be passed to callback
10371 **                      function.
10372 **      callback        The user's callback function, invoked once for each
10373 **                      group that is found during the dictionary lookup.
10374 **
10375 ** Return Values:
10376 **      DCM_NORMAL
10377 ** Notes:
10378 **
10379 ** Algorithm:
10380 **      Description of the algorithm (optional) and any other notes.
10381 */
10382 
10383 CONDITION
10384 DCM_GroupDictionary(unsigned short group, void *ctx,
10385           void (*callback) (unsigned short g, char *description, void *ctx))
10386 {
10387     int i;
10388 
10389     for (i = 0; i < (int) DIM_OF(groupTable); i++) {
10390         if ((group == 0xffff) || (group == groupTable[i].group)) {
10391             callback(groupTable[i].group, groupTable[i].description, ctx);
10392         }
10393     }
10394     return DCM_NORMAL;
10395 }
10396 
10397 /* DCM_ElementDictionary
10398 **
10399 ** Purpose:
10400 **      DCM_ElementDictionary is used to lookup descriptions of elements in
10401 **      the internal DCM element dictionary.  The caller can specify one
10402 **      element to be found or a number of elements as follows:
10403 **              (Group,  Element)       Description
10404 **              GGGG,    EEEE           Lookup one particular element (GGGGEEEE)
10405 **              GGGG,    0xffff         Lookup all elements in group GGGG
10406 **              0xffff,  EEEE           Lookup all elements in all groups with
10407 **                                      element number EEEE
10408 **              0xffff,  0xffff         Lookup all elements in all groups
10409 **      For each element that matches (the one element or wildcard), this
10410 **      function invokes the caller's callback function.
10411 **      When the callback function is invoked, the arguments are the
10412 **      element tag, an ASCII description of the element, the element value
10413 **      representation and user context information that was passed by
10414 **      the caller originally.
10415 **
10416 ** Parameter Dictionary:
10417 **      tag             The tag of the element to be found in the dictionary.
10418 **      ctx             User context information to be passed to callback
10419 **                      function.
10420 **      callback        The user's callback function, invoked once for each
10421 **                      element that is found during the dictionary lookup.
10422 **
10423 ** Return Values:
10424 **      DCM_NORMAL
10425 ** Notes:
10426 **
10427 ** Algorithm:
10428 **      Description of the algorithm (optional) and any other notes.
10429 */
10430 
10431 CONDITION
10432 DCM_ElementDictionary(DCM_TAG tag, void *ctx,
10433   void (*callback) (DCM_TAG t, char *description, DCM_VALUEREPRESENTATION r,
10434                     void *ctx))
10435 {
10436     int i;
10437     unsigned long j;
10438     GROUPPTR *p;
10439     DCMDICT *dictionaryPtr;
10440 
10441     for (i = 0; i < (int) DIM_OF(group_dictionary); i++) {
10442         if ((DCM_TAG_GROUP(tag) == group_dictionary[i].group) ||
10443             (DCM_TAG_GROUP(tag) == 0xffff)) {
10444             p = &group_dictionary[i];
10445             dictionaryPtr = p->dict;
10446             for (j = 0; j < p->entries; j++, dictionaryPtr++) {
10447                 if ((DCM_TAG_ELEMENT(tag) == 0xffff) ||
10448                     (DCM_TAG_ELEMENT(tag) == DCM_TAG_ELEMENT(dictionaryPtr->tag))) {
10449                     callback(dictionaryPtr->tag,
10450                              dictionaryPtr->englishDescription,
10451                              dictionaryPtr->representation,
10452                              ctx);
10453                 }
10454             }
10455         }
10456     }
10457     return DCM_NORMAL;
10458 }
10459 /*
10460           Copyright (C) 1993, 1994, RSNA and Washington University
10461 
10462           The software and supporting documentation for the Radiological
10463           Society of North America (RSNA) 1993, 1994 Digital Imaging and
10464           Communications in Medicine (DICOM) Demonstration were developed
10465           at the
10466                   Electronic Radiology Laboratory
10467                   Mallinckrodt Institute of Radiology
10468                   Washington University School of Medicine
10469                   510 S. Kingshighway Blvd.
10470                   St. Louis, MO 63110
10471           as part of the 1993, 1994 DICOM Central Test Node project for, and
10472           under contract with, the Radiological Society of North America.
10473 
10474           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
10475           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
10476           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
10477           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
10478           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
10479           THE SOFTWARE IS WITH THE USER.
10480 
10481           Copyright of the software and supporting documentation is
10482           jointly owned by RSNA and Washington University, and free access
10483           is hereby granted as a license to use this software, copy this
10484           software and prepare derivative works based upon this software.
10485           However, any distribution of this software source code or
10486           supporting documentation or derivative works (source code and
10487           supporting documentation) must include the three paragraphs of
10488           the copyright notice.
10489 */
10490 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
10491 
10492 /*
10493 **                              DICOM 93
10494 **                   Electronic Radiology Laboratory
10495 **                 Mallinckrodt Institute of Radiology
10496 **              Washington University School of Medicine
10497 **
10498 ** Module Name(s):
10499 **                      DCM_ListToString
10500 **                      DCM_IsString
10501 ** Author, Date:        Stephen M. Moore, 13-Jun-93
10502 ** Intent:              This file contains more DCM routines which are used
10503 **                      as support for the DCM facility and for applications.
10504 **                      These routines help parse strings and other data
10505 **                      values that are encoded in DICOM objects.
10506 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
10507 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
10508 ** Revision:            $Revision: 1.21 $
10509 ** Status:              $State: Exp $
10510 */
10511 
10512 /* DCM_ListToString
10513 **
10514 ** Purpose:
10515 **      Convert the list of strings into a single string separated by '\'
10516 **
10517 ** Parameter Dictionary:
10518 **      list            Handle to the list of strings
10519 **      offset          The actual string starts at "offset" offset in
10520 **                      each individual structure chained in the list
10521 **      string          The single large string returned to the caller
10522 **
10523 ** Return Values:
10524 **      DCM_NORMAL
10525 **      DCM_LISTFAILURE
10526 **      DCM_MALLOCFAILURE
10527 **
10528 ** Notes:
10529 **
10530 ** Algorithm:
10531 **      Description of the algorithm (optional) and any other notes.
10532 */
10533 typedef struct {
10534     void *reserved[2];
10535     char *s;
10536 }   GENERIC;
10537 
10538 CONDITION
10539 DCM_ListToString(LST_HEAD * list, long offset, char **string)
10540 {
10541     GENERIC
10542         * g;
10543     char
10544        *c,
10545        *p;
10546     long
10547         length;
10548 
10549     *string = NULL;
10550     if (list == NULL)
10551         return DCM_NORMAL;
10552 
10553     g = (void *)LST_Head(&list);
10554     if (g == NULL)
10555         return DCM_NORMAL;
10556 
10557     (void) LST_Position(&list, (void *)g);
10558 
10559     length = 0;
10560     while (g != NULL) {
10561         c = ((char *) g) + offset;
10562         length += strlen(c) + 1;
10563         g = (void *)LST_Next(&list);
10564     }
10565 
10566     p = CTN_MALLOC(length);
10567     if (p == NULL)
10568         return COND_PushCondition(DCM_MALLOCFAILURE,
10569                 DCM_Message(DCM_MALLOCFAILURE), length, "DCM_ListToString");
10570 
10571     *string = p;
10572     g = (void *)LST_Head(&list);
10573     if (g == NULL)
10574         return COND_PushCondition(DCM_LISTFAILURE, DCM_Message(DCM_LISTFAILURE),
10575                                   "DCM_ListToString");
10576     (void) LST_Position(&list, (void *)g);
10577 
10578     length = 0;
10579     while (g != NULL) {
10580         c = ((char *) g) + offset;
10581         length = strlen(c);
10582         (void) memcpy(p, c, length);
10583         p += length;
10584         *p++ = '\\';
10585         g = (void *)LST_Next(&list);
10586     }
10587     *--p = '\0';
10588     return DCM_NORMAL;
10589 }
10590 
10591 
10592 /* DCM_IsString
10593 **
10594 ** Purpose:
10595 **      Verify if the DICOM value representation is that of a string
10596 **
10597 ** Parameter Dictionary:
10598 **      representation          One of the many DICOM value representations
10599 **
10600 ** Return Values:
10601 **      TRUE
10602 **      FALSE
10603 **
10604 ** Notes:
10605 **
10606 ** Algorithm:
10607 **      Description of the algorithm (optional) and any other notes.
10608 */
10609 
10610 CTNBOOLEAN
10611 DCM_IsString(DCM_VALUEREPRESENTATION representation)
10612 {
10613     CTNBOOLEAN
10614         flag = FALSE;
10615 
10616     switch (representation) {
10617     case DCM_AE:                /* Application Entity */
10618     case DCM_AS:                /* Age string */
10619         flag = TRUE;
10620         break;
10621     case DCM_AT:                /* Attribute tag */
10622         break;
10623     case DCM_CS:                /* Control string */
10624     case DCM_DA:                /* Date */
10625         flag = TRUE;
10626         break;
10627     case DCM_DD:                /* Data set */
10628         break;
10629     case DCM_DS:                /* Decimal string */
10630     case DCM_DT:                /* Old date/time */
10631         flag = TRUE;
10632         break;
10633     case DCM_FD:                /* Floating double */
10634     case DCM_FL:                /* Float */
10635         break;
10636     case DCM_IS:                /* Integer string */
10637     case DCM_LO:                /* Long string */
10638     case DCM_LT:                /* Long text */
10639         flag = TRUE;
10640         break;
10641     case DCM_OB:                /* Other binary value (byte) */
10642     case DCM_OT:                /* Other binary value */
10643     case DCM_OW:                /* Other binary value (word) */
10644         break;
10645     case DCM_SH:                /* Short string */
10646         flag = TRUE;
10647         break;
10648     case DCM_SL:                /* Signed long */
10649     case DCM_SQ:                /* Sequence of items */
10650     case DCM_SS:                /* Signed short */
10651         break;
10652     case DCM_ST:                /* Short text */
10653     case DCM_TM:                /* Time */
10654         flag = TRUE;
10655         break;
10656     case DCM_UL:                /* Unsigned long */
10657     case DCM_US:                /* Unsigned short */
10658     /*case DCM_UNKNOWN:*/       /* Unknown/unspecified */
10659     case DCM_RET:               /* Retired */
10660     case DCM_CTX:               /* Context sensitive */
10661         break;
10662     case DCM_PN:                /* Person Name */
10663     case DCM_UI:                /* Unique identifier (UID) */
10664     case DCM_UT:                /* Unlimited Text */
10665         flag = TRUE;
10666         break;
10667     };
10668     return flag;
10669 }
10670 /*
10671           Copyright (C) 1993, RSNA and Washington University
10672 
10673           The software and supporting documentation for the Radiological
10674           Society of North America (RSNA) 1993 Digital Imaging and
10675           Communications in Medicine (DICOM) Demonstration were developed
10676           at the
10677                   Electronic Radiology Laboratory
10678                   Mallinckrodt Institute of Radiology
10679                   Washington University School of Medicine
10680                   510 S. Kingshighway Blvd.
10681                   St. Louis, MO 63110
10682           as part of the 1993 DICOM Central Test Node project for, and
10683           under contract with, the Radiological Society of North America.
10684 
10685           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
10686           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
10687           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
10688           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
10689           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
10690           THE SOFTWARE IS WITH THE USER.
10691 
10692           Copyright of the software and supporting documentation is
10693           jointly owned by RSNA and Washington University, and free access
10694           is hereby granted as a license to use this software, copy this
10695           software and prepare derivative works based upon this software.
10696           However, any distribution of this software source code or
10697           supporting documentation or derivative works (source code and
10698           supporting documentation) must include the three paragraphs of
10699           the copyright notice.
10700 */
10701 /*
10702 ** @$=@$=@$=
10703 */
10704 /*
10705 **                              DICOM 93
10706 **                   Electronic Radiology Laboratory
10707 **                 Mallinckrodt Institute of Radiology
10708 **              Washington University School of Medicine
10709 **
10710 ** Module Name(s):
10711 ** Author, Date:        Thomas R. Leith, 15-Apr-93
10712 ** Intent:              This package implements atomic functions on
10713 **                      linked lists.
10714 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
10715 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
10716 ** Revision:            $Revision: 1.21 $
10717 ** Status:              $State: Exp $
10718 */
10719 
10720 #define CURRENT  (*list)->current
10721 #define OLD_NEXT (*list)->current->next
10722 #define OLD_PREV (*list)->current->previous
10723 
10724 
10725 
10726 LST_HEAD *
10727 LST_Create(void)
10728 /*
10729 **  This module creates a new list head and returns your handle to it.
10730 **
10731 */
10732 {
10733     LST_HEAD
10734     * ptr;
10735 
10736     ptr = CTN_MALLOC(sizeof(LST_HEAD));
10737     if (ptr == NULL)
10738         return NULL;
10739 
10740     ptr->head = NULL;
10741     ptr->tail = NULL;
10742     ptr->current = NULL;
10743     ptr->count = 0;
10744     return ptr;
10745 }
10746 
10747 
10748 
10749 CONDITION
10750 LST_Destroy(LST_HEAD ** list)
10751 /*
10752  *  This routine will destroy a list.  The list must be empty.
10753  *  The list handle is set to NULL as a side-effect.
10754  *
10755  */
10756 {
10757 
10758     if ((*list)->count != 0)
10759         return LST_LISTNOTEMPTY;
10760 
10761     CTN_FREE(*list);
10762     *list = NULL;
10763     return LST_NORMAL;
10764 }
10765 
10766 
10767 
10768 CONDITION
10769 LST_Enqueue(LST_HEAD ** list, LST_NODE * node)
10770 /*
10771  *  Adds a new node to the tail of the list and returns
10772  *  status.
10773  *
10774  */
10775 {
10776     node->next = NULL;          /* no next node              */
10777     node->previous = (*list)->tail;     /* previous is old tail      */
10778     if ((*list)->head == NULL)  /* if list was empty...      */
10779         (*list)->head = node;   /* it has a head now!        */
10780     else
10781         (*list)->tail->next = node;     /* old tail now has a next   */
10782 
10783     (*list)->tail = node;       /* list now has a new tail    */
10784     (*list)->count++;           /* bump the counter           */
10785     return LST_NORMAL;
10786 }
10787 
10788 CONDITION
10789 LST_Push(LST_HEAD ** list, LST_NODE * node)
10790 /*
10791  *  Adds a new node to the head of the list and returns
10792  *  status.
10793  *
10794  */
10795 
10796 {
10797     node->next = (*list)->head; /* set the forward link      */
10798     node->previous = NULL;      /* set rearward link         */
10799     if ((*list)->tail == NULL)  /* if the list was empty     */
10800         (*list)->tail = node;   /* set the tail pointer      */
10801     else                        /* otherwise,                */
10802         (*list)->head->previous = node; /* old head now has a previous                  */
10803 
10804     (*list)->head = node;       /* set new first node        */
10805     (*list)->count++;           /* bump the counter          */
10806     return LST_NORMAL;
10807 
10808 }
10809 
10810 LST_NODE *
10811 LST_Dequeue(LST_HEAD ** list)
10812 /*
10813  *  Removes a node from the head of the list and returns
10814  *  a pointer to it.
10815  *
10816  */
10817 {
10818     LST_NODE
10819     * ptr;
10820 
10821     if ((*list)->head == NULL) {/* list is empty             */
10822         (*list)->count = 0;
10823         return NULL;
10824     }
10825     ptr = (*list)->head;        /* save the head             */
10826     (*list)->head = ptr->next;  /* set new head of list      */
10827     if ((*list)->head == NULL)  /* if the list is now empty  */
10828         (*list)->tail = NULL;   /* there is no tail anymore  */
10829     else
10830         (*list)->head->previous = NULL; /* new head has no previous  */
10831     ptr->next = NULL;           /* hide data from user       */
10832     (*list)->count--;           /* list has one fewer node   */
10833     /* now                       */
10834     return ptr;
10835 }
10836 
10837 
10838 
10839 LST_NODE *
10840 LST_Pop(LST_HEAD ** list)
10841 /*
10842  *  Removes a node from the head of the list and returns
10843  *  a pointer to it.
10844  *
10845  */
10846 {
10847     LST_NODE
10848     * ptr;
10849 
10850     if ((*list)->head == NULL) {/* list is empty             */
10851         (*list)->count = 0;
10852         return NULL;
10853     }
10854     ptr = (*list)->head;        /* save the head             */
10855     (*list)->head = ptr->next;  /* set new head of list      */
10856     if ((*list)->head == NULL)  /* if the list is now empty  */
10857         (*list)->tail = NULL;   /* there is no tail anymore  */
10858     else
10859         (*list)->head->previous = NULL; /* new head has no previous  */
10860     ptr->next = NULL;           /* hide data from user       */
10861     (*list)->count--;           /* list has one fewer node   */
10862     /* now                       */
10863     return ptr;
10864 }
10865 
10866 
10867 
10868 unsigned long
10869 LST_Count(LST_HEAD ** list)
10870 /*
10871  *  Returns the number of nodes in the list.
10872  *
10873  */
10874 {
10875     return (*list)->count;
10876 }
10877 
10878 
10879 
10880 LST_NODE *
10881 LST_Head(LST_HEAD ** list)
10882 /*
10883  *  Returns a pointer to the node at the head of the list.
10884  *  It does NOT remove the node from the list.
10885  *
10886  */
10887 {
10888     return (*list)->head;
10889 }
10890 
10891 
10892 LST_NODE *
10893 LST_Current(LST_HEAD ** list)
10894 /*
10895  *  Returns a pointer to the current node.
10896  *  It does NOT remove the node from the list.
10897  *
10898  */
10899 {
10900     return (*list)->current;
10901 }
10902 
10903 
10904 
10905 LST_NODE *
10906 LST_Tail(LST_HEAD ** list)
10907 /*
10908  *  Returns a pointer to the node at the tail of the list.
10909  *  It does NOT remove the node from the list.
10910  *
10911  */
10912 {
10913     return (*list)->tail;
10914 }
10915 
10916 
10917 CONDITION
10918 LST_Insert(LST_HEAD ** list, LST_NODE * node, LST_END where)
10919 /*
10920 **  Inserts a new node in the list.  User selects whether to insert closer
10921 **  the HEAD end, or the TAIL end.  If the list is empty, the distinction is
10922 **  moot.  In any case, CURRENT is set to the newly-inserted node.  In the
10923 **  case of an error, the list is unchanged.
10924 **/
10925 
10926 {
10927     if ((where != LST_K_BEFORE) && (where != LST_K_AFTER))
10928         goto badend;
10929 
10930     if ((*list)->head == NULL) {/* if the list was empty     */
10931         (*list)->tail = node;   /* set the tail pointer      */
10932         (*list)->head = node;   /* set the head pointer      */
10933         (*list)->count = 0;     /* will get bumped later...  */
10934         (node)->next = NULL;    /* there is no next          */
10935         (node)->previous = NULL;/* and no previous           */
10936 
10937     } else if (CURRENT == NULL) /* is he mixing semantics?       */
10938         goto nocurrent;
10939 
10940     else if ((CURRENT == (*list)->head) &&      /* if at the head           */
10941              (where == LST_K_BEFORE)) { /* and inserting BEFORE   */
10942         node->next = CURRENT;   /* splice new node in       */
10943         CURRENT->previous = node;       /* before the current     */
10944         node->previous = NULL;  /* new one has no previous  */
10945         (*list)->head = node;   /* new one is first now     */
10946 
10947     } else if ((CURRENT == (*list)->tail) &&    /* if at the tail           */
10948                (where == LST_K_AFTER)) {        /* and inserting AFTER    */
10949         node->next = NULL;      /* new node has no next     */
10950         node->previous = (*list)->tail; /* previous is old tail     */
10951         CURRENT->next = node;   /* splice new node in       */
10952         (*list)->tail = node;   /* new node is now the tail */
10953 
10954     } else if (where == LST_K_AFTER) {  /* not a special case       */
10955         OLD_NEXT->previous = node;      /* we preceed a node        */
10956         node->next = OLD_NEXT;  /* the old next follows us  */
10957         node->previous = CURRENT;       /* the current preceeds us  */
10958         CURRENT->next = node;   /* we follow current        */
10959 
10960     } else {                    /* not a special case       */
10961         OLD_PREV->next = node;  /* we follow the previous   */
10962         node->previous = OLD_PREV;      /* of current            */
10963         node->next = CURRENT;   /* current follows us and   */
10964         CURRENT->previous = node;       /* we preceed current     */
10965     };
10966 
10967     (*list)->count++;           /* bump the counter          */
10968     (*list)->current = node;    /* and set current        */
10969     return LST_NORMAL;
10970 
10971 badend:
10972     return LST_BADEND;
10973 
10974 nocurrent:
10975     return LST_NOCURRENT;
10976 }
10977 
10978 
10979 
10980 LST_NODE *
10981 LST_Remove(LST_HEAD ** list, LST_END dir)
10982 /*
10983 **  Removes the current node from the list and returns a pointer to it.
10984 **  How CURRENT gets set depends on which way the DIR argument points.  If
10985 **  DIR is LST_K_BEFORE, CURRENT will move towards the tail-end of the
10986 **  list.  If DIR is LST_K_AFTER, CURRENT will move towards the head-end of
10987 **  the list.  If there is no node in the direction of DIR, CURRENT becomes
10988 **  undefined.
10989 **
10990 **/
10991 {
10992     LST_NODE
10993     * ptr;
10994 
10995     if ((dir != LST_K_BEFORE) && (dir != LST_K_AFTER))
10996         goto baddir;
10997     if (CURRENT == NULL)
10998         goto nocurrent;
10999     if ((*list)->head == NULL)
11000         goto listempty;
11001 
11002     ptr = CURRENT;              /* save node                 */
11003 
11004     if (CURRENT == (*list)->head) {     /* removing the head         */
11005         (*list)->head = OLD_NEXT;       /* set new head of list      */
11006         if ((*list)->head == NULL)      /* if the list is now empty  */
11007             (*list)->tail = NULL;       /* no tail anymore either    */
11008         else
11009             (*list)->head->previous = NULL;     /* new head has no previous  */
11010         if (dir == LST_K_BEFORE)/* there is nothing before   */
11011             (*list)->current = NULL;    /* the head of the list      */
11012         else                    /* otherwise, remain         */
11013             (*list)->current = (*list)->head;   /* at the head...         */
11014 
11015     } else if (CURRENT == (*list)->tail) {      /* removing the tail         */
11016         (*list)->tail = OLD_PREV;       /* set new tail of list      */
11017         (*list)->tail->next = NULL;     /* new tail has no next      */
11018         if (dir == LST_K_AFTER) /* there is nothing after    */
11019             (*list)->current = NULL;    /* the tail of a list        */
11020         else                    /* otherwise, remain         */
11021             (*list)->current = (*list)->tail;   /* at the tail...            */
11022 
11023     } else {                    /* not a special case        */
11024         OLD_PREV->next = CURRENT->next; /* set forward pointer       */
11025         OLD_NEXT->previous = CURRENT->previous; /* set backward pointer      */
11026         if (dir == LST_K_BEFORE)/* depending on direction,   */
11027             (*list)->current = CURRENT->previous;       /* set current             */
11028         else                    /* in the                    */
11029             (*list)->current = CURRENT->next;   /* list head                 */
11030     }
11031 
11032     (*list)->count--;           /* one fewer nodes now       */
11033     ptr->previous = NULL;       /* hide data from user       */
11034     ptr->next = NULL;           /* hide data from user       */
11035     return ptr;
11036 
11037 baddir:
11038     return NULL;
11039 
11040 nocurrent:
11041     return NULL;
11042 
11043 listempty:
11044     (*list)->count = 0;
11045     (*list)->current = NULL;
11046     (*list)->head = (*list)->tail = NULL;
11047     return NULL;
11048 }
11049 
11050 
11051 
11052 LST_NODE *
11053 LST_Next(LST_HEAD ** list)
11054 /*
11055  *  Returns a pointer to the next node in the list and
11056  *  makes it current.
11057  *
11058  */
11059 {
11060     if ((*list)->head == NULL) {/* list is empty            */
11061         (*list)->count = 0;
11062         return NULL;
11063     }
11064     if (CURRENT == NULL) {      /* there is no CURRENT      */
11065         return NULL;
11066     }
11067     CURRENT = CURRENT->next;    /* Set current to next and return it */
11068     return CURRENT;
11069 }
11070 
11071 
11072 
11073 LST_NODE *
11074 LST_Previous(LST_HEAD ** list)
11075 /*
11076  *  Returns a pointer to the previous node in the list and
11077  *  makes it current.
11078  *
11079  */
11080 {
11081     if ((*list)->head == NULL) {/* list is empty     */
11082         (*list)->count = 0;
11083         return NULL;
11084     }
11085     if (CURRENT == NULL) {      /* there is no CURRENT       */
11086         return NULL;
11087     }
11088     if (CURRENT->previous == NULL) {    /* no PREVIOUS               */
11089         return NULL;
11090     }
11091     CURRENT = CURRENT->previous;/* found it                  */
11092     return CURRENT;
11093 }
11094 
11095 
11096 
11097 LST_NODE *
11098 LST_Position(LST_HEAD ** list, LST_NODE * node)
11099 /*
11100  *  Make a node current and return the argument.
11101  *
11102  *
11103  *  Notes:  node = lst_position(list, lst_head(list));
11104  *          makes the node at the head of the list current
11105  *          and returns a pointer to it.
11106  *
11107  *      The routine tries to verify that "node" is in the list
11108  *      by doing a few consistency checks.  It assumes that if
11109  *      any of three "known" pointers are what they should be
11110  *      that all is well.  Its not damnfoolproof, but...
11111  */
11112 {
11113     if ((*list)->head == NULL) {/* list is empty     */
11114         return NULL;
11115     }
11116     if (node == NULL)
11117         return NULL;
11118     if (((node->previous == NULL) && ((*list)->head == node)) ||
11119         ((node->next == NULL) && ((*list)->tail == node)) ||
11120         (node->previous->next == node)) {       /* its probably OK       */
11121 
11122         CURRENT = node;
11123         return CURRENT;
11124     };
11125 
11126     return NULL;
11127 }
11128 
11129 /*
11130  *  Sort a list in order according to a comparison algorithm provided
11131  *  by the caller.
11132  *
11133  */
11134 CONDITION
11135 LST_Sort(LST_HEAD ** list, size_t nodeSize, int (*compare) ())
11136 {
11137     LST_NODE
11138         * n1,
11139         *n2;
11140     LST_HEAD
11141         temp,
11142         *head;
11143     CTNBOOLEAN
11144         inserted;
11145     int ccc ;
11146 
11147     if ((*list)->head == NULL) {/* list is empty     */
11148         return LST_NORMAL;
11149     }
11150     head = &temp;
11151     head->head = NULL;
11152     head->tail = NULL;
11153     head->current = NULL;
11154     head->count = 0;
11155 
11156     while ((n1 = LST_Dequeue(list)) != NULL) {
11157         n2 = LST_Head(&head);
11158         if (n2 != NULL)
11159             (void) LST_Position(&head, n2);
11160         inserted = FALSE;
11161         while (n2 != NULL && !inserted) {
11162 #if 0
11163             if (compare(n1, n2) < 0) {
11164 #else
11165             AFNI_CALL_VALU_2ARG(compare,int,ccc,LST_NODE *,n1,LST_NODE *,n2) ;
11166             if( ccc < 0 ){
11167 #endif
11168                 (void) LST_Insert(&head, n1, LST_K_BEFORE);
11169                 inserted = TRUE;
11170             } else
11171                 n2 = LST_Next(&head);
11172         }
11173         if (n2 == NULL)
11174             (void) LST_Enqueue(&head, n1);
11175     }
11176     **list = *head;
11177     return LST_NORMAL;
11178 }
11179 
11180 /*
11181  *  Return the item at position index.  Can be NULL if list is
11182  *  empty or we go off the end of the list.
11183  *
11184  */
11185 LST_NODE *
11186 LST_Index(LST_HEAD ** l, int index)
11187 {
11188     LST_NODE
11189     * n;
11190 
11191     n = LST_Head(l);
11192     if (n == NULL)
11193         return NULL;
11194 
11195     index--;
11196     LST_Position(l, n);
11197     while (index-- > 0 && n != NULL)
11198         n = LST_Next(l);
11199 
11200     return n;
11201 }
11202 /*
11203           Copyright (C) 1993, 1994, RSNA and Washington University
11204 
11205           The software and supporting documentation for the Radiological
11206           Society of North America (RSNA) 1993, 1994 Digital Imaging and
11207           Communications in Medicine (DICOM) Demonstration were developed
11208           at the
11209                   Electronic Radiology Laboratory
11210                   Mallinckrodt Institute of Radiology
11211                   Washington University School of Medicine
11212                   510 S. Kingshighway Blvd.
11213                   St. Louis, MO 63110
11214           as part of the 1993, 1994 DICOM Central Test Node project for, and
11215           under contract with, the Radiological Society of North America.
11216 
11217           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
11218           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
11219           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
11220           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
11221           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
11222           THE SOFTWARE IS WITH THE USER.
11223 
11224           Copyright of the software and supporting documentation is
11225           jointly owned by RSNA and Washington University, and free access
11226           is hereby granted as a license to use this software, copy this
11227           software and prepare derivative works based upon this software.
11228           However, any distribution of this software source code or
11229           supporting documentation or derivative works (source code and
11230           supporting documentation) must include the three paragraphs of
11231           the copyright notice.
11232 */
11233 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
11234 
11235 /*
11236 **                   Electronic Radiology Laboratory
11237 **                 Mallinckrodt Institute of Radiology
11238 **              Washington University School of Medicine
11239 **
11240 ** Module Name(s):      UTL_RegexMatch, UTL_ConvertRegex,
11241 **                      UTL_ConvertDatetoLong, UTL_ConvertLongtoDate,
11242 **                      UTL_ConvertTimetoFloat, UTL_ConvertFloattoTime,
11243 **                      UTL_SqueezeBlanks, UTL_DateMatch, UTL_TimeMatch
11244 **                      UTL_GetDicomDate, UTL_GetDicomTime
11245 **
11246 ** Author, Date:        David E. Beecher, March 1994
11247 ** Intent:              Miscellaneous functions that may be useful in
11248 **                      a number of different areas.
11249 **
11250 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:42 $
11251 ** Source File:         $RCSfile: mri_dicom_hdr.c,v $
11252 ** Revision:            $Revision: 1.21 $
11253 ** Status:              $State: Exp $
11254 */
11255 
11256 #if 0
11257 /* UTL_RegexMatch
11258 **
11259 ** Purpose:
11260 **      Perform a DICOM regular expression match with the specified string, stm.
11261 **
11262 ** Parameter Dictionary:
11263 **      char *regex:
11264 **              The DICOM regular expression to try and match.
11265 **      char *stm:
11266 **              The input string to match.
11267 **
11268 ** Return Values:
11269 **      UTL_MATCH:      The input string matched the regular expression.
11270 **      UTL_NOMATCH:    The input string did not match the regular expression.
11271 **
11272 ** Algorithm:
11273 **      A simple function to perform a DICOM regular expression match with the
11274 **      specified  string, stm.  The sematics of the DICOM patterns must be altered
11275 **      slightly to work correctly with regex under unix...more information may
11276 **      be found below.
11277 **
11278 */
11279 
11280 #ifdef DARWIN
11281 #define USEREGCOMP
11282 #endif
11283 
11284 #ifdef USEREGCOMP
11285 #include <regex.h>
11286 #endif
11287 
11288 CONDITION
11289 UTL_RegexMatch(char *regex, char *stm)
11290 {
11291 #ifdef USEREGCOMP
11292 
11293     int
11294         ret,
11295         regexReturn;
11296     char
11297        *new_rstring;
11298     regex_t preg;
11299     char errorBuff[256];
11300     regmatch_t pmatch;
11301 
11302     new_rstring = UTL_ConvertRegex(regex);
11303 
11304     regexReturn = regcomp(&preg, new_rstring, 0);
11305     if (regexReturn != 0) {
11306         regerror(regexReturn, &preg, errorBuff, sizeof(errorBuff));
11307         fprintf(stderr, "%d\n", regexReturn);
11308         fprintf(stderr, "%s\n", errorBuff);
11309 
11310         free(new_rstring);
11311         return (UTL_NOMATCH);
11312     } else {
11313         ret = regexec(&preg, stm, 1, &pmatch, 0);
11314 
11315         switch (ret) {
11316         case 0:
11317             free(new_rstring);
11318             return (UTL_MATCH);
11319             break;
11320         default:
11321             free(new_rstring);
11322             return (UTL_NOMATCH);
11323             break;
11324         }
11325     }
11326 #else
11327     int
11328         ret;
11329     char
11330        *new_rstring;
11331 
11332     new_rstring = UTL_ConvertRegex(regex);
11333     if (re_comp(new_rstring) != (char *) 0) {
11334         free(new_rstring);
11335         return (UTL_NOMATCH);
11336     } else {
11337         ret = re_exec(stm);
11338         switch (ret) {
11339         case 0:
11340         case -1:
11341             free(new_rstring);
11342             return (UTL_NOMATCH);
11343             break;
11344         case 1:
11345             free(new_rstring);
11346             return (UTL_MATCH);
11347             break;
11348         }
11349     }
11350 #endif
11351 }
11352 
11353 /* UTL_ConvertRegex
11354 **
11355 ** Purpose:
11356 **      This function converts a DICOM "regular expression" to the proper
11357 **      regex semantics under unix.
11358 **
11359 ** Parameter Dictionary:
11360 **      char *regex:
11361 **              The DICOM regular expression to convert.
11362 **
11363 ** Return Values:
11364 **      char *: The converted regular expression which expresses DICOM pattern
11365 **              matching in regex semantics.
11366 **
11367 ** Notes:
11368 **      This routine needs to return a string of unknown length.  Since we
11369 **      don't want to burden the caller with having to remember to free the
11370 **      string after it has been used, we simply reuse the same piece of storage
11371 **      and realloc it when necessary to increase the size.
11372 **
11373 ** Algorithm:
11374 **      Simple function to convert a DICOM "regular expression" to the proper
11375 **      regex semantics under unix.  DICOM has only 2 meta characters, "*" for 0
11376 **      or more occurrences, and "?" for a single character.  The "*" must be
11377 **      converted to ".*" for regex while the "?" must be converted to ".".
11378 **      Other special characters to regex like "[", "]", and "." must also
11379 **      be escaped with the "\".  The DICOM escape character is assumed to be "\".
11380 */
11381 char *
11382 UTL_ConvertRegex(char *regex)
11383 {
11384 
11385     char
11386        *new_regex = (char *) NULL;
11387     int
11388         malloced_size = 0;
11389     int
11390         i,
11391         j,
11392         escape_on;
11393 
11394     if (new_regex == (char *) NULL) {
11395         malloced_size = REGEX_SIZE;
11396         if ((new_regex = (char *) malloc(malloced_size)) == (char *) NULL) {
11397             return ((char *) NULL);
11398         }
11399     }
11400     i = j = 0;
11401     escape_on = OFF;
11402     new_regex[j++] = '^';
11403     while (regex[i] != '\000') {
11404         switch (regex[i]) {
11405         case '*':               /* Transform the "*" to ".*" or "\*" if
11406                                  * escaped */
11407             switch (escape_on) {
11408             case OFF:
11409                 new_regex[j++] = '.';
11410                 break;
11411             case ON:
11412                 new_regex[j++] = '\\';
11413                 escape_on = OFF;
11414                 break;
11415             }
11416             new_regex[j++] = '*';
11417             i++;
11418             break;
11419         case '?':               /* Transform the "?" to "." or "?" if escaped */
11420             switch (escape_on) {
11421             case OFF:
11422                 new_regex[j++] = '.';
11423                 break;
11424             case ON:
11425                 new_regex[j++] = '?';
11426                 escape_on = OFF;
11427                 break;
11428             }
11429             i++;
11430             break;
11431         case '\\':              /* Note that we have seen the escape
11432                                  * character */
11433             switch (escape_on) {
11434             case OFF:
11435                 escape_on = ON;
11436                 break;
11437             case ON:
11438                 escape_on = OFF;
11439                 new_regex[j++] = '\\';
11440                 new_regex[j++] = '\\';
11441                 break;
11442             }
11443             i++;
11444             break;
11445         case '.':
11446         case '[':               /* These are special to regex and need to be
11447                                  * escaped */
11448         case ']':
11449             new_regex[j++] = '\\';
11450             new_regex[j++] = regex[i++];
11451             escape_on = OFF;
11452             break;
11453         default:                /* Leave the "\" in at this juncture */
11454             switch (escape_on) {
11455             case ON:
11456                 new_regex[j++] = '\\';
11457                 escape_on = OFF;
11458                 break;
11459             case OFF:
11460                 break;
11461             }
11462             new_regex[j++] = regex[i++];
11463             break;
11464         }
11465         if (j >= (malloced_size - 2)) {
11466             malloced_size += REGEX_SIZE;
11467             if ((new_regex = (char *) realloc(new_regex, malloced_size)) ==
11468                 (char *) NULL) {
11469                 return ((char *) NULL);
11470             }
11471         }
11472     }
11473     new_regex[j++] = '$';
11474     new_regex[j] = '\000';
11475     return (new_regex);
11476 }
11477 #endif
11478 /* UTL_ConvertDatetoLong
11479 **      Convert a Dicom date to a long for comparision ease.
11480 */
11481 long
11482 UTL_ConvertDatetoLong(const char *date)
11483 {
11484 
11485     char
11486         year[5],
11487         month[3],
11488         day[3];
11489 
11490     strncpy(year, date, 4);
11491     year[4] = '\000';
11492     strncpy(month, date + 4, 2);
11493     month[2] = '\000';
11494     strncpy(day, date + 6, 2);
11495     day[2] = '\000';
11496 
11497     return ((atol(year) * 10000) + (atol(month) * 100) + atol(day));
11498 }
11499 
11500 /* UTL_ConvertLongtoDate
11501 **      Convert a long to a Dicom date.
11502 */
11503 void
11504 UTL_ConvertLongtoDate(long ld, char *date)
11505 {
11506 
11507     int
11508         year,
11509         month,
11510         day;
11511 
11512     year = ld / 10000;
11513     ld -= (year * 10000);
11514     month = ld / 100;
11515     ld -= (month * 100);
11516     day = ld;
11517 
11518     sprintf(date, "%04d%02d%02d", year, month, day);
11519 
11520     return;
11521 }
11522 
11523 /* UTL_ConvertTimetoFloat
11524 **      Convert a Dicom time to a floating point number for comparision ease.
11525 */
11526 double
11527 UTL_ConvertTimetoFloat(const char *time)
11528 {
11529 
11530     size_t
11531     i;
11532     char
11533         hour[3],
11534         minute[3],
11535         second[3],
11536         fracsec[7];
11537     const char *p;
11538     double
11539         divisor,
11540         hh,
11541         mm,
11542         ss,
11543         fs;
11544 
11545     hh = mm = ss = fs = 0.0;
11546     hour[0] = minute[0] = second[0] = fracsec[0] = '\000';
11547 
11548     p = time;
11549     /*
11550      * Just a brute force way to tear down a Dicom time...not very pretty,
11551      * but it works... We are not guaranteed to have every field present as
11552      * we are in the date...
11553      */
11554     hour[0] = *p++;
11555     hour[1] = *p++;
11556     hour[2] = '\000';
11557     if (isdigit(*p)) {
11558         minute[0] = *p++;
11559         minute[1] = *p++;
11560         minute[2] = '\000';
11561         if (isdigit(*p)) {
11562             second[0] = *p++;
11563             second[1] = *p++;
11564             second[2] = '\000';
11565             if (*p == '.') {
11566                 p++;
11567                 fracsec[0] = *p++;
11568                 if ((*p != '\000') && (isdigit(*p))) {
11569                     fracsec[1] = *p++;
11570                     if ((*p != '\000') && (isdigit(*p))) {
11571                         fracsec[2] = *p++;
11572                         if ((*p != '\000') && (isdigit(*p))) {
11573                             fracsec[3] = *p++;
11574                             if ((*p != '\000') && (isdigit(*p))) {
11575                                 fracsec[4] = *p++;
11576                                 if ((*p != '\000') && (isdigit(*p))) {
11577                                     fracsec[5] = *p++;
11578                                     fracsec[6] = '\000';
11579                                 } else
11580                                     fracsec[5] = '\000';
11581                             } else
11582                                 fracsec[4] = '\000';
11583                         } else
11584                             fracsec[3] = '\000';
11585                     } else
11586                         fracsec[2] = '\000';
11587                 } else
11588                     fracsec[1] = '\000';
11589             }
11590         }
11591     }
11592     hh = atof(hour);
11593     mm = atof(minute);
11594     ss = atof(second);
11595     divisor = 1;
11596     for (i = 0; i < strlen(fracsec); i++)
11597         divisor *= 10;
11598     fs = atof(fracsec) / divisor;
11599 
11600     return ((hh * 3600.0) + (mm * 60.0) + ss + fs);
11601 }
11602 
11603 /* UTL_ConvertFloattoTime
11604 **      Convert a floating point number to a Dicom time.
11605 */
11606 void
11607 UTL_ConvertFloattoTime(double dt, char *time)
11608 {
11609     int
11610         hour,
11611         minute,
11612         second,
11613         fracsec;
11614 
11615     hour = (int) (dt / 3600.0);
11616     dt -= (hour * 3600);
11617 
11618     minute = (int) (dt / 60.);
11619     dt -= (minute * 60);
11620 
11621     second = (int) dt;
11622     dt -= second;
11623 
11624     fracsec = (int) ((dt * 1000000) + 0.5);
11625 
11626     sprintf(time, "%02d%02d%02d.%06d", hour, minute, second, fracsec);
11627 
11628     return;
11629 }
11630 
11631 
11632 /* UTL_SqueezeBlanks
11633 **
11634 */
11635 void
11636 UTL_SqueezeBlanks(char *s)
11637 {
11638 
11639     char
11640        *t1,
11641        *t2;
11642 
11643     t1 = t2 = s;
11644     while (*t2 != '\000') {
11645         if (*t2 != ' ') {
11646             *t1 = *t2;
11647             t1++;
11648         }
11649         t2++;
11650     }
11651     *t1 = '\000';
11652 
11653     return;
11654 }
11655 /* UTL_DateMatch
11656 **      Match a date range as specified in the Dicom standard
11657 */
11658 CONDITION
11659 UTL_DateMatch(char *datestring, char *stm)
11660 {
11661 
11662     int
11663         match;
11664     char
11665        *ndate;
11666     long
11667         start_date,
11668         end_date,
11669         date_in_question;
11670 
11671     if ((ndate = (char *) malloc(strlen(datestring) + 1)) == (char *) NULL)
11672         return (UTL_NOMATCH);
11673 
11674     strcpy(ndate, datestring);
11675     UTL_SqueezeBlanks(ndate);
11676     UTL_SqueezeBlanks(stm);
11677 
11678     match = 0;
11679     if (strchr(ndate, (int) '-') == (char *) NULL) {
11680         if (strcmp(ndate, stm) == 0)
11681             match = 1;
11682     } else {
11683         date_in_question = UTL_ConvertDatetoLong(stm);
11684         if (ndate[0] == '-') {
11685             end_date = UTL_ConvertDatetoLong(ndate + 1);
11686             if (date_in_question <= end_date)
11687                 match = 1;
11688         } else if (ndate[strlen(ndate) - 1] == '-') {
11689             start_date = UTL_ConvertDatetoLong(ndate);
11690             if (date_in_question >= start_date)
11691                 match = 1;
11692         } else {
11693             start_date = UTL_ConvertDatetoLong(ndate);
11694             end_date = UTL_ConvertDatetoLong(strchr(ndate, (int) '-') + 1);
11695             if ((date_in_question >= start_date) &&
11696                 (date_in_question <= end_date))
11697                 match = 1;
11698         }
11699     }
11700     free(ndate);
11701     if (match)
11702         return (UTL_MATCH);
11703     else
11704         return (UTL_NOMATCH);
11705 }
11706 /* UTL_TimeMatch
11707 **      Match a time range as specified in the Dicom standard
11708 */
11709 CONDITION
11710 UTL_TimeMatch(char *timestring, char *stm)
11711 {
11712 
11713     int
11714         match;
11715     char
11716        *ntime;
11717     double
11718         start_time,
11719         end_time,
11720         time_in_question;
11721 
11722     if ((ntime = (char *) malloc(strlen(timestring) + 2)) == (char *) NULL)
11723         return (UTL_NOMATCH);
11724 
11725     strcpy(ntime, timestring);
11726     UTL_SqueezeBlanks(ntime);
11727     UTL_SqueezeBlanks(stm);
11728 
11729     match = 0;
11730     if (strchr(ntime, (int) '-') == (char *) NULL) {
11731         if (strcmp(ntime, stm) == 0)
11732             match = 1;
11733     } else {
11734         time_in_question = UTL_ConvertTimetoFloat(stm);
11735         if (ntime[0] == '-') {
11736             end_time = UTL_ConvertTimetoFloat(ntime + 1);
11737             if (time_in_question <= end_time)
11738                 match = 1;
11739         } else if (ntime[strlen(ntime) - 1] == '-') {
11740             start_time = UTL_ConvertTimetoFloat(ntime);
11741             if (time_in_question >= start_time)
11742                 match = 1;
11743         } else {
11744             start_time = UTL_ConvertTimetoFloat(ntime);
11745             end_time = UTL_ConvertTimetoFloat(strchr(ntime, (int) '-') + 1);
11746             if ((time_in_question >= start_time) &&
11747                 (time_in_question <= end_time))
11748                 match = 1;
11749         }
11750     }
11751     free(ntime);
11752     if (match)
11753         return (UTL_MATCH);
11754     else
11755         return (UTL_NOMATCH);
11756 }
11757 /*
11758 ** UTL_GetDicomDate
11759 **      Get the current date and store as a Dicom date.
11760 */
11761 void
11762 UTL_GetDicomDate(char *datestr)
11763 {
11764 
11765     struct tm
11766        *tf;
11767     time_t
11768         loctime;
11769 
11770     loctime = time((time_t *) NULL);
11771     tf = localtime(&loctime);
11772 
11773     sprintf(datestr, "%04d%02d%02d", (tf->tm_year) + 1900, (tf->tm_mon) + 1, tf->tm_mday);
11774     return;
11775 
11776 }
11777 /*
11778 ** UTL_GetDicomTime
11779 **      Get the current time and store as a Dicom time.
11780 */
11781 void
11782 UTL_GetDicomTime(char *timestr)
11783 {
11784 
11785     struct tm
11786        *tf;
11787     time_t
11788         loctime;
11789 
11790     loctime = time((time_t *) NULL);
11791     tf = localtime(&loctime);
11792 
11793     sprintf(timestr, "%02d%02d%02d.%06d", (tf->tm_hour), (tf->tm_min), (tf->tm_sec), 0);
11794     return;
11795 }
11796 
11797 #ifdef _MSC_VER
11798 typedef struct {
11799     char key[10];
11800     struct _timeb t;
11801 }   UTL_TIMESTRUCTURE;
11802 #else
11803 typedef struct {
11804     char key[10];
11805     struct timeval t;
11806 }   UTL_TIMESTRUCTURE;
11807 #endif
11808 
11809 void *
11810 UTL_GetTimeStamp()
11811 {
11812     UTL_TIMESTRUCTURE *t;
11813 
11814     t = AFMALL( UTL_TIMESTRUCTURE, sizeof(*t));
11815     if (t == NULL)
11816         return NULL;
11817 
11818     strcpy(t->key, "UTL STAMP");
11819 
11820     gettimeofday(&t->t, NULL);
11821 
11822     return t;
11823 }
11824 
11825 double
11826 UTL_DeltaTime(void *timeStamp)
11827 {
11828     struct timeval timeNow;
11829     UTL_TIMESTRUCTURE *t;
11830     double delta = 0.;
11831 
11832     gettimeofday(&timeNow, NULL);
11833 
11834     t = (UTL_TIMESTRUCTURE *) timeStamp;
11835     if (t == NULL)
11836         return -1.0;
11837 
11838     if (strcmp(t->key, "UTL STAMP") != 0)
11839         return -1.0;
11840 
11841     delta = timeNow.tv_sec - t->t.tv_sec;
11842     delta += (timeNow.tv_usec - t->t.tv_usec) / 1000000.;
11843 
11844     return delta;
11845 }
11846 
11847 void
11848 UTL_ReleaseTimeStamp(void *timeStamp)
11849 {
11850     UTL_TIMESTRUCTURE *t;
11851 
11852     t = (UTL_TIMESTRUCTURE *) timeStamp;
11853     if (t == NULL)
11854         return;
11855 
11856     if (strcmp(t->key, "UTL STAMP") != 0)
11857         return;
11858 
11859     free(timeStamp);
11860 }
11861 
11862 CONDITION
11863 UTL_VerifyCreatePath(const char *path)
11864 {
11865     int i;
11866 #ifdef _MSC_VER
11867     struct _stat buf;
11868 #else
11869     struct stat buf;
11870 #endif
11871     char
11872        *p,
11873         temp[1024];
11874     int flag = 0;
11875     static int statCount = 0;
11876 
11877 #ifdef _MSC_VER
11878     statCount++;
11879     i = _stat(path, &buf);
11880 #else
11881     i = stat(path, &buf);
11882 #endif
11883 
11884 
11885     if (i == 0) {
11886 #ifdef _MSC_VER
11887         flag = ((buf.st_mode & _S_IFDIR) != 0);
11888 #else
11889         flag = (S_ISDIR(buf.st_mode));
11890 #endif
11891         if (flag)
11892             return UTL_NORMAL;
11893         else
11894             return UTL_PATHNOTDIR;
11895     }
11896     p = temp;
11897 
11898     while (*path != '\0') {
11899         *p++ = *path++;
11900         while (*path != '/' && *path != '\\' && *path != '\0') {
11901 #ifdef _MSC_VER
11902             if (*path == ':') {
11903                 *p++ = *path++;
11904                 if (*path == '\0')      /* We should not get C:\0, but test
11905                                          * it */
11906                     break;
11907             }
11908 #endif
11909             *p++ = *path++;
11910         }
11911 
11912         *p = '\0';
11913 #ifdef _MSC_VER
11914         statCount++;
11915         i = _stat(temp, &buf);
11916 #else
11917         i = stat(temp, &buf);
11918 #endif
11919 
11920         if (i == 0) {
11921 #ifdef _MSC_VER
11922             flag = ((buf.st_mode & _S_IFDIR) != 0);
11923 #else
11924             flag = (S_ISDIR(buf.st_mode));
11925 #endif
11926             if (!flag)
11927                 return UTL_PATHNOTDIR;
11928         } else {
11929 #ifdef _MSC_VER
11930             int e1;
11931             e1 = errno;
11932             memset(&buf, 0, sizeof(buf));
11933             /*fprintf(stderr, "Stat Count = %d\n", statCount);*/
11934             statCount++;
11935             i = _stat(temp, &buf);
11936             e1 = errno;
11937             i = _mkdir(temp);
11938 #else
11939             i = mkdir(temp, 0777);
11940 #endif
11941             if (i != 0) {
11942                 int e1;
11943                 e1 = errno;
11944                 fprintf(stderr, "Stat Count = %d\n", statCount);
11945                 perror(temp);
11946                 return UTL_FILECREATEFAILED;
11947             }
11948         }
11949     }
11950     return UTL_NORMAL;
11951 }
11952 
11953 CTNBOOLEAN UTL_IsDirectory(const char* path)
11954 {
11955     int i;
11956 #ifdef _MSC_VER
11957     struct _stat buf;
11958 #else
11959     struct stat buf;
11960 #endif
11961 
11962     int flag = 0;
11963 
11964 #ifdef _MSC_VER
11965     i = _stat(path, &buf);
11966 #else
11967     i = stat(path, &buf);
11968 #endif
11969 
11970 
11971     if (i == 0) {
11972 #ifdef _MSC_VER
11973         flag = ((buf.st_mode & _S_IFDIR) != 0);
11974 #else
11975         flag = (S_ISDIR(buf.st_mode));
11976 #endif
11977         if (flag)
11978             return TRUE;
11979     }
11980     return FALSE;
11981 }
11982 
11983 
11984 #if 0
11985 CONDITION UTL_ScanDirectory(const char* path,
11986                             LST_HEAD** lst)
11987 {
11988   UTL_FILEITEM* item = 0;
11989 
11990 #ifdef _WIN32
11991   long hFile = 0;
11992   struct _finddata_t fileInfo;
11993   char directoryText[1024];
11994   *lst = LST_Create();
11995   strcpy(directoryText, path);
11996   strcat(directoryText, "/*");
11997   if( (hFile = _findfirst(directoryText, &fileInfo)) == -1L)
11998     return 0;
11999 
12000   item = malloc(sizeof(*item));
12001   strcpy(item->path, fileInfo.name);
12002   LST_Enqueue(lst, item);
12003 
12004   while(_findnext(hFile, &fileInfo) == 0) {
12005     item = malloc(sizeof(*item));
12006     strcpy(item->path, fileInfo.name);
12007     LST_Enqueue(lst, item);
12008   }
12009   _findclose(hFile);
12010 
12011 #else
12012   DIR* dirp;
12013   struct dirent* dp;
12014 
12015   *lst = LST_Create();
12016   dirp = opendir(path);
12017   if (dirp == 0)
12018     return 0;
12019 
12020   while ((dp = readdir(dirp)) != NULL) {
12021     item = malloc(sizeof(*item));
12022     strcpy(item->path, dp->d_name);
12023     LST_Enqueue(lst, (void *)item);
12024   }
12025   closedir(dirp);
12026 #endif
12027 
12028   return UTL_NORMAL;
12029 }
12030 #endif
12031 
12032 static char* UTL_configFile = 0;
12033 static LST_HEAD* UTL_configList = 0;
12034 typedef struct {
12035   void* reserved[2];
12036   char *pName;
12037   char *pValue;
12038 } CONFIG_ITEM;
12039 
12040 CONDITION UTL_ReadConfigFile( )
12041 {
12042   FILE* f;
12043   char buf[1024];
12044 
12045   if (UTL_configList != 0)
12046     return UTL_NORMAL;
12047 
12048   UTL_configList = LST_Create();
12049   if (UTL_configList == NULL)
12050     return 0;
12051 
12052   if (UTL_configFile == 0)
12053     return UTL_NORMAL;
12054 
12055   if (UTL_configFile[0] == '\0')
12056     return UTL_NORMAL;
12057 
12058   f = fopen(UTL_configFile, "r");
12059   if (f == NULL)
12060     return 0;
12061 
12062   while (fgets(buf, sizeof(buf), f) != NULL) {
12063     char* token1;
12064     char* token2;
12065     CONFIG_ITEM* item;
12066 
12067     if (buf[0] == '#') continue;
12068     if (buf[0] == '\n') continue;
12069     token1 = strtok(buf, " \t\n");
12070     token2 = strtok(0, " \t\n");
12071     if (token2 == NULL) continue;
12072 
12073     item = (CONFIG_ITEM*)malloc(sizeof(*item) + strlen(token1) +
12074                                 strlen(token2) + 2);
12075     item->pName = ((char*)item) + sizeof(*item);
12076     strcpy(item->pName, token1);
12077     item->pValue = item->pName + strlen(token1) + 1;
12078     strcpy(item->pValue, token2);
12079 
12080     LST_Enqueue(&UTL_configList, (void *)item);
12081   }
12082 
12083   fclose(f);
12084 
12085   return UTL_NORMAL;
12086 }
12087 
12088 CONDITION UTL_SetConfigFile(const char* configFile)
12089 {
12090   if (UTL_configFile != 0) {
12091     CTN_FREE(UTL_configFile);
12092   }
12093 
12094   if (configFile == 0 || configFile[0] == '\0') {
12095     char* p = getenv("CTN_TARGET");
12096     if (p == NULL) {
12097       return UTL_NO_CTN_TARGET;
12098     }
12099     UTL_configFile = (char*) malloc(strlen(p) + strlen("/runtime/ctn_cfg.txt") + 1);
12100     strcpy(UTL_configFile, p);
12101     strcat(UTL_configFile, "/runtime/ctn_cfg.txt");
12102   } else {
12103     UTL_configFile = (char*) malloc(strlen(configFile)+1);
12104     strcpy(UTL_configFile, configFile);
12105   }
12106 
12107   return UTL_NORMAL;
12108 }
12109 
12110 CONDITION UTL_TestConfigFile(const char* configFile)
12111 {
12112   return UTL_NORMAL;
12113 }
12114 char* UTL_GetConfigParameter(const char* paramName)
12115 {
12116   CONDITION cond;
12117   char nameCopy[256];
12118   CONFIG_ITEM* item;
12119   int idx;
12120 
12121   cond = UTL_ReadConfigFile( );
12122   if (cond != UTL_NORMAL)
12123     return NULL;
12124 
12125   item = (void *)LST_Head(&UTL_configList);
12126   if (item == NULL)
12127     return NULL;
12128 
12129   (void) LST_Position(&UTL_configList, (void *)item);
12130   while(item != NULL) {
12131     if (strcmp(item->pName, paramName) == 0)
12132       return item->pValue;
12133 
12134     item = (void *)LST_Next(&UTL_configList);
12135   }
12136 
12137   strcpy(nameCopy, paramName);
12138   idx = strlen(nameCopy) - 1;
12139   while (idx > 0) {
12140     if (nameCopy[idx] == '/') {
12141       nameCopy[idx] = '\0';
12142       idx = -1;
12143       break;
12144     } else {
12145       idx--;
12146     }
12147   }
12148 
12149   if (idx < 0) {
12150     return UTL_GetConfigParameter(nameCopy);
12151   } else {
12152     return NULL;
12153   }
12154 }
12155 
12156 char**
12157 UTL_ExpandToPointerArray(const char* inputText,
12158                          const char* delimiters,
12159                          int* numberOfEntries)
12160 {
12161   int idx;
12162   int memorySize = 0;
12163   int arrayIndex = 0;
12164   char** array;
12165   char* outputPtr;
12166   char* token;
12167 
12168   *numberOfEntries = 1;
12169   for (idx = 0; inputText[idx] != '\0'; idx++) {
12170     int j;
12171     for (j = 0; delimiters[j] != '\0'; j++) {
12172       if (inputText[idx] == delimiters[j]) {
12173         (*numberOfEntries)++;
12174         break;
12175       }
12176     }
12177   }
12178 
12179   memorySize = (sizeof(char*)) * (*numberOfEntries);
12180   memorySize += strlen(inputText) + 1;
12181 
12182   array = (char**)CTN_MALLOC(memorySize);
12183   outputPtr = ((char*) array) + ((sizeof(char*)) * (*numberOfEntries));
12184   strcpy(outputPtr, inputText);
12185 
12186   token = strtok(outputPtr, delimiters);
12187   while(token != NULL) {
12188     array[arrayIndex++] = token;
12189     token = strtok(NULL, delimiters);
12190   }
12191 
12192   return array;
12193 }
12194 
12195 CTNBOOLEAN UTL_IsFile(const char* path)
12196 {
12197   int i;
12198   CTNBOOLEAN rtnValue = FALSE;
12199 
12200 #ifdef _WIN32
12201   struct _stat buf;
12202 
12203   i = _stat(path, &buf);
12204   if (i == 0) {
12205     rtnValue = ((buf.st_mode & _S_IFREG) != 0);
12206   }
12207 #else
12208   struct stat buf;
12209   i = stat(path, &buf);
12210   if (i == 0) {
12211     rtnValue = (S_ISREG(buf.st_mode));
12212   }
12213 #endif
12214 
12215   return rtnValue;
12216 }
12217 
12218 CONDITION UTL_DeleteFile(const char* path)
12219 {
12220   int i = 0;
12221 
12222   i = unlink(path);
12223 
12224   if (i == 0)
12225     return UTL_NORMAL;
12226 
12227   return COND_PushCondition(UTL_DELETEFILEFAILED, "");
12228 }
12229 
12230 
12231 CONDITION
12232 UTL_FileSize(const char* path, U32* size)
12233 {
12234   int status;
12235   struct stat im_stat;
12236 
12237   status = stat(path, &im_stat);
12238   if (status < 0) {
12239     *size = 0;
12240     return 0;
12241   } else {
12242     *size = im_stat.st_size;
12243     return UTL_NORMAL;
12244   }
12245 }
12246 
12247 
12248 /* DCM_ExportStream
12249 **
12250 ** Purpose:
12251 **      Export a DICOM object into the stream format suitable
12252 **      for network transmission or disk storage.
12253 **
12254 ** Parameter Dictionary:
12255 **      object          Pointer to caller's DICOM object
12256 **      opt             Bitmask giving options for exporting data.  Legal
12257 **                      options give the byte order of exported data:
12258 **                              DCM_ORDERNATIVE
12259 **                              DCM_ORDERLITTLEENDIAN
12260 **                              DCM_ORDERBIGENDIAN
12261 **      buffer          Pointer to caller's buffer to hold next slug
12262 **                      of DCM stream data.
12263 **      bufferlength    Length of caller's buffer to hold stream data.
12264 **      returnlength    Pointer to caller's variable into which we write
12265 **                      the amount of data exported.
12266 **      ctx             Pointer to context variable we maintain to keep
12267 **                      track of our location in export process.
12268 **
12269 ** Return Values:
12270 **
12271 **      DCM_FILEACCESSERROR
12272 **      DCM_ILLEGALOBJECT
12273 **      DCM_LISTFAILURE
12274 **      DCM_NORMAL
12275 **      DCM_NULLOBJECT
12276 **
12277 ** Algorithm:
12278 **      Description of the algorithm (optional) and any other notes.
12279 */
12280 
12281 CONDITION
12282 DCM_ExportStream(DCM_OBJECT ** callerObject, unsigned long opt,
12283                  void *buffer, unsigned long bufferlength,
12284                  DCM_EXPORT_STREAM_CALLBACK* callback,
12285                  void *ctx)
12286 {
12287 
12288 
12289     PRIVATE_OBJECT
12290         ** object;
12291     CONDITION
12292         cond;
12293 
12294     object = (PRIVATE_OBJECT **) callerObject;
12295     cond = checkObject(object, "DCM_ExportStream");
12296     if (cond != DCM_NORMAL)
12297         return cond;
12298 
12299     return exportStream(callerObject, opt, buffer, bufferlength, callback,
12300                         ctx, 0);
12301 }
 

Powered by Plone

This site conforms to the following standards: