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  

l_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:43 $
00055 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
00056 ** Revision:            $Revision: 1.2 $
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 "dbtrace.h"    /* rcr - instead of debugtrace.h */
00074 
00075 
00076 /****************************************************************/
00077 /***** Function and variables to set byte order of this CPU *****/
00078 /****************************************************************/
00079 #define BYTEORDER_SAME        1
00080 #define BYTEORDER_REVERSE     2
00081 #define NATIVE_ORDER          BYTEORDER_SAME
00082 
00083 static int LITTLE_ORDER ;
00084 static int BIG_ORDER ;
00085 static int LITTLE_ENDIAN_ARCHITECTURE = -1 ;
00086 
00087 static void RWC_set_endianosity(void)
00088 {
00089    union { unsigned char bb[2] ;
00090            short         ss    ; } fred ;
00091 
00092    if( LITTLE_ENDIAN_ARCHITECTURE < 0 ){
00093      fred.bb[0] = 1 ; fred.bb[1] = 0 ;
00094 
00095      LITTLE_ENDIAN_ARCHITECTURE = (fred.ss == 1) ;
00096 
00097      if( LITTLE_ENDIAN_ARCHITECTURE ){
00098        LITTLE_ORDER = BYTEORDER_SAME ;
00099        BIG_ORDER    = BYTEORDER_REVERSE ;
00100      } else {
00101        BIG_ORDER    = BYTEORDER_SAME ;
00102        LITTLE_ORDER = BYTEORDER_REVERSE ;
00103      }
00104    }
00105 }
00106 
00107 /****************************************************************/
00108 /***** Function and variables to replace printf() ***************/
00109 
00110 static char *pbuf = NULL ;
00111 static int  npbuf = 0 ;
00112 
00113 #define NPBUF 1024
00114 
00115 static void RWC_clear_pbuf(void)
00116 {
00117    if( pbuf != NULL ){ free(pbuf); pbuf = NULL; npbuf = 0; }
00118 }
00119 
00120 static int RWC_printf( char *fmt , ... )
00121 {
00122    static char *sbuf = NULL ;
00123    int nsbuf , nn , lpbuf ;
00124    va_list vararg_ptr ;
00125 
00126    va_start( vararg_ptr , fmt ) ;
00127 
00128    if( sbuf == NULL ) sbuf = AFMALL( char, NPBUF) ;  /* 1st time in */
00129 
00130    sbuf[0] = '\0' ;
00131    nn = vsprintf( sbuf , fmt , vararg_ptr ) ;
00132    va_end( vararg_ptr ) ;
00133    nsbuf = strlen(sbuf) ;
00134    if( nsbuf == 0 ) return(0);
00135 
00136    if( npbuf == 0 ){
00137      pbuf = AFMALL(char,NPBUF) ; npbuf = NPBUF ; pbuf[0] = '\0' ;
00138    }
00139 
00140    lpbuf = strlen(pbuf) ;
00141    if( lpbuf+nsbuf+8 > npbuf ){
00142      npbuf += NPBUF; pbuf = AFREALL( pbuf, char, npbuf);
00143    }
00144 
00145    strcat(pbuf,sbuf) ;
00146    return(nn);
00147 }
00148 
00149 /****************************************************************/
00150 
00151 static off_t        pxl_off = 0 ;  /* store pixel array offset */
00152 static unsigned int pxl_len = 0 ;  /* and length in file */
00153 
00154 void mri_dicom_pxlarr( off_t *poff , unsigned int *plen )
00155 {
00156    *poff = pxl_off ; *plen = pxl_len ;
00157 }
00158 
00159 /****************************************************************/
00160 
00161 static int rwc_opt = 0 ;
00162 
00163 #define RWC_NONAME_MASK  1
00164 #define RWC_NOHEX_MASK   2
00165 
00166 void mri_dicom_noname( int ii )
00167 {
00168    if( ii )
00169      rwc_opt |= RWC_NONAME_MASK ;
00170    else if( rwc_opt & RWC_NONAME_MASK )
00171      rwc_opt ^= RWC_NONAME_MASK ;
00172 }
00173 
00174 void mri_dicom_nohex( int ii )
00175 {
00176    if( ii )
00177      rwc_opt |= RWC_NOHEX_MASK ;
00178    else if( rwc_opt & RWC_NOHEX_MASK )
00179      rwc_opt ^= RWC_NOHEX_MASK ;
00180 }
00181 
00182 /****************************************************************/
00183 
00184 static int rwc_vm=0 ;                     /* 28 Oct 2002 */
00185 
00186 void mri_dicom_setvm( int vv )
00187 {
00188   rwc_vm = vv ;
00189 }
00190 
00191 /****************************************************************/
00192 
00193 static int rwc_err=1 ;                     /* 28 Oct 2002 */
00194 
00195 void mri_dicom_seterr( int vv )
00196 {
00197   rwc_err = vv ;   /* 07 May 2003: an error will subtract 1 from rwc_err */
00198 }
00199 
00200 /****************************************************************/
00201 
00202 static int rwc_fd ;  /* 10 Sep 2002 */
00203 
00204 char * mri_dicom_header( char *fname )
00205 {
00206     DCM_OBJECT * object;
00207     CONDITION cond;
00208     CTNBOOLEAN verbose = FALSE ,
00209                exitFlag = FALSE,
00210                formatFlag = FALSE;
00211     unsigned long
00212         options = DCM_ORDERLITTLEENDIAN;
00213     long vmLimit = rwc_vm ;             /* 28 Oct 2002 */
00214     LST_HEAD* fileNames = 0;
00215     UTL_FILEITEM* p = NULL;
00216 
00217     char *ppp=NULL ;
00218 
00219 ENTRY("mri_dicom_header") ;
00220 
00221     if( fname == NULL ) RETURN(NULL) ;
00222 
00223     RWC_set_endianosity() ;
00224 
00225     { char *eee = getenv("AFNI_TRACE") ;
00226       if( eee!=NULL && (*eee=='y' || *eee=='Y') ) verbose = TRUE ;
00227     }
00228 
00229     DCM_Debug(verbose);
00230 
00231     RWC_clear_pbuf() ; pxl_len = 0 ; pxl_off = 0 ;
00232 
00233 STATUS(fname) ;
00234     rwc_fd = -1 ;
00235     cond = DCM_OpenFile(fname, options, &object);
00236     if (cond != DCM_NORMAL && ((options & DCM_PART10FILE) == 0)) {
00237 STATUS("DCM_OpenFile open failed; try again as Part 10") ;
00238       (void) DCM_CloseObject(&object);
00239       (void) COND_PopCondition(TRUE);
00240       if( rwc_fd >= 0 ){ close(rwc_fd); rwc_fd = -1; }
00241       cond = DCM_OpenFile(fname, options | DCM_PART10FILE, &object);
00242     }
00243     if (cond == DCM_NORMAL) {
00244 STATUS("DCM_OpenFile is good") ;
00245        RWC_printf("DICOM File: %s\n", fname);
00246        if (formatFlag)
00247          cond = DCM_FormatElements(&object, vmLimit, "");
00248        else
00249          cond = DCM_DumpElements(&object, vmLimit);
00250     } else {
00251 STATUS("DCM_OpenFile failed") ;
00252     }
00253     (void) DCM_CloseObject(&object);
00254     (void) COND_PopCondition(TRUE);
00255 
00256     if( pbuf != NULL ){
00257       ppp = strdup(pbuf) ; RWC_clear_pbuf() ;
00258     }
00259 
00260     if( rwc_fd >= 0 ){ close(rwc_fd); rwc_fd = -1; }
00261 
00262     RETURN(ppp);
00263 }
00264 
00265 /*
00266           Copyright (C) 1993, 1994, RSNA and Washington University
00267 
00268           The software and supporting documentation for the Radiological
00269           Society of North America (RSNA) 1993, 1994 Digital Imaging and
00270           Communications in Medicine (DICOM) Demonstration were developed
00271           at the
00272                   Electronic Radiology Laboratory
00273                   Mallinckrodt Institute of Radiology
00274                   Washington University School of Medicine
00275                   510 S. Kingshighway Blvd.
00276                   St. Louis, MO 63110
00277           as part of the 1993, 1994 DICOM Central Test Node project for, and
00278           under contract with, the Radiological Society of North America.
00279 
00280           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00281           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00282           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00283           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00284           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00285           THE SOFTWARE IS WITH THE USER.
00286 
00287           Copyright of the software and supporting documentation is
00288           jointly owned by RSNA and Washington University, and free access
00289           is hereby granted as a license to use this software, copy this
00290           software and prepare derivative works based upon this software.
00291           However, any distribution of this software source code or
00292           supporting documentation or derivative works (source code and
00293           supporting documentation) must include the three paragraphs of
00294           the copyright notice.
00295 */
00296 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
00297 /*
00298 ** @$=@$=@$=
00299 */
00300 /*
00301 **                              DICOM 93
00302 **                   Electronic Radiology Laboratory
00303 **                 Mallinckrodt Institute of Radiology
00304 **              Washington University School of Medicine
00305 **
00306 ** Module Name(s):      COND_PushCondition
00307 **                      COND_ExtractConditions
00308 **                      COND_TopCondition
00309 **                      COND_PopCondition
00310 **                      COND_DumpConditions
00311 **                      COND_CopyText
00312 **                      COND_WriteConditions
00313 ** Author, Date:        Stephen M. Moore, 15-Apr-93
00314 ** Intent:              This file contains functions implementing a simple
00315 **                      error facility.  It was first written by Stephen Moore
00316 **                      (smm@wuerl.wustl.edu) to support PACS development at
00317 **                      the Mallinckrodt Institute of Radiology.  The function
00318 **                      names have been modified to have a slightly more
00319 **                      generic name, but the basic model and concepts are
00320 **                      the same.
00321 **
00322 **                      The condition package maintains a stack of
00323 **                      <condition, message> pairs that callers can push or
00324 **                      pop.  When a routine returns an abnormal value, it
00325 **                      should push a condition onto the stack so that the
00326 **                      caller can examine the value at a later time.  Nested
00327 **                      routines may push a number of conditions onto the
00328 **                      stack providing more detailed information about why
00329 **                      a routine did not return normally.
00330 **
00331 **                      The stack is maintained as a simple stack array.  If
00332 **                      it overflows, we dump the stack to stdout and reset it.
00333 **
00334 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
00335 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
00336 ** Revision:            $Revision: 1.2 $
00337 ** Status:              $State: Exp $
00338 */
00339 
00340 
00341 /*
00342 **
00343 **  INCLUDE FILES
00344 **
00345 */
00346 
00347 
00348 typedef struct {
00349     CONDITION statusCode;
00350     char statusText[256];
00351 }   EDB;
00352 
00353 #define MAXEDB  100
00354 
00355 static int stackPtr = -1;
00356 static EDB EDBStack[MAXEDB];
00357 static void (*ErrorCallback) () = NULL;
00358 static void dumpstack(FILE * fp);
00359 
00360 
00361 /*
00362 **++
00363 **  FUNCTIONAL DESCRIPTION:
00364 **
00365 **      COND_PushCondition
00366 **      This routine is used to log a condition on the stack.  The user
00367 **      passes an error code (currently uninterpreted), a format string
00368 **      and optional format arguments.  We use the vsprintf routine to
00369 **      interpret the user's format string and arguments, and we place the
00370 **      error condition and resultant string on the stack.
00371 **
00372 **  FORMAL PARAMETERS:
00373 **
00374 **      code:
00375 **          The condition code of the error/warning.
00376 **
00377 **      controlString:
00378 **          format string for vsprintf statement
00379 **
00380 **      [varargs]:
00381 **          variable arguments to be used with controlString
00382 **
00383 **  RETURN VALUE:
00384 **
00385 **      code (as passed in by the user)
00386 **
00387 **  SIDE EFFECTS:
00388 **
00389 **      Places a new entry on the stack.  If the stack
00390 **      fills up, drop the last condition.
00391 **      Calls a user-established callback just before return.
00392 **
00393 */
00394 CONDITION
00395 COND_PushCondition(CONDITION cond, char *controlString,...)
00396 {
00397     va_list
00398         args;
00399     char
00400         buffer[1024];
00401 
00402 /*lint -e40 -e50 */
00403     va_start(args, controlString);
00404     if (controlString == NULL)
00405         controlString = "NULL Control string passedto PushCondition";
00406     (void) vsprintf(buffer, controlString, args);
00407     va_end(args);
00408 /*lint +e40 +e50 */
00409 
00410     stackPtr++;
00411     EDBStack[stackPtr].statusCode = cond;
00412     buffer[256] = '\0';
00413 
00414     (void) strcpy(EDBStack[stackPtr].statusText, buffer);
00415     if (ErrorCallback != NULL)
00416 #if 0
00417         ErrorCallback(EDBStack[stackPtr].statusCode,
00418                       EDBStack[stackPtr].statusText);
00419 #else
00420         AFNI_CALL_VOID_2ARG( ErrorCallback ,
00421                              CONDITION,EDBStack[stackPtr].statusCode ,
00422                              char *   ,EDBStack[stackPtr].statusText  ) ;
00423 #endif
00424 
00425     if (stackPtr >= MAXEDB - 2) {
00426         dumpstack(stderr);
00427         fprintf(stderr, "CONDITION Stack overflow\n");
00428         stackPtr = 0;
00429     }
00430 
00431     return cond;
00432 
00433 }
00434 
00435 
00436 /*
00437 **++
00438 **  FUNCTIONAL DESCRIPTION:
00439 **
00440 **  COND_ExtractConditions
00441 **      This routine walks through the stack and passes the condition
00442 **      codes and text back to the user.  The caller supplies a
00443 **      callback routine.  We start at the top of the stack and
00444 **      call the user's callback for each message on the stack.  The
00445 **      user can terminate the process at any time by returning
00446 **      a zero from his callback.
00447 **
00448 **  FORMAL PARAMETERS:
00449 **
00450 **      callback:
00451 **          User routine to call for each message on the stack.
00452 **
00453 **  RETURN VALUE:
00454 **
00455 **      1
00456 **
00457 **  SIDE EFFECTS:
00458 **
00459 **
00460 **  DESIGN:
00461 **
00462 **      None
00463 **--
00464 */
00465 
00466 CONDITION
00467 COND_ExtractConditions(CTNBOOLEAN(*callback) ())
00468 {
00469     int
00470         index,
00471         returnflag;
00472 
00473     for (index = stackPtr, returnflag = 1; index >= 0 && returnflag != 0;
00474          index--) {
00475 #if 0
00476         returnflag = callback(EDBStack[index].statusCode,
00477                               EDBStack[index].statusText);
00478 #else
00479         AFNI_CALL_VALU_2ARG( callback , int,returnflag            ,
00480                              CONDITION,EDBStack[index].statusCode ,
00481                              char *   ,EDBStack[index].statusText  ) ;
00482 #endif
00483     }
00484 
00485     return COND_NORMAL;
00486 }
00487 
00488 /*
00489 **++
00490 **  FUNCTIONAL DESCRIPTION:
00491 **
00492 **      COND_TopCondition
00493 **      This routine is used to look at the top condition message on
00494 **      the stack.  The user passes pointers to areas to place
00495 **      the error message.  The function also returns the code
00496 **      for the top error message.  If the stack is empty, the
00497 **      success code (0) is returned.
00498 **
00499 **  FORMAL PARAMETERS:
00500 **
00501 **      code:
00502 **          Pointer to the user's area to hold the error code
00503 **
00504 **      text
00505 **          Pointer to the user's area to hold the error text
00506 **
00507 **      maxlength
00508 **          Maximum buffer length in the user's text area
00509 **
00510 **  RETURN VALUE:
00511 **
00512 **      top error code on the stack
00513 **
00514 **  SIDE EFFECTS:
00515 **
00516 **
00517 */
00518 
00519 CONDITION
00520 COND_TopCondition(CONDITION * code, char *text, unsigned long maxlength)
00521 {
00522     CONDITION rtnValue;
00523 
00524     if (stackPtr >= 0) {
00525         *code = EDBStack[stackPtr].statusCode;
00526         (void) strncpy(text, EDBStack[stackPtr].statusText, maxlength - 1);
00527         text[maxlength - 1] = '\0';
00528         rtnValue = EDBStack[stackPtr].statusCode;
00529     } else {
00530         *code = COND_NORMAL;
00531         *text = '\0';
00532         rtnValue = COND_NORMAL;
00533     }
00534 
00535     return rtnValue;
00536 }
00537 
00538 /*
00539 **++
00540 **  FUNCTIONAL DESCRIPTION:
00541 **
00542 **      COND_PopCondition
00543 **      This routine pops one or all conditions off the stack.
00544 **      The user passes a flag which indicates the operation.
00545 **      After the clear, the current top error code is returned.
00546 **      If the stack is empty at this point, the success code (0)
00547 **      is returned.
00548 **
00549 **  FORMAL PARAMETERS:
00550 **
00551 **      clearstack:
00552 **          Flag which indicates if the entire stack is to be cleared.
00553 **              0           Just pop the top error
00554 **              non zero    Clear the entire stack
00555 **
00556 **  RETURN VALUE:
00557 **
00558 **      The new top error code.  0 if the stack is empty
00559 **
00560 **  SIDE EFFECTS:
00561 **
00562 **
00563 */
00564 
00565 CONDITION
00566 COND_PopCondition(CTNBOOLEAN clearstack)
00567 {
00568     CONDITION
00569         value;
00570 
00571     if (stackPtr >= 0)
00572         value = EDBStack[stackPtr].statusCode;
00573     else
00574         value = COND_NORMAL;
00575 
00576     if (clearstack) {
00577         stackPtr = -1;
00578     } else if (stackPtr <= 0) {
00579         stackPtr = -1;
00580     } else {
00581         stackPtr--;
00582     }
00583 
00584     return value;
00585 }
00586 
00587 /*
00588 **++
00589 **  FUNCTIONAL DESCRIPTION:
00590 **
00591 **      COND_EstablishCallback
00592 **      Establishes a callback routine to be called whenever a
00593 **      new condition is placed on the stack.  There is no stack
00594 **      mechanism for these callbacks, so each new callback routine
00595 **      completely supersedes the previous one.
00596 **
00597 **  FORMAL PARAMETERS:
00598 **
00599 **      callback:
00600 **          The new callback routine.  If NULL, this will
00601 **          disable callbacks.
00602 **
00603 **  RETURN VALUE:
00604 **
00605 **      0
00606 **
00607 **  SIDE EFFECTS:
00608 **
00609 **
00610 */
00611 
00612 CONDITION
00613 COND_EstablishCallback(void (*callback) ())
00614 {
00615 
00616     ErrorCallback = callback;
00617 
00618     return COND_NORMAL;
00619 }
00620 
00621 
00622 /* function name
00623 **
00624 ** Purpose:
00625 **      Describe the purpose of the function
00626 **
00627 ** Parameter Dictionary:
00628 **      Define the parameters to the function
00629 **
00630 ** Return Values:
00631 **
00632 ** Algorithm:
00633 **      Description of the algorithm (optional) and any other notes.
00634 */
00635 
00636 void
00637 COND_DumpConditions(void)
00638 {
00639 
00640     dumpstack(stderr);
00641     stackPtr = -1;
00642 }
00643 
00644 static void
00645 dumpstack(FILE * lfp)
00646 {
00647     int
00648         index;
00649 
00650     for (index = 0; index <= stackPtr; index++)
00651         fprintf(lfp, "%8x %s\n", (unsigned int)EDBStack[index].statusCode,
00652                 EDBStack[index].statusText);
00653 }
00654 
00655 /*
00656 **++
00657 **  FUNCTIONAL DESCRIPTION:
00658 **
00659 **      COND_CopyText
00660 **      This function copies as much text as possible from the
00661 **      condition stack and places it in the caller's buffer.
00662 **
00663 **  FORMAL PARAMETERS:
00664 **
00665 **      txt
00666 **          Pointer to the user's area to hold the error text
00667 **
00668 **      length
00669 **          Maximum buffer length in the user's text area
00670 **
00671 **  RETURN VALUE:
00672 **
00673 **      none
00674 **
00675 **  SIDE EFFECTS:
00676 **
00677 */
00678 
00679 void
00680 COND_CopyText(char *txt, size_t length)
00681 {
00682     size_t i;
00683     int j;
00684 
00685     txt[0] = '\0';
00686 
00687     j = stackPtr;
00688     while (length > 2 && j >= 0) {
00689         i = strlen(EDBStack[j].statusText);
00690         if (i > length)
00691             i = length - 2;
00692         strncpy(txt, EDBStack[j].statusText, i);
00693         txt[i++] = '\n';
00694         txt[i] = '\0';
00695         length -= i;
00696         txt += i;
00697         j--;
00698     }
00699 }
00700 
00701 /* COND_WriteConditions
00702 **
00703 ** Purpose:
00704 **      Write the condition stack to a file, ie stdout or stderr.
00705 **
00706 ** Parameter Dictionary:
00707 **      File * lfp, the file to which the stack is written.
00708 **
00709 ** Return Values:
00710 **
00711 ** Algorithm:
00712 **      A reiteration of the COND_DumpConditions except this takes an argument.
00713 */
00714 
00715 void
00716 COND_WriteConditions(FILE * lfp)
00717 {
00718     dumpstack(lfp);
00719     stackPtr = -1;
00720 }
00721 /*
00722           Copyright (C) 1995 - 1996, RSNA and Washington University
00723 
00724           The software and supporting documentation for the Radiological
00725           Society of North America (RSNA) 1993 - 1996 Digital Imaging and
00726           Communications in Medicine (DICOM) Demonstration were developed
00727           at the
00728                   Electronic Radiology Laboratory
00729                   Mallinckrodt Institute of Radiology
00730                   Washington University School of Medicine
00731                   510 S. Kingshighway Blvd.
00732                   St. Louis, MO 63110
00733           as part of the 1993 - 1996 DICOM Central Test Node project for, and
00734           under contract with, the Radiological Society of North America.
00735 
00736           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00737           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00738           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00739           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00740           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00741           THE SOFTWARE IS WITH THE USER.
00742 
00743           Copyright of the software and supporting documentation is
00744           jointly owned by RSNA and Washington University, and free access
00745           is hereby granted as a license to use this software, copy this
00746           software and prepare derivative works based upon this software.
00747           However, any distribution of this software source code or
00748           supporting documentation or derivative works (source code and
00749           supporting documentation) must include the three paragraphs of
00750           the copyright notice.
00751 */
00752 /*
00753 +-+-+-+-+-+-+-+-+-
00754 */
00755 /*
00756 **                   Electronic Radiology Laboratory
00757 **                 Mallinckrodt Institute of Radiology
00758 **              Washington University School of Medicine
00759 **
00760 ** Module Name(s):
00761 ** Author, Date:        Steve Moore, 30-Jun-96
00762 ** Intent:              Provide common abstractions needed for operations
00763 **                      in a multi-threaded environment.
00764 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
00765 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
00766 ** Revision:            $Revision: 1.2 $
00767 ** Status:              $State: Exp $
00768 */
00769 
00770 /*
00771           Copyright (C) 1993, 1994, RSNA and Washington University
00772 
00773           The software and supporting documentation for the Radiological
00774           Society of North America (RSNA) 1993, 1994 Digital Imaging and
00775           Communications in Medicine (DICOM) Demonstration were developed
00776           at the
00777                   Electronic Radiology Laboratory
00778                   Mallinckrodt Institute of Radiology
00779                   Washington University School of Medicine
00780                   510 S. Kingshighway Blvd.
00781                   St. Louis, MO 63110
00782           as part of the 1993, 1994 DICOM Central Test Node project for, and
00783           under contract with, the Radiological Society of North America.
00784 
00785           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
00786           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
00787           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
00788           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
00789           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
00790           THE SOFTWARE IS WITH THE USER.
00791 
00792           Copyright of the software and supporting documentation is
00793           jointly owned by RSNA and Washington University, and free access
00794           is hereby granted as a license to use this software, copy this
00795           software and prepare derivative works based upon this software.
00796           However, any distribution of this software source code or
00797           supporting documentation or derivative works (source code and
00798           supporting documentation) must include the three paragraphs of
00799           the copyright notice.
00800 */
00801 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
00802 
00803 /*
00804 **                              DICOM 93
00805 **                   Electronic Radiology Laboratory
00806 **                 Mallinckrodt Institute of Radiology
00807 **              Washington University School of Medicine
00808 **
00809 ** Module Name(s):      DCM_OpenFile
00810 **                      DCM_CreateObject
00811 **                      DCM_CloseObject
00812 **                      DCM_AddElement
00813 **                      DCM_AddSequenceElement
00814 **                      DCM_RemoveElement
00815 **                      DCM_GetElementValue
00816 **                      DCM_GetElementSize
00817 **                      DCM_ScanParseObject
00818 **                      DCM_ImportStream
00819 **                      DCM_ExportStream
00820 **                      DCM_GetObjectSize
00821 **                      DCM_DumpElements
00822 **                      DCM_Debug
00823 **                      DCM_WriteFile
00824 **                      DCM_ModifyElements
00825 **                      DCM_ParseObject
00826 **                      DCM_RemoveGroup
00827 **                      DCM_GetSequenceList
00828 **                      DCM_ComputeExportSize
00829 **      private functions
00830 **                      newElementItem
00831 **                      findCreateGroup
00832 **                      insertNewElement
00833 **                      updateObjectType
00834 **                      updateSpecialElements
00835 **                      exportFixedFields
00836 **                      exportData
00837 **                      fileSize
00838 **                      swapInPlace
00839 **                      checkObject
00840 **                      writeFile
00841 **                      countBytes
00842 **                      exportStream
00843 **                      verifyFormat
00844 **                      readFile
00845 ** Author, Date:        Stephen M. Moore, 26-Apr-93
00846 ** Intent:
00847 **      This file contains the routines which implement a facility for
00848 **      manipulating DICOM V3 information objects.  These routines parse
00849 **      and construct NEMA objects (or streams).  Users are able to
00850 **      read/write/examine individual attributes.  The package uses those
00851 **      individual elements to construct an internal memory representation of
00852 **      an object.  This representation is a linked list of the individual
00853 **      attributes.  The user of the package can add attributes to an object,
00854 **      remove an element from an object, query the object about an attribute,
00855 **      and convert the object to and from its "stream" representation.
00856 **      In addition, the package can parse a file which contains a stream
00857 **      and create its internal object.
00858 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
00859 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
00860 ** Revision:            $Revision: 1.2 $
00861 ** Status:              $State: Exp $
00862 */
00863 
00864 
00865 static CTNBOOLEAN debug = FALSE;/* Flag for debugging messages to stdout */
00866 
00867 /* Prototypes for internal functions
00868 */
00869 static CONDITION
00870 newElementItem(DCM_ELEMENT * src, CTNBOOLEAN allocateData,
00871                PRV_ELEMENT_ITEM ** dst);
00872 static CONDITION
00873 findCreateGroup(PRIVATE_OBJECT ** object, unsigned short group,
00874                 PRV_GROUP_ITEM ** groupPtr);
00875 static CONDITION
00876 insertNewElement(PRIVATE_OBJECT ** object,
00877                  DCM_ELEMENT * element);
00878 static CONDITION
00879 updateObjectType(PRIVATE_OBJECT ** object,
00880                  DCM_ELEMENT * element);
00881 static CONDITION
00882 updateSpecialElements(PRIVATE_OBJECT ** object,
00883                       PRV_ELEMENT_ITEM * item);
00884 static void
00885 exportFixedFields(DCM_ELEMENT * element,
00886                   unsigned char *b, U32 length, int byteOrder,
00887                   CTNBOOLEAN explicitVR, U32 * rtnLength);
00888 static CONDITION
00889 exportData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
00890            unsigned char *src,
00891            unsigned char *dst, U32 length, int byteOrder,
00892            U32 * rtnLength);
00893 #ifdef MACOS
00894 static long fileSize(int fd);
00895 #else
00896 static int fileSize(int fd);
00897 #endif
00898 static void swapInPlace(PRIVATE_OBJECT ** object, DCM_ELEMENT * e);
00899 static CONDITION checkObject(PRIVATE_OBJECT ** object, char *caller);
00900 static CONDITION
00901     writeFile(void *buffer, U32 length, int flag, void /* int */ *fd);
00902 static CONDITION
00903 countBytes(void *buffer, U32 length, int flag,
00904            void /* unsigned long */ *sizePtr);
00905 static CONDITION
00906 exportStream(DCM_OBJECT ** callerObject, unsigned long opt,
00907              void *buffer, U32 bufferlength, CONDITION(*callback) (),
00908              void *ctx, int sequenceLevel);
00909 
00910 static CONDITION
00911     verifyFormat(PRV_ELEMENT_ITEM * item);
00912 static CONDITION
00913 readFile(char *name, unsigned char *callerBuf, int fd, long size,
00914          off_t fileOffset, int recursionLevel,
00915          unsigned long opt, DCM_OBJECT ** callerObject,
00916          U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
00917          void *ctx,
00918          CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
00919          CONDITION(*sk) (void *ctx, int offset, int flag));
00920 static CONDITION
00921 readFile1(const char *name, unsigned char *callerBuf, int fd, U32 size,
00922           off_t * fileOffset, int recursionLevel,
00923           unsigned long opt, PRIVATE_OBJECT ** parentObject,
00924           DCM_OBJECT ** callerObject,
00925           U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
00926           void *ctx,
00927           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
00928           CONDITION(*sk) (void *ctx, int offset, int flag));
00929 
00930 static PRV_ELEMENT_ITEM *locateElement(PRIVATE_OBJECT ** obj, DCM_TAG tag);
00931 static void computeVM(PRIVATE_OBJECT ** object, DCM_ELEMENT * element);
00932 static void ctxSensitiveLookup(PRIVATE_OBJECT ** object, DCM_ELEMENT * element);
00933 static CONDITION
00934 copyData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
00935          DCM_ELEMENT * to, U32 * rtnLength);
00936 static CONDITION
00937 readLengthToEnd(int fd, const char *fileName,
00938                 unsigned long opt, U32 * lengthToEnd);
00939 
00940 static void swapATGroupElement(DCM_ELEMENT * e);
00941 
00942 static void
00943 dumpBinaryData(void *d, DCM_VALUEREPRESENTATION vr,
00944                long vm, long vmLimit);
00945 static void
00946 compareGroup(PRV_GROUP_ITEM * g1, PRV_GROUP_ITEM * g2,
00947              void (*callback) (const DCM_ELEMENT * e1,
00948                                const DCM_ELEMENT * e2,
00949                                void *ctx),
00950              void *ctx);
00951 static void remapFileName(const char *name, char *mapName);
00952 
00953 
00954 /* DCM_OpenFile
00955 **
00956 ** Purpose:
00957 **  This function opens a file that conforms to the DICOM V3 standard.
00958 **  The file is parsed and an internal representation of the data is created.
00959 **  A handle is returned to the caller to allow access to the data.
00960 **
00961 ** Parameter Dictionary:
00962 **   name       ASCIZ string giving path name to file to be opened.
00963 **   opt        BITMASK giving options used when opening file and
00964 **              interpreting data.  Current options have to do with the
00965 **              byte order of the data in the file.  Legal masks for
00966 **              this field are:
00967 **                      DCM_ORDERNATIVE
00968 **                      DCM_ORDERLITTLEENDIAN
00969 **                      DCM_ORDERBIGENDIAN
00970 **   object     Pointer to handle to return to caller  giving caller
00971 **              future access to the data in the object.
00972 **
00973 ** Return Values:
00974 **
00975 **      DCM_ELEMENTCREATEFAILED
00976 **      DCM_ELEMENTLENGTHERROR
00977 **      DCM_ELEMENTOUTOFORDER
00978 **      DCM_FILEACCESSERROR
00979 **      DCM_FILEOPENFAILED
00980 **      DCM_ILLEGALOPTION
00981 **      DCM_ILLEGALSTREAMLENGTH
00982 **      DCM_LISTFAILURE
00983 **      DCM_NORMAL
00984 **      DCM_OBJECTCREATEFAILED
00985 **      DCM_UNEVENELEMENTLENGTH
00986 **
00987 ** Algorithm:
00988 **      Determine file byte order (per caller's options)
00989 **      Create new ACR object
00990 **      Open file read only.
00991 **      Determine size of file
00992 **      While you have not reached end of file
00993 **          Read next (group, element, length) triple
00994 **          Lookup data element in dictionary
00995 **          Read data value according to byte order and (group,element)
00996 **          Check to see that data element is in numerical order
00997 **          Add data element to linked list
00998 **      End while
00999 */
01000 
01001 CONDITION
01002 DCM_OpenFile(const char *name, unsigned long opt, DCM_OBJECT ** callerObject)
01003 {
01004     CONDITION cond;
01005     int fd;
01006     off_t fileOffset = 0;
01007     U32 lengthToEnd;
01008     U32 size;
01009     CTNBOOLEAN
01010         remainFileOpen = FALSE; /* Leave file open after parse ? */
01011 
01012 ENTRY("DCM_OpenFile") ;
01013 
01014     if ((opt & (DCM_ORDERMASK | DCM_FILEFORMATMASK)) == 0)
01015         RETURN(COND_PushCondition(DCM_ILLEGALOPTION,
01016                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
01017                                   "DCM_OpenFile"));
01018 
01019 #ifdef _MSC_VER
01020     fd = open(name, O_RDONLY | O_BINARY);
01021 #else
01022     rwc_fd = fd = open(name, O_RDONLY);
01023 #endif
01024     if ((fd < 0) && ((opt & DCM_FILENAMEMASK) == DCM_TRYFILENAMECHANGE)) {
01025         char mapName[1024];
01026         remapFileName(name, mapName);
01027 #ifdef _MSC_VER
01028         fd = open(mapName, O_RDONLY | O_BINARY);
01029 #else
01030         fd = open(mapName, O_RDONLY);
01031         if (fd < 0) {
01032             strcat(mapName, ".");
01033             fd = open(mapName, O_RDONLY);
01034         }
01035 #endif
01036     }
01037     if (fd < 0) {
01038         char msg[1024] ;
01039         sprintf(msg,"DCM_OpenFile open(%s) fails",name) ;
01040         perror(msg) ;
01041         RETURN(COND_PushCondition(DCM_FILEOPENFAILED,
01042                                   DCM_Message(DCM_FILEOPENFAILED), name,
01043                                   "DCM_OpenFile"));
01044     }
01045     size = fileSize(fd);
01046     if (size <= 0)
01047         RETURN(DCM_FILEACCESSERROR);
01048 
01049     if ((opt & DCM_LENGTHTOENDMASK) == DCM_USELENGTHTOEND) {
01050         cond = readLengthToEnd(fd, name,
01051                                opt & (~DCM_LENGTHTOENDMASK), &lengthToEnd);
01052         if (cond != DCM_NORMAL) {
01053             (void) close(fd); rwc_fd = -1 ;
01054             RETURN(COND_PushCondition(DCM_FILEOPENFAILED,
01055                      DCM_Message(DCM_FILEOPENFAILED), name, "DCM_OpenFile"));
01056         }
01057         size = lengthToEnd;
01058         fileOffset = 24;
01059         (void) lseek(fd, 24, SEEK_SET);
01060     }
01061 #ifdef OLDSMM
01062     cond = readFile(name, NULL, fd, size, 0, 0, opt, callerObject, NULL,
01063                     &remainFileOpen, NULL, NULL, NULL);
01064 #endif
01065     cond = readFile1(name, NULL, fd, size, &fileOffset, 0, opt, NULL,
01066                      callerObject, NULL, &remainFileOpen, NULL, NULL, NULL);
01067     if ((cond != DCM_NORMAL) || !remainFileOpen){
01068         (void) close(fd); rwc_fd = -1 ;
01069     }
01070     if (cond != DCM_NORMAL) {
01071         if (debug)
01072             DCM_DumpElements(callerObject, 1);
01073         RETURN(COND_PushCondition(DCM_FILEOPENFAILED,
01074                      DCM_Message(DCM_FILEOPENFAILED), name, "DCM_OpenFile"));
01075     } else
01076         RETURN(DCM_NORMAL);
01077 }
01078 
01079 CONDITION
01080 DCM_ReadStream(DCM_OBJECT ** callerObject, unsigned long opt, long size,
01081                void *ctx,
01082           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
01083                CONDITION(*sk) (void *ctx, int offset, int flag))
01084 {
01085     CONDITION cond;
01086     int fd = -1;
01087     CTNBOOLEAN
01088         remainFileOpen = FALSE; /* Leave file open after parse ? */
01089     off_t fileOffset = 0;
01090 
01091     if ((opt & (DCM_ORDERMASK | DCM_FILEFORMATMASK)) == 0)
01092         return COND_PushCondition(DCM_ILLEGALOPTION,
01093                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
01094                                   "DCM_ReadStream");
01095 
01096     cond = readFile1("", NULL, fd, size, &fileOffset, 0, opt, NULL,
01097                      callerObject, NULL, &remainFileOpen, ctx, rd, sk);
01098     if (cond != DCM_NORMAL)
01099         return COND_PushCondition(DCM_READSTREAMFAILED,
01100                        DCM_Message(DCM_READSTREAMFAILED), "DCM_ReadStream");
01101     else
01102         return DCM_NORMAL;
01103 }
01104 
01105 /* DCM_CreateObject
01106 **
01107 ** Purpose:
01108 **      This function creates a new object and initializes some
01109 **      of the fields in the object
01110 **
01111 ** Parameter Dictionary:
01112 **      object          Pointer to caller's handle for object to be created.
01113 **      opt             Flag with options used when creating object.
01114 **                      The only option that we use now is DCM_NOGROUPLENGTH.
01115 **
01116 ** Return Values:
01117 **      DCM_NORMAL
01118 **      DCM_OBJECTCREATEFAILED
01119 **      DCM_LISTFAILURE
01120 **
01121 ** Algorithm:
01122 **      Description of the algorithm (optional) and any other notes.
01123 */
01124 
01125 CONDITION
01126 DCM_CreateObject(DCM_OBJECT ** object, unsigned long opt)
01127 {
01128     PRIVATE_OBJECT
01129         * obj;
01130 
01131     if (object == NULL) {
01132         (void) COND_PushCondition(DCM_NULLADDRESS,
01133                           DCM_Message(DCM_NULLADDRESS), "DCM_CreateObject");
01134         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
01135                    DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CreateObject");
01136     }
01137     obj = (PRIVATE_OBJECT *) CTN_MALLOC(sizeof(PRIVATE_OBJECT));
01138     if (obj == NULL) {
01139         (void) COND_PushCondition(DCM_MALLOCFAILURE,
01140                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
01141                                   "DCM_CreateObject");
01142         *object = NULL;
01143         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
01144                    DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CreateObject");
01145     }
01146     (void) memset(obj, 0, sizeof(PRIVATE_OBJECT));
01147     (void) strcpy(obj->keyType, KEY_DCM_OBJECT);
01148 
01149 
01150     obj->objectType = DCM_OBJECTUNKNOWN;
01151     obj->accessMethod = DCM_MEMORY_ACCESS;
01152     obj->deleteFlag = FALSE;
01153     if ((opt & DCM_GROUPLENGTHMASK) == DCM_NOGROUPLENGTH)
01154         obj->groupLengthFlag = FALSE;
01155     else
01156         obj->groupLengthFlag = TRUE;
01157     obj->objectSize = 0;
01158     obj->offset = 0;
01159     obj->pixelSize = 0;
01160     obj->pixelOffset = 0;
01161     obj->pixelBitsAllocated = 0;
01162     obj->pixelRepresentation = 0xffff;
01163     obj->groupCtx = NULL;
01164     obj->elementCtx = NULL;
01165     obj->fd = -1;
01166     obj->fileName[0] = '\0';
01167     obj->preambleFlag = FALSE;
01168     obj->preamble[0] = '\0';
01169     obj->dataOptions = 0;
01170     obj->metaHeaderLength = 0xffffffff;
01171     obj->longVRAttributes = 0;
01172     obj->waveformDataVR[0] = '\0';
01173 
01174     obj->groupList = LST_Create();
01175     if (obj->groupList == NULL) {
01176         CTN_FREE(obj);
01177         *object = NULL;
01178         return COND_PushCondition(DCM_LISTFAILURE,
01179                                   DCM_Message(DCM_LISTFAILURE),
01180                                   "DCM_CreateObject");
01181     }
01182     *object = (DCM_OBJECT *) obj;
01183     return DCM_NORMAL;
01184 }
01185 
01186 
01187 /* DCM_CloseObject
01188 **
01189 ** Purpose:
01190 **      Close an information object by freeing memory allocated to it and
01191 **      destroying caller's reference to it.
01192 **
01193 ** Parameter Dictionary:
01194 **      callerObject    Address of caller's pointer to a DCM_OBJECT.
01195 **
01196 ** Return Values:
01197 **
01198 **      DCM_FILEDELETEFAILED
01199 **      DCM_ILLEGALOBJECT
01200 **      DCM_LISTFAILURE
01201 **      DCM_NORMAL
01202 **      DCM_NULLOBJECT
01203 **
01204 ** Algorithm:
01205 */
01206 
01207 CONDITION
01208 DCM_CloseObject(DCM_OBJECT ** callerObject)
01209 {
01210     CONDITION
01211         cond;
01212     PRV_GROUP_ITEM
01213         * group;
01214     PRV_ELEMENT_ITEM
01215         * element;
01216     PRIVATE_OBJECT
01217         ** object;
01218     DCM_SEQUENCE_ITEM
01219         * sequenceItem;
01220     DCM_FRAGMENT_ITEM* fragmentItem;
01221 
01222     if (debug)
01223         fprintf(stderr, "Starting DCM_CloseObject\n");
01224 
01225     object = (PRIVATE_OBJECT **) callerObject;
01226     cond = checkObject(object, "DCM_CloseObject");
01227     if (cond != DCM_NORMAL)
01228         return cond;
01229 
01230     if ((*object)->fd > 0)
01231         (void) close((*object)->fd);
01232 
01233     if (debug)
01234         fprintf(stderr, "DCM_CloseObject: Legal object and file closed\n");
01235 
01236     while ((group = (void *)LST_Pop(&(*object)->groupList)) != NULL) {
01237         if (debug)
01238             fprintf(stderr, "DCM_CloseObject: group %04x\n", group->group);
01239 
01240         while ((element = (void *)LST_Pop(&group->elementList)) != NULL) {
01241             if (debug)
01242                 fprintf(stderr, "DCM_CloseObject: Element %08x\n",
01243                         element->element.tag);
01244             if (element->element.representation == DCM_SQ) {
01245                 if (debug)
01246                     fprintf(stderr, "Sequence List Address: %p\n",
01247                             element->element.d.sq);
01248                 if (element->element.d.sq != NULL) {
01249                     while ((sequenceItem = (void *)LST_Pop(&element->element.d.sq)) != NULL) {
01250                         (void) DCM_CloseObject(&sequenceItem->object);
01251                         CTN_FREE(sequenceItem);
01252                     }
01253                     (void) LST_Destroy(&element->element.d.sq);
01254                 }
01255             } else if (element->fragmentFlag) {
01256                 if (debug)
01257                     fprintf(stderr, "Fragment List Address: %p\n",
01258                             element->element.d.fragments);
01259                 if (element->element.d.fragments != NULL) {
01260                     while ((fragmentItem = (void *)LST_Pop(&element->element.d.fragments)) != NULL) {
01261                         CTN_FREE(fragmentItem);
01262                     }
01263                     (void) LST_Destroy(&element->element.d.fragments);
01264                 }
01265             }
01266             if (debug)
01267                 fprintf(stderr, "DCM_CloseObject: free %8p\n", element);
01268 
01269             CTN_FREE(element);
01270         }
01271         cond = LST_Destroy(&group->elementList);
01272         if (cond != LST_NORMAL)
01273             return COND_PushCondition(DCM_LISTFAILURE,
01274                            DCM_Message(DCM_LISTFAILURE), "DCM_CloseObject");
01275         CTN_FREE(group);
01276     }
01277     cond = LST_Destroy(&(*object)->groupList);
01278     if (cond != LST_NORMAL)
01279         return COND_PushCondition(DCM_LISTFAILURE,
01280                            DCM_Message(DCM_LISTFAILURE), "DCM_CloseObject");
01281 
01282     cond = DCM_NORMAL;
01283     if ((*object)->deleteFlag) {
01284         if (unlink((*object)->fileName) != 0) {
01285 /****    (void) COND_PushCondition(DCM_FILEDELETEFAILED, strerror(errno));****/
01286             cond = COND_PushCondition(DCM_FILEDELETEFAILED,
01287                                       DCM_Message(DCM_FILEDELETEFAILED), (*object)->fileName, strerror(errno),
01288                                       "DCM_CloseObject");
01289 
01290         }
01291     }
01292     CTN_FREE(*object);
01293     *object = NULL;
01294     return cond;
01295 }
01296 
01297 /* DCM_AddElement
01298 **
01299 ** Purpose:
01300 **      Add an element to an existing DCM object
01301 **
01302 ** Parameter Dictionary:
01303 **      object          Pointer to caller's existing DCM object.
01304 **      element         Pointer to DCM element to be added to object
01305 **
01306 ** Return Values:
01307 **
01308 **      DCM_ILLEGALOBJECT
01309 **      DCM_ILLEGALREPRESENTATION
01310 **      DCM_INSERTFAILED
01311 **      DCM_NORMAL
01312 **      DCM_NULLOBJECT
01313 **
01314 ** Algorithm:
01315 **      Check caller's object to make certain it is a legal object
01316 **      Check element to see that caller is not trying to add
01317 **          group length or length to end data elements.
01318 **      Lookup element in the dictionary
01319 **      If element is not in the dictionary, use caller's definition
01320 **      If element is in the dictionary, make certain caller used
01321 **          proper definitions or left things undefined.
01322 **      Call findCreateGroup to
01323 **          - create new group if this group does not exist
01324 **          - create length to end element if necessary
01325 **          - update object size for this object
01326 **          - set CURRENT pointer in linked list to head of this group
01327 **      Call insertNewElement to
01328 **          - create a copy of the caller's element
01329 **          - insert copy into linked list
01330 **      Call updateObjectType to
01331 **          - update this object as type COMMAND, DATASET, MESSAGE
01332 */
01333 
01334 CONDITION
01335 DCM_AddElement(DCM_OBJECT ** callerObject, DCM_ELEMENT * element)
01336 {
01337     CONDITION
01338         cond;
01339     DCM_ELEMENT
01340         localElement;
01341     PRIVATE_OBJECT
01342         ** object;
01343     PRV_GROUP_ITEM
01344         * groupItem;
01345 
01346     object = (PRIVATE_OBJECT **) callerObject;
01347 
01348     cond = checkObject(object, "DCM_AddElement");
01349     if (cond != DCM_NORMAL)
01350         return cond;
01351 
01352     if ((DCM_TAG_ELEMENT(element->tag) == 0x0000))
01353         return COND_PushCondition(DCM_ILLEGALADD,
01354                    DCM_Message(DCM_ILLEGALADD), DCM_TAG_GROUP(element->tag),
01355                            DCM_TAG_ELEMENT(element->tag), "DCM_AddElement");
01356 
01357 
01358     localElement = *element;
01359 
01360     cond = DCM_LookupElement(&localElement);
01361     if (cond != DCM_NORMAL) {
01362         (void) COND_PopCondition(0);
01363         localElement = *element;
01364     } else {
01365         if (localElement.representation == DCM_OT ||
01366             localElement.representation == DCM_CTX)
01367             localElement.representation = element->representation;
01368         if (element->representation != DCM_UN &&
01369             element->representation != localElement.representation) {
01370             return COND_PushCondition(DCM_ILLEGALREPRESENTATION,
01371                                       DCM_Message(DCM_ILLEGALREPRESENTATION),
01372                                       DCM_TAG_GROUP(element->tag),
01373                                       DCM_TAG_ELEMENT(element->tag),
01374                                       "DCM_AddElement");
01375         }
01376     }
01377 
01378     cond = findCreateGroup(object, DCM_TAG_GROUP(localElement.tag), &groupItem);
01379     if (cond != DCM_NORMAL)
01380         return COND_PushCondition(DCM_INSERTFAILED,
01381                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01382                                   DCM_TAG_ELEMENT(element->tag),
01383                                   "DCM_AddElement");
01384 
01385     cond = insertNewElement(object, &localElement);
01386     if (cond != DCM_NORMAL)
01387         return COND_PushCondition(DCM_INSERTFAILED,
01388                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01389                                   DCM_TAG_ELEMENT(element->tag),
01390                                   "DCM_AddElement");
01391 
01392     cond = updateObjectType(object, &localElement);
01393     if (cond != DCM_NORMAL)
01394         return COND_PushCondition(DCM_INSERTFAILED,
01395                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01396                                   DCM_TAG_ELEMENT(element->tag),
01397                                   "DCM_AddElement");
01398 
01399     return DCM_NORMAL;
01400 }
01401 
01402 /* DCM_AddSequenceElement
01403 **
01404 ** Purpose:
01405 **      Add a sequence element to an existing DCM object.  This
01406 **      function takes ownership of the caller's sequence list
01407 **      when it adds the element to the object.  The caller's
01408 **      copy of the sequence list is removed.
01409 **
01410 ** Parameter Dictionary:
01411 **      object          Pointer to caller's existing DCM object.
01412 **      element         Pointer to DCM element to be added to object
01413 **
01414 ** Return Values:
01415 **
01416 **      DCM_ILLEGALOBJECT
01417 **      DCM_ILLEGALREPRESENTATION
01418 **      DCM_INSERTFAILED
01419 **      DCM_NORMAL
01420 **      DCM_NULLOBJECT
01421 **
01422 ** Algorithm:
01423 */
01424 
01425 CONDITION
01426 DCM_AddSequenceElement(DCM_OBJECT ** callerObject, DCM_ELEMENT * element)
01427 {
01428     CONDITION cond;
01429     DCM_ELEMENT localElement;
01430     PRIVATE_OBJECT **object;
01431     PRV_GROUP_ITEM *groupItem;
01432 
01433     object = (PRIVATE_OBJECT **) callerObject;
01434 
01435     cond = checkObject(object, "DCM_AddSequenceElement");
01436     if (cond != DCM_NORMAL)
01437         return cond;
01438 
01439     if ((DCM_TAG_ELEMENT(element->tag) == 0x0000))
01440         return COND_PushCondition(DCM_ILLEGALADD,
01441                    DCM_Message(DCM_ILLEGALADD), DCM_TAG_GROUP(element->tag),
01442                            DCM_TAG_ELEMENT(element->tag), "DCM_AddElement");
01443 
01444 
01445     localElement = *element;
01446 
01447     cond = DCM_LookupElement(&localElement);
01448     if (cond != DCM_NORMAL) {
01449         (void) COND_PopCondition(0);
01450         localElement = *element;
01451     } else {
01452         localElement.representation = element->representation;
01453     }
01454     if (localElement.representation != DCM_SQ) {
01455         return COND_PushCondition(DCM_NOTASEQUENCE,
01456                                   DCM_Message(DCM_NOTASEQUENCE),
01457                                   DCM_TAG_GROUP(localElement.tag),
01458                                   DCM_TAG_ELEMENT(localElement.tag),
01459                                   "DCM_AddSequenceElement");
01460     }
01461     cond = findCreateGroup(object, DCM_TAG_GROUP(localElement.tag), &groupItem);
01462     if (cond != DCM_NORMAL)
01463         return COND_PushCondition(DCM_INSERTFAILED,
01464                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01465                                   DCM_TAG_ELEMENT(element->tag),
01466                                   "DCM_AddSequenceElement");
01467 
01468     cond = insertNewElement(object, &localElement);
01469     if (cond != DCM_NORMAL)
01470         return COND_PushCondition(DCM_INSERTFAILED,
01471                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01472                                   DCM_TAG_ELEMENT(element->tag),
01473                                   "DCM_AddElement");
01474 
01475     cond = updateObjectType(object, &localElement);
01476     if (cond != DCM_NORMAL)
01477         return COND_PushCondition(DCM_INSERTFAILED,
01478                  DCM_Message(DCM_INSERTFAILED), DCM_TAG_GROUP(element->tag),
01479                                   DCM_TAG_ELEMENT(element->tag),
01480                                   "DCM_AddSequenceElement");
01481 
01482     /*
01483      * We have taken ownership of the sequence list, so zero out caller's
01484      * copy
01485      */
01486     element->d.sq = NULL;
01487 
01488     return DCM_NORMAL;
01489 }
01490 
01491 /* DCM_RemoveElement
01492 **
01493 ** Purpose:
01494 **      This function removes a single element from an information object.
01495 **
01496 ** Parameter Dictionary:
01497 **      callerObject            Handle to the object
01498 **      tag                     The tag of the element to be removed
01499 **
01500 ** Return Values:
01501 **
01502 **      DCM_ELEMENTNOTFOUND
01503 **      DCM_ILLEGALOBJECT
01504 **      DCM_NORMAL
01505 **      DCM_NULLOBJECT
01506 **
01507 ** Algorithm:
01508 **      Description of the algorithm (optional) and any other notes.
01509 */
01510 
01511 CONDITION
01512 DCM_RemoveElement(DCM_OBJECT ** callerObject, DCM_TAG tag)
01513 {
01514     PRIVATE_OBJECT
01515         ** object;
01516     PRV_GROUP_ITEM
01517         * groupItem;
01518     PRV_ELEMENT_ITEM
01519         * elementItem,
01520         *groupLengthItem;
01521     CONDITION
01522         cond;
01523     CTNBOOLEAN
01524         flag;
01525     unsigned short
01526         group,
01527         element;
01528 
01529     object = (PRIVATE_OBJECT **) callerObject;
01530     cond = checkObject(object, "DCM_RemoveElement");
01531     if (cond != DCM_NORMAL)
01532         return cond;
01533 
01534     group = DCM_TAG_GROUP(tag);
01535     element = DCM_TAG_ELEMENT(tag);
01536 
01537     groupItem = (void *)LST_Head(&((*object)->groupList));
01538     if (groupItem == NULL)
01539         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01540                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01541                                   "DCM_RemoveElement");
01542 
01543     (void) LST_Position(&((*object)->groupList), (void *)groupItem);
01544 
01545     flag = FALSE;
01546     while ((groupItem != NULL) && (flag == FALSE)) {
01547         if (groupItem->group == group)
01548             flag = TRUE;
01549         else
01550             groupItem = (void *)LST_Next(&(*object)->groupList);
01551     }
01552     if (flag == FALSE)
01553         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01554                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01555                                   "DCM_RemoveElement");
01556 
01557     elementItem = (void *)LST_Head(&groupItem->elementList);
01558     if (elementItem == NULL)
01559         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01560                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01561                                   "DCM_RemoveElement");
01562 
01563     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
01564 
01565     groupLengthItem = elementItem;
01566     if (DCM_TAG_ELEMENT(groupLengthItem->element.tag) != 0x0000)
01567         groupLengthItem = NULL;
01568 
01569 
01570     flag = FALSE;
01571     while ((elementItem != NULL) && (flag == FALSE)) {
01572         if (DCM_TAG_ELEMENT(elementItem->element.tag) == element)
01573             flag = TRUE;
01574         else
01575             elementItem = (void *)LST_Next(&groupItem->elementList);
01576     }
01577 
01578     if (flag == FALSE)
01579         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01580                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
01581                                   "DCM_RemoveElement");
01582 
01583     if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH) {
01584         groupItem->baseLength -= elementItem->paddedDataLength + 2 + 2 + 4;
01585         if (groupLengthItem != NULL) {
01586             *groupLengthItem->element.d.ul = groupItem->baseLength;
01587         }
01588     }
01589     if ((*object)->objectSize != DCM_UNSPECIFIEDLENGTH)
01590         (*object)->objectSize -= elementItem->paddedDataLength + 2 + 2 + 4;
01591     if (elementItem->element.representation == DCM_OW ||
01592         elementItem->element.representation == DCM_OB ||
01593         elementItem->element.representation == DCM_SQ) {
01594         groupItem->longVRAttributes--;
01595         (*object)->longVRAttributes--;
01596     }
01597     (void) LST_Remove(&(groupItem->elementList), LST_K_AFTER);
01598     CTN_FREE(elementItem);
01599     return DCM_NORMAL;
01600 }
01601 
01602 /* DCM_GetElementValue
01603 **
01604 ** Purpose:
01605 **      This function retrieves the data from one data element and
01606 **      returns it in a buffer allocated by the caller.  In the event
01607 **      the data is larger than the caller's buffer, multiple calls
01608 **      are used to retrieve the data.
01609 **
01610 ** Parameter Dictionary:
01611 **      object          Pointer to user's object containing desired element
01612 **      element         DCM_ELEMENT structure containing (group,element)
01613 **                      specification of desired data element
01614 **      rtnLength       Pointer to caller variable to hold length of
01615 **                      data returned by this call.
01616 **      ctx             Pointer to context variable used for multiple
01617 **                      calls to this function.  Caller should set the
01618 **                      pointer to NULL before the first call and not
01619 **                      touch the pointer again.
01620 **
01621 ** Return Values:
01622 **
01623 **      DCM_CANNOTGETSEQUENCEVALUE
01624 **      DCM_ELEMENTNOTFOUND
01625 **      DCM_GETINCOMPLETE
01626 **      DCM_ILLEGALCONTEXT
01627 **      DCM_ILLEGALOBJECT
01628 **      DCM_NORMAL
01629 **      DCM_NULLOBJECT
01630 **
01631 ** Algorithm:
01632 **      Check caller's object to make certain it is a legal DCM object.
01633 **      Find head of the object linked list.
01634 **      Search linked list sequentially until object is found or end
01635 **      of list reached.
01636 **      If end of list
01637 **              return DCM_ELEMENTNOTFOUND
01638 **      If CTX pointer containts NULL
01639 **          Begin copy from beginning of element
01640 **      else
01641 **          Begin copy from address in CTX pointer
01642 **      Copy data from element data area to user buffer
01643 **      If copy is incomplete (remaining data longer than caller's buffer)
01644 **          Update CTX pointer to point to next uncopied part of data
01645 **          Return DCM_GETINCOMPLETE
01646 **      else
01647 **          Update CTX pointer to point past data area.
01648 **          Return DCM_NORMAL
01649 */
01650 
01651 CONDITION
01652 DCM_GetElementValue(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
01653                     U32 * rtnLength, void **ctx)
01654 {
01655     PRIVATE_OBJECT
01656         ** object;
01657     PRV_GROUP_ITEM
01658         * groupItem;
01659     PRV_ELEMENT_ITEM
01660         * elementItem;
01661     int
01662         nBytes;
01663     CONDITION
01664         cond;
01665 
01666     object = (PRIVATE_OBJECT **) callerObject;
01667     cond = checkObject(object, "DCM_GetElementValue");
01668     if (cond != DCM_NORMAL)
01669         return cond;
01670 
01671     groupItem = (void *)LST_Head(&(*object)->groupList);
01672     if (groupItem == NULL)
01673         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01674               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01675                                   DCM_TAG_ELEMENT(element->tag),
01676                                   "DCM_GetElementValue");
01677 
01678     (void) LST_Position(&(*object)->groupList, (void *)groupItem);
01679     while (groupItem != NULL) {
01680         if (groupItem->group == DCM_TAG_GROUP(element->tag))
01681             break;
01682 
01683         groupItem = (void *)LST_Next(&(*object)->groupList);
01684     }
01685     if (groupItem == NULL)
01686         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01687               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01688                                   DCM_TAG_ELEMENT(element->tag),
01689                                   "DCM_GetElementValue");
01690 
01691     elementItem = (void *)LST_Head(&groupItem->elementList);
01692     if (elementItem == NULL)
01693         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01694               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01695                                   DCM_TAG_GROUP(element->tag),
01696                                   "DCM_GetElementValue");
01697 
01698     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
01699     while (elementItem != NULL) {
01700         if (elementItem->element.tag == element->tag) {
01701             unsigned char *p;
01702             U32 l;
01703 
01704             if (element->representation == DCM_SQ)
01705                 return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
01706                                     DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
01707                                        element->tag, "DCM_GetElementValue");
01708 
01709             p = *ctx;
01710             if ((U32) p > elementItem->element.length)
01711                 return COND_PushCondition(DCM_ILLEGALCONTEXT,
01712                                           DCM_Message(DCM_ILLEGALCONTEXT),
01713                                           "DCM_GetElementValue");
01714 
01715             l = MIN(element->length, (elementItem->element.length - (U32) p));
01716 
01717             *rtnLength = l;
01718             {
01719                 if (elementItem->element.d.ot == NULL) {
01720                     if ((*object)->fd != -1) {
01721                         (void) lseek((*object)->fd,
01722                              elementItem->dataOffset + (off_t) p, SEEK_SET);
01723                         nBytes = read((*object)->fd, element->d.ot, (int) l);
01724                     } else {
01725                         (*object)->sk((*object)->userCtx,
01726                                       (long) (elementItem->dataOffset + (off_t) p), SEEK_SET);
01727                         cond = (*object)->rd((*object)->userCtx, element->d.ot, l,
01728                                              &nBytes);
01729                     }
01730                     if ((unsigned) nBytes != l) {
01731                         return COND_PushCondition(DCM_FILEACCESSERROR,
01732                                            DCM_Message(DCM_FILEACCESSERROR),
01733                                                   (*object)->fileName,
01734                                                   "DCM_GetElementValue");
01735                     }
01736                     if( LITTLE_ENDIAN_ARCHITECTURE ){
01737                       if (elementItem->element.representation == DCM_AT) {
01738                           DCM_ELEMENT e;
01739                           e = elementItem->element;
01740                           e.length = l;
01741                           e.d.ot = element->d.ot;
01742                           swapATGroupElement(&e);
01743                       }
01744                     }
01745                     if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01746                         DCM_ELEMENT e;
01747                         e = elementItem->element;
01748                         e.length = l;
01749                         e.d.ot = element->d.ot;
01750                         swapInPlace(object, &e);
01751                     }
01752                 } else {
01753                     unsigned char *q;
01754                     q = (unsigned char *) elementItem->element.d.ot +
01755                         (U32) p;
01756                     (void) memcpy(element->d.ot, q, l);
01757                     if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01758                         DCM_ELEMENT e;
01759                         e = elementItem->element;
01760                         e.length = l;
01761                         e.d.ot = element->d.ot;
01762                         swapInPlace(object, &e);
01763                     }
01764                 }
01765                 p += l;
01766                 *ctx = (void *) p;
01767                 if ((unsigned) p == elementItem->element.length)
01768                     return DCM_NORMAL;
01769                 else
01770                     return DCM_GETINCOMPLETE;
01771             }
01772 
01773         }
01774         elementItem = (void *)LST_Next(&groupItem->elementList);
01775     }
01776     return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01777               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01778                               DCM_TAG_ELEMENT(element->tag),
01779                               "DCM_GetElementValue");
01780 }
01781 
01782 char*
01783 DCM_GetString(DCM_OBJECT** callerObject, DCM_TAG tag)
01784 {
01785   DCM_ELEMENT e;
01786   CONDITION cond;
01787   char* s;
01788   char tmp[64] = "";
01789   char b[64] = "";
01790 
01791   e.tag = tag;
01792   cond = DCM_GetElement(callerObject, tag, &e);
01793   if (cond != DCM_NORMAL) {
01794     COND_PopCondition(TRUE);
01795     return 0;
01796   }
01797 
01798   if (DCM_IsString(e.representation)) {
01799     s = AFMALL( char, e.length + 1);
01800     e.d.string = s;
01801     cond = DCM_ParseObject(callerObject, &e, 1, 0, 0, 0);
01802     if (cond != DCM_NORMAL) {
01803       free(s);
01804       s = 0;
01805     }
01806     return s;
01807   }
01808 
01809   if (e.representation == DCM_SQ) {
01810     return 0;
01811   }
01812 
01813   if (e.length > sizeof(b))
01814     return 0;
01815 
01816   e.d.ot = b;
01817   cond = DCM_ParseObject(callerObject, &e, 1, 0, 0, 0);
01818   if (cond != DCM_NORMAL) {
01819     COND_PopCondition(TRUE);
01820     return 0;
01821   }
01822 
01823   switch (e.representation) {
01824     case DCM_AT:
01825     case DCM_FD:
01826     case DCM_FL:
01827       strcpy(tmp, "<Unimplemented>");
01828       break;
01829     case DCM_SL:
01830       sprintf(tmp, "%d", *e.d.sl);
01831       break;
01832     case DCM_SQ:
01833       strcpy(tmp, "<Unimplemented>");
01834       break;
01835     case DCM_SS:
01836       sprintf(tmp, "%d", *e.d.ss);
01837       break;
01838     case DCM_UL:
01839       sprintf(tmp, "%d", *e.d.ul);
01840       break;
01841     case DCM_UN:
01842       strcpy(tmp, "<Unimplemented>");
01843       break;
01844     case DCM_US:
01845       sprintf(tmp, "%d", *e.d.us);
01846       break;
01847     /*case DCM_UNKNOWN:*/
01848     case DCM_RET:
01849     case DCM_CTX:
01850     case DCM_OB:
01851     case DCM_OW:
01852     case DCM_DLM:
01853     default:
01854       strcpy(tmp, "<Unimplemented>");
01855       break;
01856   }
01857 
01858   s = (char*) malloc(strlen(tmp) + 1);
01859   strcpy(s, tmp);
01860 
01861   return s;
01862 }
01863 
01864 
01865 
01866 CONDITION
01867 DCM_GetElementValueOffset(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
01868                           unsigned long offset)
01869 {
01870     PRIVATE_OBJECT **object;
01871     PRV_ELEMENT_ITEM *elementItem;
01872     int nBytes;
01873     CONDITION cond;
01874 
01875     object = (PRIVATE_OBJECT **) callerObject;
01876     cond = checkObject(object, "DCM_GetElementValue");
01877     if (cond != DCM_NORMAL)
01878         return cond;
01879 
01880     elementItem = locateElement(object, element->tag);
01881     if (elementItem == NULL)
01882         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
01883               DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(element->tag),
01884                                   DCM_TAG_ELEMENT(element->tag),
01885                                   "DCM_GetElementValueOffset");
01886 
01887 
01888     {
01889         unsigned char *p;
01890         U32 l;
01891 
01892         if (element->representation == DCM_SQ)
01893             return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
01894                                     DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
01895                                  element->tag, "DCM_GetElementValueOffset");
01896 
01897         p = (unsigned char *) offset;;
01898         if ((U32) p > elementItem->element.length)
01899             return COND_PushCondition(DCM_BADOFFSET,
01900                                       DCM_Message(DCM_BADOFFSET),
01901                                       (int) offset,
01902                                       (int) elementItem->element.length,
01903                                       "DCM_GetElementValueLength");
01904 
01905         l = element->length;
01906         if (l + offset > elementItem->element.length) {
01907             return COND_PushCondition(DCM_BADLENGTH,
01908                                       DCM_Message(DCM_BADLENGTH),
01909                                       (int) offset, (int) l,
01910                                       (int) elementItem->element.length,
01911                                       "DCM_GetElementValueLength");
01912         } {
01913             if (elementItem->element.d.ot == NULL) {
01914                 if ((*object)->fd != -1) {
01915                     (void) lseek((*object)->fd,
01916                              elementItem->dataOffset + (off_t) p, SEEK_SET);
01917                     nBytes = read((*object)->fd, element->d.ot, (int) l);
01918                 } else {
01919                     (*object)->sk((*object)->userCtx,
01920                     (long) (elementItem->dataOffset + (off_t) p), SEEK_SET);
01921                     cond = (*object)->rd((*object)->userCtx, element->d.ot, l,
01922                                          &nBytes);
01923                 }
01924                 if ((unsigned) nBytes != l) {
01925                     return COND_PushCondition(DCM_FILEACCESSERROR,
01926                                            DCM_Message(DCM_FILEACCESSERROR),
01927                                               (*object)->fileName,
01928                                               "DCM_GetElementValueValue");
01929                 }
01930                 if( LITTLE_ENDIAN_ARCHITECTURE ){
01931                   if (elementItem->element.representation == DCM_AT) {
01932                       DCM_ELEMENT e;
01933                       e = elementItem->element;
01934                       e.length = l;
01935                       e.d.ot = element->d.ot;
01936                       swapATGroupElement(&e);
01937                   }
01938                 }
01939                 if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01940                     DCM_ELEMENT e;
01941                     e = elementItem->element;
01942                     e.length = l;
01943                     e.d.ot = element->d.ot;
01944                     swapInPlace(object, &e);
01945                 }
01946             } else {
01947                 unsigned char *q;
01948                 q = (unsigned char *) elementItem->element.d.ot +
01949                     (U32) p;
01950                 (void) memcpy(element->d.ot, q, l);
01951                 if (elementItem->byteOrder == BYTEORDER_REVERSE) {
01952                     DCM_ELEMENT e;
01953                     e = elementItem->element;
01954                     e.length = l;
01955                     e.d.ot = element->d.ot;
01956                     swapInPlace(object, &e);
01957                 }
01958             }
01959             return DCM_NORMAL;
01960         }
01961 
01962     }
01963 }
01964 
01965 
01966 
01967 /* DCM_GetElementSize
01968 **
01969 ** Purpose:
01970 **      Return the size of one data element in an ACR object.
01971 **
01972 ** Parameter Dictionary:
01973 **      object          Pointer to caller's ACR object
01974 **      element         Pointer to ACR element that defines data element
01975 **                      of interest by specifying (group,element) pair
01976 **      rtnLength       Pointer to caller variable to hold returned
01977 **                      length of data element
01978 **
01979 ** Return Values:
01980 **
01981 **      DCM_NORMAL
01982 **      DCM_NULLOBJECT
01983 **      DCM_ILLEGALOBJECT
01984 **      DCM_ELEMENTNOTFOUND
01985 **
01986 ** Algorithm:
01987 **      Description of the algorithm (optional) and any other notes.
01988 */
01989 
01990 CONDITION
01991 DCM_GetElementSize(DCM_OBJECT ** callerObject, DCM_TAG tag,
01992                    U32 * rtnLength)
01993 {
01994     PRIVATE_OBJECT
01995         ** object;
01996     PRV_GROUP_ITEM
01997         * groupItem;
01998     PRV_ELEMENT_ITEM
01999         * elementItem;
02000     CONDITION
02001         cond;
02002     CTNBOOLEAN
02003         flag;
02004     unsigned short
02005         group,
02006         element;
02007 
02008     object = (PRIVATE_OBJECT **) callerObject;
02009     cond = checkObject(object, "DCM_GetElementSize");
02010     if (cond != DCM_NORMAL)
02011         return cond;
02012 
02013     group = DCM_TAG_GROUP(tag);
02014     element = DCM_TAG_ELEMENT(tag);
02015 
02016     groupItem = (void *)LST_Head(&((*object)->groupList));
02017     if (groupItem == NULL)
02018         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02019                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02020                                   "DCM_GetElementSize");
02021 
02022     (void) LST_Position(&((*object)->groupList), (void *)groupItem);
02023 
02024     flag = FALSE;
02025     while ((groupItem != NULL) && (flag == FALSE)) {
02026         if (groupItem->group == group)
02027             flag = TRUE;
02028         else
02029             groupItem = (void *)LST_Next(&(*object)->groupList);
02030     }
02031     if (flag == FALSE)
02032         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02033                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02034                                   "DCM_GetElementSize");
02035 
02036     elementItem = (void *)LST_Head(&groupItem->elementList);
02037     if (elementItem == NULL)
02038         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02039                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02040                                   "DCM_GetElementSize");
02041 
02042     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02043 
02044     flag = FALSE;
02045     while ((elementItem != NULL) && (flag == FALSE)) {
02046         if (elementItem->element.tag == tag)
02047             flag = TRUE;
02048         else
02049             elementItem = (void *)LST_Next(&groupItem->elementList);
02050     }
02051 
02052     if (flag == FALSE)
02053         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
02054                            DCM_Message(DCM_ELEMENTNOTFOUND), group, element,
02055                                   "DCM_GetElementSize");
02056 
02057 
02058     *rtnLength = elementItem->element.length;
02059     return DCM_NORMAL;
02060 }
02061 
02062 
02063 /* DCM_ScanParseObject
02064 **
02065 ** Purpose:
02066 **      DCM_ScanParseObject is used to allow a caller to examine every
02067 **      element in a DICOM object and to parse the elements in the object.
02068 **      The caller passes a list of elements to be parsed from the object.
02069 **      This function examines each element in the object in order
02070 **      (ascending group/element).  If the element in the object is found
02071 **      in the caller's parse list, the element is parsed (and a value
02072 **      placed in storage allocated by the caller).  If the element is
02073 **      not found in the caller's list, a callback function is invoked
02074 **      to notify the caller of the element.  When the callback function
02075 **      is invoked, the arguments are:
02076 **              DCM_ELEMENT *e  Pointer to the individual element
02077 **              void *ctx       Caller's context information
02078 **
02079 **      This function is very useful for determining exactly which
02080 **      elements are present in an object without having to ask for
02081 **      each one individually.
02082 **
02083 ** Parameter Dictionary:
02084 **      callerObject    Pointer to caller's DICOM object
02085 **      buf             Unused
02086 **      bufferSizd      Unused
02087 **      vector          A vector of elements which are to be parsed.  An entry
02088 **                      in the vector gives the tag and describes where the
02089 **                      parsed data is to be stored.
02090 **      vectorLength    Number of entries in the vector.
02091 **      callback        Caller function invoked for an element that is in
02092 **                      the object but is not found in caller's list.
02093 **      ctx             Context information that is passed to callback function.
02094 **
02095 ** Return Values:
02096 **
02097 **      DCM_NORMAL
02098 **      DCM_NULLOBJECT
02099 **      DCM_ILLEGALOBJECT
02100 **
02101 ** Algorithm:
02102 */
02103 
02104 CONDITION
02105 DCM_ScanParseObject(DCM_OBJECT ** callerObject, void *buf, size_t bufferSize,
02106                     DCM_FLAGGED_ELEMENT * elementVector, int vectorLength,
02107                     CONDITION(*callback) (const DCM_ELEMENT* e, void* ctx),
02108                     void *ctx)
02109 {
02110     PRIVATE_OBJECT
02111         ** object;
02112     PRV_GROUP_ITEM
02113         * groupItem;
02114     PRV_ELEMENT_ITEM
02115         * elementItem;
02116     CONDITION
02117         cond;
02118     CTNBOOLEAN
02119         done = FALSE;
02120     DCM_ELEMENT
02121         e;
02122     int
02123         i;
02124     CTNBOOLEAN
02125         found;
02126     U32
02127         l;
02128     char
02129        *p;
02130 
02131     object = (PRIVATE_OBJECT **) callerObject;
02132     cond = checkObject(object, "DCM_ScanParseObject");
02133     if (cond != DCM_NORMAL)
02134         return cond;
02135 
02136     groupItem = (void *)LST_Head(&((*object)->groupList));
02137     (void) LST_Position(&((*object)->groupList), (void *)groupItem);
02138     while (groupItem != NULL && !done) {
02139         elementItem = (void *)LST_Head(&groupItem->elementList);
02140         (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02141         while (elementItem != NULL && !done) {
02142             for (found = FALSE, i = 0; !found && i < vectorLength; i++) {
02143                 if (elementItem->element.tag == elementVector[i].e.tag) {
02144                     found = TRUE;
02145                     (void)copyData(object,elementItem,&elementVector[i].e, &l);
02146                     *elementVector[i].flagAddress |= elementVector[i].flag;
02147 
02148                     if (DCM_IsString(elementVector[i].e.representation)) {
02149                         elementVector[i].e.d.string[l] = '\0';
02150                         p = elementVector[i].e.d.string + l - 1;
02151                         while (p >= elementVector[i].e.d.string && (*p == ' '))
02152                             *p-- = '\0';
02153                     }
02154                 }
02155             }
02156             if (!found) {
02157                 e = elementItem->element;
02158                 cond = callback(&e, ctx);
02159                 if (cond != DCM_NORMAL)
02160                     done = TRUE;
02161             }
02162             elementItem = (void *)LST_Next(&groupItem->elementList);
02163         }
02164         groupItem = (void *)LST_Next(&((*object)->groupList));
02165     }
02166     return DCM_NORMAL;
02167 }
02168 
02169 /* DCM_ImportStream
02170 **
02171 ** Purpose:
02172 **      Import data from memory in DCM stream format and create
02173 **      an internal memory representation of the object.
02174 **
02175 ** Parameter Dictionary:
02176 **      buf             Pointer to caller's buffer containing ACR NEMA data
02177 **      length          Length of input data in bytes
02178 **      opt             Bitmask giving options for interpreting data.
02179 **                      Legal values specify the order of the bytes in the data
02180 **                              ACR_ORDERNATIVE
02181 **                              ACR_ORDERLITTLEENDIAN
02182 **                              ACR_ORDERBIGENDIAN
02183 **      object          Pointer to object created and returned by this function
02184 **
02185 ** Return Values:
02186 **
02187 **      DCM_ELEMENTCREATEFAILED
02188 **      DCM_ELEMENTLENGTHERROR
02189 **      DCM_ELEMENTOUTOFORDER
02190 **      DCM_FILEACCESSERROR
02191 **      DCM_ILLEGALOPTION
02192 **      DCM_ILLEGALSTREAMLENGTH
02193 **      DCM_LISTFAILURE
02194 **      DCM_NORMAL
02195 **      DCM_OBJECTCREATEFAILED
02196 **      DCM_UNEVENELEMENTLENGTH
02197 **
02198 ** Algorithm:
02199 **      call private import stream function which handles recursion
02200 **
02201 */
02202 
02203 CONDITION
02204 DCM_ImportStream(unsigned char *buf, unsigned long length,
02205                  unsigned long opt, DCM_OBJECT ** callerObject)
02206 {
02207 #ifdef DEBUG
02208     if (debug)
02209         (void) fprintf(stderr, "DCM_ImportStream, %ld bytes\n", length);
02210 #endif
02211 
02212     if ((opt & DCM_ORDERMASK) == 0)
02213         return COND_PushCondition(DCM_ILLEGALOPTION,
02214                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
02215                                   "DCM_ImportStream");
02216 
02217     return readFile("", buf, -1, length, 0, 0, opt, callerObject, NULL, NULL,
02218                     NULL, NULL, NULL);
02219 }
02220 
02221 /* DCM_GetObjectSize
02222 **
02223 ** Purpose:
02224 **      Return the size of a DICOM object when it is represented in
02225 **      stream format.
02226 **
02227 ** Parameter Dictionary:
02228 **      object          Pointer to caller's DICOM object
02229 **      returnlength    Pointer to unsigned long variable to hold length of
02230 **                      object
02231 **
02232 ** Return Values:
02233 **
02234 **      DCM_ILLEGALOBJECT
02235 **      DCM_NORMAL
02236 **      DCM_NULLOBJECT
02237 **
02238 ** Algorithm:
02239 **      Description of the algorithm (optional) and any other notes.
02240 */
02241 
02242 CONDITION
02243 DCM_GetObjectSize(DCM_OBJECT ** callerObject, unsigned long *returnlength)
02244 {
02245     PRIVATE_OBJECT
02246         ** object;
02247     CONDITION
02248         cond;
02249 
02250     object = (PRIVATE_OBJECT **) callerObject;
02251     cond = checkObject(object, "DCM_GetObjectSize");
02252     if (cond != DCM_NORMAL)
02253         return cond;
02254 
02255     *returnlength = (*object)->objectSize;
02256     return DCM_NORMAL;
02257 }
02258 
02259 /* DCM_DumpElements
02260 **
02261 ** Purpose:
02262 **      Dump a short description of each data element in an object to
02263 **      stdout (for use as a debugging tool).
02264 **
02265 ** Parameter Dictionary:
02266 **      object          Pointer to caller's handle for DCM object to be dumped
02267 **      vm              Limit on the value multiplicity for printing
02268 **                      binary data.  Print no more than vm values.
02269 **
02270 ** Return Values:
02271 **
02272 **      DCM_ILLEGALOBJECT
02273 **      DCM_NORMAL
02274 **      DCM_NULLOBJECT
02275 **
02276 ** Algorithm:
02277 **      Check caller's handle to make certain it is a legal DCM object
02278 **      Print object type (COMMAND, DATASET, MESSAGE) and size in bytes
02279 **      For each GROUP in the object linked list
02280 **          For each ELEMENT ITEM in the group linked list
02281 **              print group, element, size, description
02282 **              print some or all of data based on data element representation
02283 **                      (ASCII number, ASCII text, binary)
02284 **          End for
02285 **      End for
02286 */
02287 CONDITION
02288 DCM_DumpElements(DCM_OBJECT ** callerObject, long vm)
02289 {
02290     PRV_GROUP_ITEM
02291         * groupItem;
02292     PRV_ELEMENT_ITEM
02293         * elementItem;
02294     PRIVATE_OBJECT
02295         ** object;
02296     CONDITION
02297         cond;
02298     DCM_SEQUENCE_ITEM
02299         * sq;
02300     char
02301         scratch[128];
02302     int
02303         stringLength;
02304 
02305     object = (PRIVATE_OBJECT **) callerObject;
02306 
02307     cond = checkObject(object, "DCM_DumpElements");
02308     if (cond != DCM_NORMAL)
02309         return cond;
02310 
02311     switch ((*object)->objectType) {
02312     case DCM_OBJECTUNKNOWN:
02313         RWC_printf("Object type: UNKNOWN\n");
02314         break;
02315     case DCM_OBJECTCOMMAND:
02316         RWC_printf("Object type: COMMAND\n");
02317         break;
02318     case DCM_OBJECTIMAGE:
02319         RWC_printf("Object type: IMAGE\n");
02320         break;
02321     case DCM_OBJECTELEMENTLIST:
02322         RWC_printf("Object type: ELEMENT LIST\n");
02323         break;
02324     default:
02325         RWC_printf("Object type: Unknown (error)\n");
02326         break;
02327     }
02328     RWC_printf("Object size: %ld\n", (*object)->objectSize);
02329 
02330     groupItem = (void *)LST_Head(&(*object)->groupList);
02331     if (groupItem != NULL)
02332         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
02333 
02334     while (groupItem != NULL) {
02335 #ifdef MACOS
02336         RWC_printf("Group: %04x, Length: %8ld\n", groupItem->group,
02337                groupItem->baseLength);
02338 #else
02339         RWC_printf("Group: %04x, Length: %8d\n", groupItem->group,
02340                groupItem->baseLength);
02341 #endif
02342         elementItem = (void *)LST_Head(&groupItem->elementList);
02343         if (elementItem != NULL)
02344             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02345         while (elementItem != NULL) {
02346 #ifdef MACOS
02347             (void) RWC_printf("%04x %04x %8ld [%-8lu] ",
02348                           DCM_TAG_GROUP(elementItem->element.tag),
02349                           DCM_TAG_ELEMENT(elementItem->element.tag),
02350                           elementItem->element.length ,
02351                           (unsigned long) elementItem->element.data_offset );
02352 #else
02353             (void) RWC_printf("%04x %04x %8d [%-8lu] ",
02354                           DCM_TAG_GROUP(elementItem->element.tag),
02355                           DCM_TAG_ELEMENT(elementItem->element.tag),
02356                           elementItem->element.length ,
02357                           (unsigned long) elementItem->element.data_offset );
02358 #endif
02359 
02360             if( (rwc_opt & RWC_NONAME_MASK) == 0 )
02361               (void) RWC_printf("//%31s//", elementItem->element.description);
02362             else
02363               (void) RWC_printf("//") ;
02364 
02365             if (elementItem->element.d.ot == NULL)
02366                 (void) RWC_printf("Data on disk\n");
02367             else {
02368                 switch (elementItem->element.representation) {
02369                 case DCM_AE:
02370                 case DCM_AS:
02371                 case DCM_CS:
02372                 case DCM_DA:
02373                 case DCM_DT:
02374                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02375                     strncpy(scratch, elementItem->element.d.string, stringLength);
02376                     scratch[stringLength] = '\0';
02377                     (void) RWC_printf("%s\n", scratch);
02378                     break;
02379                 case DCM_DD:
02380                 case DCM_FD:
02381                 case DCM_FL:
02382                     (void) RWC_printf("Unimplemented\n");
02383                     break;
02384                 case DCM_DS:
02385                 case DCM_IS:
02386                 case DCM_LO:
02387                 case DCM_LT:
02388                 case DCM_PN:
02389                 case DCM_SH:
02390                 case DCM_UT:
02391                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02392                     strncpy(scratch, elementItem->element.d.string, stringLength);
02393                     scratch[stringLength] = '\0';
02394                     (void) RWC_printf("%s\n", scratch);
02395                     break;
02396                 case DCM_SL:
02397 #ifdef MACOS
02398                     (void) RWC_printf("%8lx %ld\n", *elementItem->element.d.sl,
02399                                   *elementItem->element.d.sl);
02400 #else
02401                     if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02402                       (void) RWC_printf("%8x %d\n", *elementItem->element.d.sl,
02403                                         *elementItem->element.d.sl);
02404                     else
02405                       (void) RWC_printf(" %d\n", *elementItem->element.d.sl ) ;
02406 
02407                     if (vm > 1)
02408                         dumpBinaryData(elementItem->element.d.ot,
02409                                        elementItem->element.representation,
02410                              elementItem->element.length / sizeof(U32), vm);
02411 #endif
02412                     break;
02413                 case DCM_SS:
02414                     if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02415                       (void) RWC_printf("%4x %d\n", *elementItem->element.d.ss,
02416                                     *elementItem->element.d.ss);
02417                     else
02418                       (void) RWC_printf(" %d\n", *elementItem->element.d.ss ) ;
02419 
02420                     if (vm > 1)
02421                         dumpBinaryData(elementItem->element.d.ot,
02422                                        elementItem->element.representation,
02423                            elementItem->element.length / sizeof(short), vm);
02424                     break;
02425                 case DCM_SQ:
02426                     (void) RWC_printf("SEQUENCE\n");
02427                     sq = (void *)LST_Head(&elementItem->element.d.sq);
02428                     if (sq != NULL)
02429                         (void) LST_Position(&elementItem->element.d.sq, (void *)sq);
02430                     RWC_printf("DCM Dump SEQUENCE\n");
02431                     while (sq != NULL) {
02432                         (void) DCM_DumpElements(&sq->object, vm);
02433                         sq = (void *)LST_Next(&elementItem->element.d.sq);
02434                     }
02435                     RWC_printf("DCM Dump SEQUENCE Complete\n");
02436                     break;
02437                 case DCM_ST:
02438                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02439                     strncpy(scratch, elementItem->element.d.string, stringLength);
02440                     scratch[stringLength] = '\0';
02441                     (void) RWC_printf("%s\n", scratch);
02442                     break;
02443                 case DCM_TM:
02444                 case DCM_UI:
02445                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02446                     strncpy(scratch, elementItem->element.d.string, stringLength);
02447                     scratch[stringLength] = '\0';
02448                     (void) RWC_printf("%s\n", scratch);
02449                     break;
02450                 case DCM_AT:
02451                 case DCM_UL:
02452 #ifdef MACOS
02453                     (void) RWC_printf("%8lx %ld\n", *elementItem->element.d.ul,
02454                                   *elementItem->element.d.ul);
02455 #else
02456                     if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02457                       (void) RWC_printf("%8x %d\n", *elementItem->element.d.ul,
02458                                     *elementItem->element.d.ul);
02459                     else
02460                       (void) RWC_printf(" %d\n", *elementItem->element.d.ul ) ;
02461 
02462                     if (vm > 1)
02463                         dumpBinaryData(elementItem->element.d.ot,
02464                                        elementItem->element.representation,
02465                              elementItem->element.length / sizeof(U32), vm);
02466 #endif
02467                     break;
02468                 case DCM_US:{
02469                     int nel = elementItem->element.length / sizeof(unsigned short) , rr ;
02470                     for( rr=0 ; rr < nel ; rr++ ){
02471                      if( (rwc_opt & RWC_NOHEX_MASK) == 0 )
02472                        (void) RWC_printf("%4x %d", elementItem->element.d.us[rr],
02473                                                    elementItem->element.d.us[rr]);
02474                      else
02475                        (void) RWC_printf(" %d", elementItem->element.d.us[rr] ) ;
02476                     }
02477                     RWC_printf("\n") ;
02478 
02479                     if (vm > 1)
02480                         dumpBinaryData(elementItem->element.d.ot,
02481                                        elementItem->element.representation,
02482                                        elementItem->element.length / sizeof(unsigned short), vm);
02483                     }
02484                     break;
02485                 case DCM_OB:
02486                 case DCM_UN:
02487                     dumpBinaryData(elementItem->element.d.ot,
02488                                        elementItem->element.representation,
02489                                elementItem->element.length , MAX(rwc_vm,8));
02490                     break;
02491 
02492                 case DCM_OT:
02493                 case DCM_OW:
02494                 /*case DCM_UNKNOWN:*/
02495                 case DCM_RET:
02496                     (void) RWC_printf("Unimplemented\n");
02497                     break;
02498                 default:
02499                     (void) RWC_printf("Some unimplemented logic if here\n");
02500                     break;
02501                 }
02502             }
02503             elementItem = (void *)LST_Next(&groupItem->elementList);
02504         }
02505         groupItem = (void *)LST_Next(&(*object)->groupList);
02506     }
02507 
02508     RWC_printf("DCM Dump Elements Complete\n");
02509     return DCM_NORMAL;
02510 }
02511 
02512 CONDITION
02513 DCM_FormatElements(DCM_OBJECT ** callerObject, long vm, const char* prefix)
02514 {
02515     PRV_GROUP_ITEM
02516         * groupItem;
02517     PRV_ELEMENT_ITEM
02518         * elementItem;
02519     PRIVATE_OBJECT
02520         ** object;
02521     CONDITION
02522         cond;
02523     DCM_SEQUENCE_ITEM
02524         * sq;
02525     char
02526         scratch[128];
02527     int
02528         stringLength;
02529     char localPrefix[128];
02530 
02531     object = (PRIVATE_OBJECT **) callerObject;
02532 
02533     cond = checkObject(object, "DCM_DumpElements");
02534     if (cond != DCM_NORMAL)
02535         return cond;
02536 
02537     RWC_printf("\n%sDCM Dump Elements\n", prefix);
02538     switch ((*object)->objectType) {
02539     case DCM_OBJECTUNKNOWN:
02540         RWC_printf("%sObject type: UNKNOWN\n", prefix);
02541         break;
02542     case DCM_OBJECTCOMMAND:
02543         RWC_printf("%sObject type: COMMAND\n", prefix);
02544         break;
02545     case DCM_OBJECTIMAGE:
02546         RWC_printf("%sObject type: IMAGE\n", prefix);
02547         break;
02548     case DCM_OBJECTELEMENTLIST:
02549         RWC_printf("%sObject type: ELEMENT LIST\n", prefix);
02550         break;
02551     default:
02552         RWC_printf("%sObject type: Unknown (error)\n", prefix);
02553         break;
02554     }
02555     RWC_printf("%sObject size: %ld\n", prefix, (*object)->objectSize);
02556 
02557     groupItem = (void *)LST_Head(&(*object)->groupList);
02558     if (groupItem != NULL)
02559         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
02560 
02561     while (groupItem != NULL) {
02562         RWC_printf("%sGroup: %04x, Length: %8d\n", prefix, groupItem->group,
02563                groupItem->baseLength);
02564         elementItem = (void *)LST_Head(&groupItem->elementList);
02565         if (elementItem != NULL)
02566             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
02567         while (elementItem != NULL) {
02568             (void) RWC_printf("%s%04x %04x %8d ",
02569                           prefix,
02570                           DCM_TAG_GROUP(elementItem->element.tag),
02571                           DCM_TAG_ELEMENT(elementItem->element.tag),
02572                           elementItem->element.length);
02573             (void) RWC_printf("//%31s//", elementItem->element.description);
02574             if (elementItem->element.d.ot == NULL)
02575                 (void) RWC_printf("Data on disk\n");
02576             else {
02577                 switch (elementItem->element.representation) {
02578                 case DCM_AE:
02579                 case DCM_AS:
02580                 case DCM_CS:
02581                 case DCM_DA:
02582                 case DCM_DT:
02583                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02584                     strncpy(scratch, elementItem->element.d.string, stringLength);
02585                     scratch[stringLength] = '\0';
02586                     (void) RWC_printf("%s\n", scratch);
02587                     break;
02588                 case DCM_DD:
02589                 case DCM_FD:
02590                 case DCM_FL:
02591                     (void) RWC_printf("Unimplemented\n");
02592                     break;
02593                 case DCM_DS:
02594                 case DCM_IS:
02595                 case DCM_LO:
02596                 case DCM_LT:
02597                 case DCM_PN:
02598                 case DCM_SH:
02599                 case DCM_UT:
02600                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02601                     strncpy(scratch, elementItem->element.d.string, stringLength);
02602                     scratch[stringLength] = '\0';
02603                     (void) RWC_printf("%s\n", scratch);
02604                     break;
02605                 case DCM_SL:
02606 #ifdef MACOS
02607                     (void) RWC_printf("%8lx %ld\n", *elementItem->element.d.sl,
02608                                   *elementItem->element.d.sl);
02609 #else
02610                     (void) RWC_printf("%8x %d\n", *elementItem->element.d.sl,
02611                                   *elementItem->element.d.sl);
02612                     if (vm > 1)
02613                         dumpBinaryData(elementItem->element.d.ot,
02614                                        elementItem->element.representation,
02615                              elementItem->element.length / sizeof(U32), vm);
02616 #endif
02617                     break;
02618                 case DCM_SS:
02619                     (void) RWC_printf("%4x %d\n", *elementItem->element.d.ss,
02620                                   *elementItem->element.d.ss);
02621                     if (vm > 1)
02622                         dumpBinaryData(elementItem->element.d.ot,
02623                                        elementItem->element.representation,
02624                            elementItem->element.length / sizeof(short), vm);
02625                     break;
02626                 case DCM_SQ:
02627                     (void) RWC_printf("SEQUENCE\n");
02628                     sq = (void *)LST_Head(&elementItem->element.d.sq);
02629                     if (sq != NULL)
02630                         (void) LST_Position(&elementItem->element.d.sq, (void *)sq);
02631                     RWC_printf("%sDCM Dump SEQUENCE\n", prefix);
02632                     strcpy(localPrefix, prefix);
02633                     strcat(localPrefix, " ");
02634                     while (sq != NULL) {
02635                         (void) DCM_FormatElements(&sq->object, vm, localPrefix);
02636                         sq = (void *)LST_Next(&elementItem->element.d.sq);
02637                     }
02638                     RWC_printf("%sDCM Dump SEQUENCE Complete\n", prefix);
02639                     break;
02640                 case DCM_ST:
02641                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02642                     strncpy(scratch, elementItem->element.d.string, stringLength);
02643                     scratch[stringLength] = '\0';
02644                     (void) RWC_printf("%s\n", scratch);
02645                     break;
02646                 case DCM_TM:
02647                 case DCM_UI:
02648                     stringLength = MIN(sizeof(scratch) - 1, elementItem->element.length);
02649                     strncpy(scratch, elementItem->element.d.string, stringLength);
02650                     scratch[stringLength] = '\0';
02651                     (void) RWC_printf("%s\n", scratch);
02652                     break;
02653                 case DCM_AT:
02654                 case DCM_UL:
02655                     (void) RWC_printf("%8x %d\n", *elementItem->element.d.ul,
02656                                   *elementItem->element.d.ul);
02657                     if (vm > 1)
02658                         dumpBinaryData(elementItem->element.d.ot,
02659                                        elementItem->element.representation,
02660                              elementItem->element.length / sizeof(U32), vm);
02661                     break;
02662                 case DCM_US:
02663                     (void) RWC_printf("%4x %d\n", *elementItem->element.d.us,
02664                                   *elementItem->element.d.us);
02665                     if (vm > 1)
02666                         dumpBinaryData(elementItem->element.d.ot,
02667                                        elementItem->element.representation,
02668                                        elementItem->element.length / sizeof(unsigned short), vm);
02669                     break;
02670                 case DCM_OT:
02671                 case DCM_OW:
02672                 case DCM_OB:
02673                 /*case DCM_UNKNOWN:*/
02674                 case DCM_RET:
02675                     (void) RWC_printf("Unimplemented\n");
02676                     break;
02677                 default:
02678                     (void) RWC_printf("Some unimplemented logic if here\n");
02679                     break;
02680                 }
02681             }
02682             elementItem = (void *)LST_Next(&groupItem->elementList);
02683         }
02684         groupItem = (void *)LST_Next(&(*object)->groupList);
02685     }
02686 
02687     RWC_printf("%sDCM Dump Elements Complete\n\n", prefix);
02688     return DCM_NORMAL;
02689 }
02690 
02691 /* DCM_Debug
02692 **
02693 ** Purpose:
02694 **      To enable the debugging facility
02695 **
02696 ** Parameter Dictionary:
02697 **      flag    CTNBOOLEAN variable TRUE if caller wants to turn on debugging
02698 **              info; FALSE otherwise
02699 **
02700 ** Return Values:
02701 **      None
02702 **
02703 ** Algorithm:
02704 **      Description of the algorithm (optional) and any other notes.
02705 */
02706 
02707 void
02708 DCM_Debug(CTNBOOLEAN flag)
02709 {
02710     debug = flag;
02711 }
02712 
02713 /* DCM_WriteFile
02714 **
02715 ** Purpose:
02716 **      Export an object from the internal representation and
02717 **      write the stream representation to a file.
02718 **
02719 ** Parameter Dictionary:
02720 **      object          DCM_OBJECT which is to be written to the file
02721 **      opt             Bitmask giving options for exporting data.  Legal
02722 **                      options give the byte order of exported data:
02723 **                              DCM_ORDERNATIVE
02724 **                              DCM_ORDERLITTLEENDIAN
02725 **                              DCM_ORDERBIGENDIAN
02726 **      file            ASCIIZ name of the file to be created.
02727 **
02728 ** Return Values:
02729 **
02730 **      DCM_FILEACCESSERROR
02731 **      DCM_FILECREATEFAILED
02732 **      DCM_ILLEGALOBJECT
02733 **      DCM_LISTFAILURE
02734 **      DCM_NORMAL
02735 **      DCM_NULLOBJECT
02736 **
02737 ** Algorithm:
02738 **      Description of the algorithm (optional) and any other notes.
02739 */
02740 
02741 CONDITION
02742 DCM_ExportStream(DCM_OBJECT ** callerObject, unsigned long opt,
02743                  void *buffer, unsigned long bufferlength,
02744                  DCM_EXPORT_STREAM_CALLBACK* callback,
02745                  void *ctx) ;
02746 
02747 CONDITION
02748 DCM_WriteFile(DCM_OBJECT ** callerObject, unsigned long opt, const char *file)
02749 {
02750     PRIVATE_OBJECT
02751         ** object;
02752     int
02753         fd;
02754     unsigned char
02755         buf[2048];
02756     CONDITION
02757         cond;
02758 
02759     object = (PRIVATE_OBJECT **) callerObject;
02760     cond = checkObject(object, "DCM_WriteFile");
02761     if (cond != DCM_NORMAL)
02762         return cond;
02763 #ifdef MACOS
02764     fd = open(file, O_WRONLY | O_CREAT | O_TRUNC);
02765 #elif _MSC_VER
02766     fd = _open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
02767                _S_IREAD | _S_IWRITE);
02768 #else
02769     fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
02770 #endif
02771     if (fd < 0) {
02772         return COND_PushCondition(DCM_FILECREATEFAILED,
02773                    DCM_Message(DCM_FILECREATEFAILED), file, strerror(errno),
02774                                   "DCM_WriteFile");
02775     }
02776     cond = DCM_ExportStream(callerObject, opt, buf,
02777                             (unsigned long) sizeof(buf), writeFile, &fd);
02778     if (cond != DCM_NORMAL)
02779         return cond;
02780 
02781     (void) close(fd);
02782     return DCM_NORMAL;
02783 }
02784 
02785 /* DCM_ModifyElements
02786 **
02787 ** Purpose:
02788 **
02789 ** Parameter Dictionary:
02790 **      callerObject            Handle to user's DICOM object to be modified
02791 **      vector                  Mandatory elements that need to be stored
02792 **                              in the object
02793 **      count                   Number of such mandatory elements
02794 **      flaggedVector           Optional elements
02795 **      flaggedCount            Number of such optional elements
02796 **      updateCount             Total number of elements updated (returned to
02797 **                              caller)
02798 **
02799 ** Return Values:
02800 **
02801 **      DCM_ILLEGALOBJECT
02802 **      DCM_ILLEGALREPRESENTATION
02803 **      DCM_INSERTFAILED
02804 **      DCM_NORMAL
02805 **      DCM_NULLOBJECT
02806 **
02807 ** Algorithm:
02808 **      Check caller's object to make certain it is a legal DCM object.
02809 **      Find head of the object linked list.
02810 **      Search linked list sequentially until object is found or end
02811 **      of list reached.
02812 **      If end of list
02813 **              return DCM_ELEMENTNOTFOUND
02814 **      If CTX pointer containts NULL
02815 **          Begin copy from beginning of element
02816 **      else
02817 **          Begin copy from address in CTX pointer
02818 **      Copy data from element data area to user buffer
02819 **      If copy is incomplete (remaining data longer than caller's buffer)
02820 **          Update CTX pointer to point to next uncopied part of data
02821 **          Return DCM_GETINCOMPLETE
02822 **      else
02823 **          Update CTX pointer to point past data area.
02824 **          Return DCM_NORMAL
02825 */
02826 
02827 CONDITION
02828 DCM_ModifyElements(DCM_OBJECT ** callerObject, DCM_ELEMENT * vector, int count,
02829                    DCM_FLAGGED_ELEMENT * flaggedVector, int flaggedCount,
02830                    int *updateCount)
02831 {
02832     PRIVATE_OBJECT
02833         ** object;
02834     CONDITION
02835         cond;
02836     DCM_ELEMENT
02837         e;
02838     int
02839         c = 0;
02840 
02841     object = (PRIVATE_OBJECT **) callerObject;
02842     cond = checkObject(object, "DCM_ModifyElement");
02843     if (cond != DCM_NORMAL)
02844         return cond;
02845 
02846     while (count-- > 0) {
02847         cond = DCM_RemoveElement(callerObject, vector->tag);
02848         if (cond != DCM_NORMAL)
02849             (void) COND_PopCondition(FALSE);
02850 
02851         e = *vector;
02852         if (DCM_IsString(e.representation))
02853             e.length = strlen(e.d.string);
02854 
02855         cond = DCM_AddElement(callerObject, &e);
02856         if (cond != DCM_NORMAL)
02857             return cond;
02858 
02859         c++;
02860         vector++;
02861     }
02862 
02863     while (flaggedCount-- > 0) {
02864         if ((*(flaggedVector->flagAddress) & flaggedVector->flag) != 0) {
02865             cond = DCM_RemoveElement(callerObject, flaggedVector->e.tag);
02866             if (cond != DCM_NORMAL)
02867                 (void) COND_PopCondition(FALSE);
02868 
02869             e = flaggedVector->e;
02870             if (DCM_IsString(e.representation))
02871                 e.length = strlen(e.d.string);
02872             cond = DCM_AddElement(callerObject, &e);
02873             if (cond != DCM_NORMAL)
02874                 return cond;
02875             c++;
02876         }
02877         flaggedVector++;
02878     }
02879 
02880     if (updateCount != NULL)
02881         *updateCount = c;
02882     return DCM_NORMAL;
02883 }
02884 
02885 
02886 /* DCM_ParseObject
02887 **
02888 ** Purpose:
02889 **      Parse the object and store the mandatory and optional elements in
02890 **      different vectors.
02891 **
02892 ** Parameter Dictionary:
02893 **      callerObject            Handle to user's DICOM object to be modified
02894 **      vector                  Mandatory elements that need to be stored
02895 **                              in the object
02896 **      count                   Number of such mandatory elements
02897 **      flaggedVector           Optional elements
02898 **      flaggedCount            Number of such optional elements
02899 **      parseCount              Total number of elements parsed (returned to
02900 **                              caller)
02901 **
02902 ** Return Values:
02903 **
02904 **      DCM_CANNOTGETSEQUENCEVALUE
02905 **      DCM_ELEMENTNOTFOUND
02906 **      DCM_GETINCOMPLETE
02907 **      DCM_ILLEGALCONTEXT
02908 **      DCM_ILLEGALOBJECT
02909 **      DCM_NORMAL
02910 **      DCM_NULLOBJECT
02911 **
02912 ** Notes:
02913 **
02914 ** Algorithm:
02915 **      Description of the algorithm (optional) and any other notes.
02916 */
02917 CONDITION
02918 DCM_ParseObject(DCM_OBJECT ** callerObject, DCM_ELEMENT * vector,
02919               int count, DCM_FLAGGED_ELEMENT * flaggedVector, int flagCount,
02920                 int *parseCount)
02921 {
02922     PRIVATE_OBJECT
02923         ** object;
02924     CONDITION
02925         cond;
02926     void
02927        *ctx;
02928     U32
02929         l;
02930     int
02931         c = 0;
02932     char
02933        *p;
02934 
02935     object = (PRIVATE_OBJECT **) callerObject;
02936     cond = checkObject(object, "DCM_ParseObject");
02937     if (cond != DCM_NORMAL)
02938         return cond;
02939 
02940     while (count-- > 0) {
02941         ctx = NULL;
02942         cond = DCM_GetElementValue(callerObject, vector, &l, &ctx);
02943         if (cond != DCM_NORMAL)
02944             return cond;
02945         if (DCM_IsString(vector->representation)) {
02946             vector->d.string[l] = '\0';
02947             p = vector->d.string + l - 1;
02948             while (p >= vector->d.string && (*p == ' '))
02949                 *p-- = '\0';
02950         }
02951         c++;
02952         vector++;
02953     }
02954 
02955     while (flagCount-- > 0) {
02956         ctx = NULL;
02957         cond = DCM_GetElementValue(callerObject, &flaggedVector->e, &l, &ctx);
02958         if (cond != DCM_NORMAL) {
02959             (void) COND_PopCondition(FALSE);
02960         } else {
02961             c++;
02962             if (DCM_IsString(flaggedVector->e.representation)) {
02963                 flaggedVector->e.d.string[l] = '\0';
02964                 p = flaggedVector->e.d.string + l - 1;
02965                 while (p >= flaggedVector->e.d.string && (*p == ' '))
02966                     *p-- = '\0';
02967             }
02968             *(flaggedVector->flagAddress) |= flaggedVector->flag;
02969         }
02970         flaggedVector++;
02971     }
02972 
02973     if (parseCount != NULL)
02974         *parseCount = c;
02975     return DCM_NORMAL;
02976 }
02977 
02978 
02979 /* DCM_RemoveGroup
02980 **
02981 ** Purpose:
02982 **      Remove an element with the given group number from the object
02983 **
02984 ** Parameter Dictionary:
02985 **      callerObject            Handle to caller's object
02986 **      group                   Group number of the element to be removed.
02987 **
02988 ** Return Values:
02989 **
02990 **      DCM_GROUPNOTFOUND
02991 **      DCM_ILLEGALOBJECT
02992 **      DCM_LISTFAILURE
02993 **      DCM_NORMAL
02994 **      DCM_NULLOBJECT
02995 **
02996 ** Notes:
02997 **
02998 ** Algorithm:
02999 **      Description of the algorithm (optional) and any other notes.
03000 */
03001 
03002 CONDITION
03003 DCM_RemoveGroup(DCM_OBJECT ** callerObject, unsigned short group)
03004 {
03005     PRIVATE_OBJECT
03006         ** object;
03007     CONDITION
03008         cond;
03009     PRV_GROUP_ITEM
03010         * groupItem;
03011     PRV_ELEMENT_ITEM
03012         * elementItem;
03013     CTNBOOLEAN
03014         found = FALSE;
03015 
03016     object = (PRIVATE_OBJECT **) callerObject;
03017     cond = checkObject(object, "DCM_RemoveGroup");
03018     if (cond != DCM_NORMAL)
03019         return cond;
03020 
03021     groupItem = (void *)LST_Head(&(*object)->groupList);
03022     if (groupItem == NULL)
03023         return COND_PushCondition(DCM_GROUPNOTFOUND,
03024             DCM_Message(DCM_GROUPNOTFOUND), (int) group, "DCM_RemoveGroup");
03025 
03026     (void) LST_Position(&(*object)->groupList, (void *)groupItem);
03027 
03028     while (!found && (groupItem != NULL)) {
03029         if (groupItem->group == group)
03030             found = TRUE;
03031         else
03032             groupItem = (void *)LST_Next(&(*object)->groupList);
03033     }
03034     if (groupItem == NULL)
03035         return COND_PushCondition(DCM_GROUPNOTFOUND,
03036             DCM_Message(DCM_GROUPNOTFOUND), (int) group, "DCM_RemoveGroup");
03037 
03038 
03039     while ((elementItem = (void *)LST_Pop(&groupItem->elementList)) != NULL)
03040         CTN_FREE(elementItem);
03041 
03042     groupItem = (void *)LST_Remove(&(*object)->groupList, LST_K_AFTER);
03043     cond = LST_Destroy(&groupItem->elementList);
03044     if (cond != LST_NORMAL)
03045         return COND_PushCondition(DCM_LISTFAILURE,
03046                            DCM_Message(DCM_LISTFAILURE), "DCM_RemoveGroup");
03047     CTN_FREE(groupItem);
03048     return DCM_NORMAL;
03049 }
03050 
03051 /* DCM_GetSequenceList
03052 **
03053 ** Purpose:
03054 **      Obtain the sequence list from the DICOM object corresponding to the
03055 **      tag value.
03056 **
03057 ** Parameter Dictionary:
03058 **      object          Handle to the DICOM object
03059 **      tag             Tag number of the sequence list element to be obtained
03060 **                      from the DICOM object
03061 **      list            Holds the sequence list. Returned to the caller.
03062 **
03063 ** Return Values:
03064 **
03065 **      DCM_ELEMENTNOTFOUND
03066 **      DCM_ILLEGALOBJECT
03067 **      DCM_NORMAL
03068 **      DCM_NULLOBJECT
03069 **
03070 ** Notes:
03071 **
03072 ** Algorithm:
03073 **      Description of the algorithm (optional) and any other notes.
03074 */
03075 
03076 CONDITION
03077 DCM_GetSequenceList(DCM_OBJECT ** object, DCM_TAG tag, LST_HEAD ** list)
03078 {
03079     PRIVATE_OBJECT
03080         ** obj;
03081     CONDITION
03082         cond;
03083     PRV_GROUP_ITEM
03084         * groupItem;
03085     PRV_ELEMENT_ITEM
03086         * elementItem;
03087     CTNBOOLEAN
03088         found = FALSE;
03089 
03090     obj = (PRIVATE_OBJECT **) object;
03091     cond = checkObject(obj, "DCM_GetSequenceList");
03092     if (cond != DCM_NORMAL)
03093         return cond;
03094 
03095     groupItem = (void *)LST_Head(&(*obj)->groupList);
03096     if (groupItem == NULL)
03097         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03098                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03099                                   DCM_TAG_ELEMENT(tag),
03100                                   "DCM_GetSequenceList");
03101 
03102     (void) LST_Position(&(*obj)->groupList, (void *)groupItem);
03103     while (groupItem != NULL) {
03104         if (groupItem->group == DCM_TAG_GROUP(tag))
03105             break;
03106 
03107         groupItem = (void *)LST_Next(&(*obj)->groupList);
03108     }
03109     if (groupItem == NULL)
03110         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03111                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03112                                   DCM_TAG_ELEMENT(tag),
03113                                   "DCM_GetSequenceList");
03114 
03115     elementItem = (void *)LST_Head(&groupItem->elementList);
03116     if (elementItem == NULL)
03117         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03118                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03119                                   DCM_TAG_GROUP(tag),
03120                                   "DCM_GetSequenceTag");
03121 
03122     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
03123     while (!found && (elementItem != NULL)) {
03124         if (elementItem->element.tag == tag) {
03125             *list = elementItem->element.d.sq;
03126             found = TRUE;
03127         }
03128         elementItem = (void *)LST_Next(&groupItem->elementList);
03129     }
03130     if (found)
03131         return DCM_NORMAL;
03132     else
03133         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03134                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03135                                   DCM_TAG_ELEMENT(tag),
03136                                   "DCM_GetSequenceList");
03137 }
03138 
03139 CONDITION
03140 DCM_GetSequenceElement(DCM_OBJECT ** object, DCM_TAG top, DCM_ELEMENT * e)
03141 {
03142     PRIVATE_OBJECT **obj;
03143     CONDITION cond;
03144     PRV_GROUP_ITEM *groupItem;
03145     PRV_ELEMENT_ITEM *elementItem;
03146     DCM_SEQUENCE_ITEM *seqItem;
03147 
03148     CTNBOOLEAN found = FALSE;
03149 
03150     obj = (PRIVATE_OBJECT **) object;
03151     cond = checkObject(obj, "DCM_GetSequenceElement");
03152     if (cond != DCM_NORMAL)
03153         return cond;
03154 
03155     elementItem = locateElement(obj, top);
03156     if (elementItem == NULL) {
03157         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03158                                   DCM_Message(DCM_ELEMENTNOTFOUND),
03159                                   DCM_TAG_GROUP(top),
03160                                   DCM_TAG_ELEMENT(top),
03161                                   "DCM_GetElementSequence");
03162     }
03163     if (elementItem->element.representation != DCM_SQ) {
03164         return COND_PushCondition(DCM_UNEXPECTEDREPRESENTATION,
03165                                   DCM_Message(DCM_UNEXPECTEDREPRESENTATION),
03166                                   "DCM_GetSequenceElement", "sequence");
03167     }
03168     seqItem = (void *)LST_Head(&elementItem->element.d.sq);
03169     cond = DCM_ParseObject(&seqItem->object, e, 1, NULL, 0, NULL);
03170     return cond;
03171 
03172 #if 0
03173     return DCM_NORMAL;
03174 #endif
03175 }
03176 
03177 /* DCM_GetElementValueList
03178 **
03179 ** Purpose:
03180 **
03181 ** Parameter Dictionary:
03182 **      Define the parameters to the function
03183 **
03184 ** Return Values:
03185 **
03186 **      DCM_ELEMENTNOTFOUND
03187 **      DCM_ILLEGALOBJECT
03188 **      DCM_LISTFAILURE
03189 **      DCM_MALLOCFAILURE
03190 **      DCM_NORMAL
03191 **      DCM_NULLOBJECT
03192 **
03193 ** Notes:
03194 **
03195 ** Algorithm:
03196 **      Description of the algorithm (optional) and any other notes.
03197 */
03198 CONDITION
03199 DCM_GetElementValueList(DCM_OBJECT ** object, DCM_TAG tag,
03200                   size_t structureSize, long stringOffset, LST_HEAD ** list)
03201 {
03202     PRIVATE_OBJECT
03203         ** obj;
03204     CONDITION
03205         cond;
03206     PRV_GROUP_ITEM
03207         * groupItem;
03208     PRV_ELEMENT_ITEM
03209         * elementItem;
03210     CTNBOOLEAN
03211         found = FALSE;
03212     char
03213        *src,
03214        *dst,
03215        *p;
03216     U32
03217         l;
03218 
03219     obj = (PRIVATE_OBJECT **) object;
03220     cond = checkObject(obj, "DCM_GetSequenceList");
03221     if (cond != DCM_NORMAL)
03222         return cond;
03223 
03224     groupItem = (void *)LST_Head(&(*obj)->groupList);
03225     if (groupItem == NULL)
03226         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03227                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03228                                   DCM_TAG_ELEMENT(tag),
03229                                   "DCM_GetSequenceList");
03230 
03231     (void) LST_Position(&(*obj)->groupList, (void *)groupItem);
03232     while (groupItem != NULL) {
03233         if (groupItem->group == DCM_TAG_GROUP(tag))
03234             break;
03235 
03236         groupItem = (void *)LST_Next(&(*obj)->groupList);
03237     }
03238     if (groupItem == NULL)
03239         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03240                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03241                                   DCM_TAG_ELEMENT(tag),
03242                                   "DCM_GetSequenceList");
03243 
03244     elementItem = (void *)LST_Head(&groupItem->elementList);
03245     if (elementItem == NULL)
03246         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03247                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03248                                   DCM_TAG_GROUP(tag),
03249                                   "DCM_GetSequenceTag");
03250 
03251     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
03252     while (!found && (elementItem != NULL)) {
03253         if (elementItem->element.tag == tag) {
03254             found = TRUE;
03255         } else
03256             elementItem = (void *)LST_Next(&groupItem->elementList);
03257     }
03258     if (!found)
03259         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03260                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03261                                   DCM_TAG_ELEMENT(tag),
03262                                   "DCM_GetElementValueList");
03263 
03264     if (!DCM_IsString(elementItem->element.representation)) {
03265         return COND_PushCondition(DCM_UNEXPECTEDREPRESENTATION,
03266         DCM_Message(DCM_UNEXPECTEDREPRESENTATION), "DCM_GetElementValueList",
03267                                   "string");
03268     }
03269     src = elementItem->element.d.string;
03270     l = elementItem->element.length;
03271     while (l > 0) {
03272         while (l > 1 && (*src == ' ' || *src == DCM_DELIMITOR)) {
03273             l--;
03274             src++;
03275         }
03276         if ((l == 1) && (*src == ' ' || *src == DCM_DELIMITOR))
03277             l--;
03278 
03279         if (l != 0) {
03280             p = CTN_MALLOC(structureSize);
03281             if (p == NULL)
03282                 return COND_PushCondition(DCM_MALLOCFAILURE,
03283                               DCM_Message(DCM_MALLOCFAILURE), structureSize,
03284                                           "DCM_GetElementValueList");
03285             dst = p + stringOffset;
03286             while ((l > 1) && (*src != DCM_DELIMITOR)) {
03287                 *dst++ = *src++;
03288                 l--;
03289             }
03290             if ((l == 1) && (*src != ' ')) {
03291                 *dst++ = *src++;
03292                 l--;
03293             }
03294             *dst = '\0';;
03295             cond = LST_Enqueue(list, (void *)p);
03296             if (cond != LST_NORMAL)
03297                 return COND_PushCondition(DCM_LISTFAILURE,
03298                    DCM_Message(DCM_LISTFAILURE), "DCM_GetElementValueList");
03299         }
03300     }
03301     return DCM_NORMAL;
03302 }
03303 
03304 /* DCM_AddElementList
03305 **
03306 ** Purpose:
03307 **      Add an element list to the DICOM object
03308 **
03309 ** Parameter Dictionary:
03310 **      callerObject            Handle to object to which the element is to be
03311 **                              added
03312 **      element                 The element in which the string obtained from
03313 **                              the list is to be stored. Finally the element
03314 **                              is added to the DICOM object.
03315 **      list                    List of structures , each containing a string
03316 **                              starting at some offset specified by the
03317 **                              parameter "offset"
03318 **      offset                  Offset in each individual structure (see
03319 **                              explanation for parameter list)
03320 **
03321 ** Return Values:
03322 **
03323 **      DCM_ILLEGALOBJECT
03324 **      DCM_ILLEGALREPRESENTATION
03325 **      DCM_INSERTFAILED
03326 **      DCM_NORMAL
03327 **      DCM_NULLOBJECT
03328 **
03329 ** Notes:
03330 **
03331 ** Algorithm:
03332 **      Description of the algorithm (optional) and any other notes.
03333 */
03334 CONDITION
03335 DCM_AddElementList(DCM_OBJECT ** callerObject, DCM_ELEMENT * element,
03336                    LST_HEAD * list, long offset)
03337 {
03338     DCM_ELEMENT
03339         e;                      /* Local copy of caller's element */
03340     CONDITION
03341         cond;
03342     char
03343        *s;
03344 
03345     e = *element;
03346     cond = DCM_ListToString(list, offset, &s);
03347     if (cond != DCM_NORMAL)
03348         return cond;
03349 
03350     e.d.string = s;
03351     e.length = strlen(s);
03352     cond = DCM_AddElement(callerObject, &e);
03353     CTN_FREE(s);
03354     return cond;
03355 }
03356 
03357 /* DCM_GetElement
03358 **
03359 ** Purpose:
03360 **      Get the element with the specified tag number from the given DICOM
03361 **      object
03362 **
03363 ** Parameter Dictionary:
03364 **      callerObject            Handle to the DICOM object
03365 **      tag                     Tag number of the element to be obtained
03366 **                              from the object
03367 **      element                 The element to be returned
03368 **
03369 ** Return Values:
03370 **
03371 **      DCM_ELEMENTNOTFOUND
03372 **      DCM_ILLEGALOBJECT
03373 **      DCM_NORMAL
03374 **      DCM_NULLOBJECT
03375 **
03376 ** Notes:
03377 **
03378 ** Algorithm:
03379 **      Description of the algorithm (optional) and any other notes.
03380 */
03381 CONDITION
03382 DCM_GetElement(DCM_OBJECT ** callerObject, DCM_TAG tag, DCM_ELEMENT * element)
03383 {
03384     PRIVATE_OBJECT
03385         ** obj;
03386     CONDITION
03387         cond;
03388     PRV_ELEMENT_ITEM
03389         * elementItem;
03390 
03391     obj = (PRIVATE_OBJECT **) callerObject;
03392     cond = checkObject(obj, "DCM_GetElementVM");
03393     if (cond != DCM_NORMAL)
03394         return cond;
03395 
03396     elementItem = locateElement(obj, tag);
03397     if (elementItem == NULL)
03398         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
03399                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
03400                                   DCM_TAG_ELEMENT(tag),
03401                                   "DCM_GetElementVM");
03402     *element = elementItem->element;
03403     element->d.ot = NULL;
03404     return DCM_NORMAL;
03405 }
03406 
03407 CONDITION
03408 DCM_ComputeExportLength(DCM_OBJECT ** callerObject, unsigned long opt,
03409                         unsigned long *length)
03410 {
03411     PRIVATE_OBJECT
03412         ** object;
03413     unsigned char
03414         buf[2048];
03415     CONDITION
03416         cond;
03417 
03418     object = (PRIVATE_OBJECT **) callerObject;
03419     cond = checkObject(object, "DCM_ComputeExportSize");
03420     if (cond != DCM_NORMAL)
03421         return cond;
03422 
03423     *length = 0;
03424     cond = DCM_ExportStream(callerObject, opt, buf,
03425                             (unsigned long) sizeof(buf), countBytes, length);
03426     if (cond != DCM_NORMAL)
03427         return cond;
03428 
03429     return DCM_NORMAL;
03430 }
03431 
03432 CONDITION
03433 DCM_CompareAttributes(DCM_OBJECT ** o1, DCM_OBJECT ** o2,
03434                       void (*callback) (const DCM_ELEMENT * e1,
03435                                         const DCM_ELEMENT * e2,
03436                                         void *ctx),
03437                       void *ctx)
03438 {
03439     PRIVATE_OBJECT **object1,
03440       **object2;
03441     PRV_GROUP_ITEM *groupItem1,
03442        *groupItem2;
03443     CONDITION cond;
03444 
03445     object1 = (PRIVATE_OBJECT **) o1;
03446     cond = checkObject(object1, "DCM_CompareAttributes");
03447     if (cond != DCM_NORMAL)
03448         return cond;
03449 
03450     object2 = (PRIVATE_OBJECT **) o2;
03451     cond = checkObject(object1, "DCM_CompareAttributes");
03452     if (cond != DCM_NORMAL)
03453         return cond;
03454 
03455     groupItem1 = (void *)LST_Head(&(*object1)->groupList);
03456     if (groupItem1 != NULL)
03457         (void) LST_Position(&(*object1)->groupList, (void *)groupItem1);
03458 
03459     groupItem2 = (void *)LST_Head(&(*object2)->groupList);
03460     if (groupItem2 != NULL)
03461         (void) LST_Position(&(*object2)->groupList, (void *)groupItem2);
03462 
03463 
03464     while (groupItem1 != NULL) {
03465         if (groupItem2 == NULL) {
03466             compareGroup(groupItem1, NULL, callback, ctx);
03467             groupItem1 = (void *)LST_Next(&(*object1)->groupList);
03468         } else if (groupItem1->group == groupItem2->group) {
03469             compareGroup(groupItem1, groupItem2, callback, ctx);
03470             groupItem1 = (void *)LST_Next(&(*object1)->groupList);
03471             groupItem2 = (void *)LST_Next(&(*object2)->groupList);
03472         } else if (groupItem1->group > groupItem2->group) {
03473             compareGroup(NULL, groupItem2, callback, ctx);
03474             groupItem2 = (void *)LST_Next(&(*object2)->groupList);
03475         } else {
03476             compareGroup(groupItem1, NULL, callback, ctx);
03477             groupItem1 = (void *)LST_Next(&(*object1)->groupList);
03478         }
03479     }
03480 
03481     while (groupItem2 != NULL) {
03482         compareGroup(NULL, groupItem2, callback, ctx);
03483         groupItem2 = (void *)LST_Next(&(*object2)->groupList);
03484     }
03485     return DCM_NORMAL;
03486 }
03487 
03488 CTNBOOLEAN
03489 DCM_GroupPresent(DCM_OBJECT ** o1, U16 group)
03490 {
03491     PRIVATE_OBJECT **object;
03492     PRV_GROUP_ITEM * item;
03493     CONDITION cond;
03494     CTNBOOLEAN tooFar = FALSE;
03495 
03496     object = (PRIVATE_OBJECT **) o1;
03497     cond = checkObject(object, "DCM_CompareAttributes");
03498     if (cond != DCM_NORMAL)
03499         return FALSE;
03500 
03501 
03502     item = (void *)LST_Head(&(*object)->groupList);
03503     if (item != NULL)
03504         (void) LST_Position(&(*object)->groupList, (void *)item);
03505 
03506     while (item != NULL && !tooFar) {
03507         if (item->group == group) {
03508             return TRUE;
03509         } else if (item->group > group) {
03510             tooFar = TRUE;
03511         } else {
03512             item = (void *)LST_Next(&(*object)->groupList);
03513         }
03514     }
03515     return FALSE;
03516 }
03517 
03518 /*     ------------------------------------------------------------
03519 **  Private functions below here
03520 */
03521 
03522 /* newElementItem
03523 **
03524 ** Purpose:
03525 **      Create a new element item suitable for placing in the linked
03526 **      list representation of an ACR object.  Copy data from an
03527 **      existing element, but skip the actual data field.
03528 **      Describe the purpose of the function
03529 **
03530 ** Parameter Dictionary:
03531 **      src     Pointer to source element that is to be copied
03532 **      dst     Pointer to pointer to destination element which is allocated
03533 **              by this routine and filled in appropriately.
03534 **
03535 ** Return Values:
03536 **      DCM_NORMAL
03537 **      DCM_ELEMENTCREATEFAILED
03538 **
03539 ** Algorithm:
03540 **      Allocate new element item of size:
03541 **              Size PRV_ELEMENT_ITEM + length of data value
03542 **      Copy data from caller's DCM_ELEMENT into newly created
03543 **              PRV_ELEMENT_ITEM.
03544 **      Point data value of newly created PRV_ELEMENT_ITEM to part of the
03545 **      allocated space (just past the end of the PRV_ELEMENT_ITEM).
03546 */
03547 static CONDITION
03548 newElementItem(DCM_ELEMENT * src, CTNBOOLEAN allocateData,
03549                PRV_ELEMENT_ITEM ** dst)
03550 {
03551     U32
03552     l;
03553 
03554     if (allocateData && (src->representation != DCM_SQ)) {
03555         l = src->length;
03556         if (l & 1)
03557             l++;
03558     } else
03559         l = 0;
03560 
03561     if (debug)
03562         fprintf(stderr, "newElementItem: CTN_MALLOC %8d %8d ", l,
03563                 (int)(sizeof(PRV_ELEMENT_ITEM) + l));
03564 
03565     *dst = (PRV_ELEMENT_ITEM *) CTN_MALLOC(sizeof(PRV_ELEMENT_ITEM) + l);
03566     if (debug)
03567         fprintf(stderr, "%8p\n", *dst);
03568 
03569     if (*dst == NULL) {
03570         return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
03571                      DCM_Message(DCM_ELEMENTCREATEFAILED), "newElementItem",
03572                                   DCM_TAG_GROUP(src->tag),
03573                                   DCM_TAG_ELEMENT(src->tag),
03574                                   l);
03575     }
03576     memset(*dst, 0, sizeof(PRV_ELEMENT_ITEM));
03577     (*dst)->element = *src;
03578     (*dst)->byteOrder = NATIVE_ORDER;
03579     (*dst)->allocatedDataLength = (size_t) l;
03580     (*dst)->originalDataLength = src->length;
03581     (*dst)->paddedDataLength = src->length;
03582     if (allocateData)
03583         (*dst)->element.d.ot = ((char *) (*dst)) + sizeof(PRV_ELEMENT_ITEM);
03584     else
03585         (*dst)->element.d.ot = NULL;
03586 
03587     (*dst)->fragmentFlag = 0;
03588     return DCM_NORMAL;
03589 }
03590 
03591 /* findCreateGroup
03592 **
03593 ** Purpose:
03594 **      Find the group in the DCM object corresponding to the group
03595 **      passed by the caller.  If the group does not yet exist, create
03596 **      a new group.  Set the CURRENT pointer in the linked list
03597 **      to point at that group.
03598 **
03599 ** Parameter Dictionary:
03600 **      object          Pointer to caller's DCM object
03601 **      group           Group number to locate/create
03602 **      groupPtr        Mechanism for returning pointer to located group
03603 **
03604 ** Return Values:
03605 **
03606 **      DCM_ELEMENTCREATEFAILED
03607 **      DCM_LISTFAILURE
03608 **      DCM_NORMAL
03609 **
03610 ** Algorithm:
03611 **      Set ITEM to head of linked list of ACR object
03612 **      Set CURRENT item in linked list to ITEM
03613 **      Search sequentially through linked list until:
03614 **          - Reach exisiting group that matches caller's group
03615 **          - Reach a group with larger group number than caller's group
03616 **          - Reach end of linked list
03617 **      Each time you move to a new item, update CURRENT to point to that item
03618 **      If reached existing group
03619 **          return
03620 **      If reached a group with larger group number than caller's group,
03621 **          Insert new group with Group Length Element (0000) just before
03622 **          the group with the larger group number.
03623 **          Set CURRENT pointer in linked list to point at new group
03624 **          If group is COMMAND or IDENTIFYING,
03625 **              Insert Length to End Element
03626 **          Return
03627 **      If reached end of the linked list
03628 **          Append new group with Group Length Element (0000) to the end
03629 **          of the linked list.
03630 **          Set CURRENT pointer in linked list to point at new group
03631 **          If group is COMMAND or IDENTIFYING,
03632 **              Insert Length to End Element
03633 **          Return
03634 **
03635 */
03636 
03637 static CONDITION
03638 findCreateGroup(PRIVATE_OBJECT ** object, unsigned short group,
03639                 PRV_GROUP_ITEM ** groupItem)
03640 {
03641     PRV_GROUP_ITEM
03642     * item;
03643     CONDITION
03644         cond;
03645     CTNBOOLEAN
03646         tooFar = FALSE;
03647 
03648     item = (void *)LST_Head(&(*object)->groupList);
03649     if (item != NULL)
03650         (void) LST_Position(&(*object)->groupList, (void *)item);
03651 
03652     while (item != NULL && !tooFar) {
03653         if (item->group == group) {
03654             *groupItem = item;
03655             return DCM_NORMAL;
03656         } else if (item->group > group) {
03657             tooFar = TRUE;
03658         } else {
03659             item = (void *)LST_Next(&(*object)->groupList);
03660         }
03661     }
03662 
03663     {
03664         U32 l;
03665         PRV_GROUP_ITEM *newGroupItem;
03666         DCM_ELEMENT groupLength = {0, DCM_UL, "", 1, sizeof(l), NULL};
03667         PRV_ELEMENT_ITEM *groupLengthItem;
03668 
03669         newGroupItem = CTN_MALLOC(sizeof(*newGroupItem));
03670         if (newGroupItem == NULL)
03671             return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
03672                                       DCM_Message(DCM_ELEMENTCREATEFAILED),
03673                                       "findCreateGroup",
03674                                       group, 0xffff, sizeof(*newGroupItem));
03675 
03676 
03677         *groupItem = newGroupItem;
03678         newGroupItem->group = group;
03679         newGroupItem->baseLength = 0;
03680         newGroupItem->longVRAttributes = 0;
03681         newGroupItem->elementList = LST_Create();
03682         if (newGroupItem->elementList == NULL)
03683             return COND_PushCondition(DCM_LISTFAILURE,
03684                                       DCM_Message(DCM_LISTFAILURE),
03685                                       "findCreateGroup");
03686 
03687         if (tooFar)
03688             cond = LST_Insert(&(*object)->groupList, (void *)newGroupItem, LST_K_BEFORE);
03689         else
03690             cond = LST_Enqueue(&(*object)->groupList, (void *)newGroupItem);
03691         if (cond != LST_NORMAL)
03692             return COND_PushCondition(DCM_LISTFAILURE,
03693                                       DCM_Message(DCM_LISTFAILURE),
03694                                       "findCreateGroup");
03695         (void) LST_Position(&(*object)->groupList, (void *)newGroupItem);
03696         if (cond != LST_NORMAL)
03697             return COND_PushCondition(DCM_LISTFAILURE,
03698                                       DCM_Message(DCM_LISTFAILURE),
03699                                       "findCreateGroup");
03700 
03701         groupLength.d.ul = &l;
03702         l = 0;
03703         if ((*object)->groupLengthFlag) {
03704             groupLength.tag = DCM_MAKETAG(group, 0);
03705             cond = newElementItem(&groupLength, TRUE, &groupLengthItem);
03706             (void) memcpy(groupLengthItem->element.d.ot, &l, sizeof(l));
03707 
03708             if (LST_Insert(&newGroupItem->elementList, (void *)groupLengthItem, LST_K_AFTER) !=
03709                 LST_NORMAL)
03710                 return COND_PushCondition(DCM_LISTFAILURE,
03711                                           DCM_Message(DCM_LISTFAILURE),
03712                                           "findCreateGroup");
03713 
03714             (*object)->objectSize += 8 + groupLengthItem->element.length;
03715         }
03716     }
03717     return DCM_NORMAL;
03718 }
03719 
03720 /* insertNewElement
03721 **
03722 ** Purpose:
03723 **      Create a new DCM_ELEMENT item using a copy of the caller's
03724 **      DCM_ELEMENT and insert it into the ACR object's linked list.
03725 **
03726 ** Parameter Dictionary:
03727 **      object          Pointer to caller's ACR_OBJECT
03728 **      element         Pointer to caller's ACR_ELEMENT to be copied
03729 **                      and inserted into linked list.
03730 **
03731 ** Return Values:
03732 **
03733 **      DCM_ELEMENTCREATEFAILED
03734 **      DCM_LISTFAILURE
03735 **      DCM_NORMAL
03736 **      DCM_UNEVENELEMENTLENGTH
03737 **      DCM_BADELEMENTINGROUP
03738 **
03739 ** Algorithm:
03740 **      Call newElementItem to create a copy of the DCM_ELEMENT
03741 **      Copy caller's data into data area allocated by newElementItem
03742 **      Increment object's OBJECTSIZE field by size of new element
03743 **      Use CURRENT pointer in DCM object linked list to get pointer
03744 **      to the group where we insert this element
03745 **      Update Group Length by adding size of new element
03746 **      Search sequentially through linked list until we reach:
03747 **          - End of linked list
03748 **          - A different group
03749 **          - An element in the same group with a larger element number
03750 **      If reached end of linked list
03751 **          Append new ACR_ELEMENTITEM to end of linked list
03752 **      If reached a different group
03753 **          Insert new ACR_ELEMENTITEM just before new group
03754 **      If reached an element in the same group with a larger element number
03755 **          Insert new ACR_ELEMENTITEM just before the "larger" element
03756 */
03757 static CONDITION
03758 insertNewElement(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
03759 {
03760     PRV_ELEMENT_ITEM
03761     * nextItem,
03762     *newItem;
03763     PRV_GROUP_ITEM
03764         * groupItem;
03765     CONDITION
03766         cond;
03767     char
03768        *p;
03769 
03770     cond = newElementItem(element, TRUE, &newItem);
03771     if (cond != DCM_NORMAL) {
03772         return cond;
03773     }
03774     newItem->byteOrder = DCM_ORDERNATIVE;
03775     if ((newItem->element.length & 1) != 0) {
03776         if (newItem->element.representation == DCM_AE) {
03777             p = newItem->element.d.string;      /* repair, check for 16 */
03778             p[newItem->element.length] = ' ';
03779             newItem->paddedDataLength = element->length + 1;
03780             (void) memcpy(p, element->d.string, element->length);
03781         } else if (newItem->element.representation == DCM_AS) {
03782             p = newItem->element.d.string;
03783             p[newItem->element.length] = ' ';
03784             newItem->paddedDataLength = element->length + 1;
03785             (void) memcpy(p, element->d.string, element->length);
03786         } else if (newItem->element.representation == DCM_CS) {
03787             p = newItem->element.d.string;
03788             p[newItem->element.length] = ' ';
03789             newItem->paddedDataLength = element->length + 1;
03790             (void) memcpy(p, element->d.string, element->length);
03791         } else if (newItem->element.representation == DCM_DA) {
03792             p = newItem->element.d.string;
03793             p[newItem->element.length] = ' ';
03794             newItem->paddedDataLength = element->length + 1;
03795             (void) memcpy(p, element->d.string, element->length);
03796         } else if (newItem->element.representation == DCM_DS) {
03797             p = newItem->element.d.string;
03798             p[newItem->element.length] = ' ';
03799             newItem->paddedDataLength = element->length + 1;
03800             (void) memcpy(p, element->d.string, element->length);
03801         } else if (newItem->element.representation == DCM_IS) {
03802             p = newItem->element.d.string;
03803             p[newItem->element.length] = ' ';
03804             newItem->paddedDataLength = element->length + 1;
03805             (void) memcpy(p, element->d.string, element->length);
03806         } else if (newItem->element.representation == DCM_LT) {
03807             p = newItem->element.d.string;
03808             p[newItem->element.length] = ' ';
03809             newItem->paddedDataLength = element->length + 1;
03810             (void) memcpy(p, element->d.string, element->length);
03811         } else if (newItem->element.representation == DCM_LO) {
03812             p = newItem->element.d.string;
03813             p[newItem->element.length] = ' ';
03814             newItem->paddedDataLength = element->length + 1;
03815             (void) memcpy(p, element->d.string, element->length);
03816         } else if (newItem->element.representation == DCM_PN) {
03817             p = newItem->element.d.string;
03818             p[newItem->element.length] = ' ';
03819             newItem->paddedDataLength = element->length + 1;
03820             (void) memcpy(p, element->d.string, element->length);
03821         } else if (newItem->element.representation == DCM_SH) {
03822             p = newItem->element.d.string;
03823             p[newItem->element.length] = ' ';
03824             newItem->paddedDataLength = element->length + 1;
03825             (void) memcpy(p, element->d.string, element->length);
03826         } else if (newItem->element.representation == DCM_ST) {
03827             p = newItem->element.d.string;
03828             p[newItem->element.length] = ' ';
03829             newItem->paddedDataLength = element->length + 1;
03830             (void) memcpy(p, element->d.string, element->length);
03831         } else if (newItem->element.representation == DCM_TM) {
03832             p = newItem->element.d.string;
03833             p[newItem->element.length] = ' ';
03834             newItem->paddedDataLength = element->length + 1;
03835             (void) memcpy(p, element->d.string, element->length);
03836         } else if (newItem->element.representation == DCM_UI) {
03837             p = newItem->element.d.string;
03838             p[newItem->element.length] = '\0';
03839             newItem->paddedDataLength = element->length + 1;
03840             (void) memcpy(p, element->d.string, element->length);
03841         } else if (newItem->element.representation == DCM_UT) {
03842             p = newItem->element.d.string;
03843             p[newItem->element.length] = ' ';
03844             newItem->paddedDataLength = element->length + 1;
03845             (void) memcpy(p, element->d.string, element->length);
03846         } else if (newItem->element.representation == DCM_SQ) {
03847 /*          newItem->element.length = 0xffffffff; */
03848             newItem->element.d.sq = element->d.sq;
03849         } else {
03850             CTN_FREE(newItem);
03851             return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
03852                                       DCM_Message(DCM_UNEVENELEMENTLENGTH),
03853                                       DCM_TAG_GROUP(element->tag),
03854                              DCM_TAG_ELEMENT(element->tag), element->length,
03855                                       "insertNewElement");
03856         }
03857     } else if (newItem->element.representation != DCM_SQ) {
03858         (void) memcpy(newItem->element.d.ot, element->d.ot, element->length);
03859     } else {
03860 /*      newItem->element.length = 0xffffffff; */
03861         newItem->element.d.sq = element->d.sq;
03862     }
03863     if ((*object)->objectSize != DCM_UNSPECIFIEDLENGTH)
03864         (*object)->objectSize += 8 + newItem->paddedDataLength;
03865 
03866 /* repair */
03867     cond = updateSpecialElements(object, newItem);
03868     if (cond != DCM_NORMAL)
03869         return cond;
03870 
03871     groupItem = (void *)LST_Current(&(*object)->groupList);
03872     if (groupItem == NULL)
03873         return COND_PushCondition(DCM_LISTFAILURE,
03874                           DCM_Message(DCM_LISTFAILURE), "insertNewElement");
03875 
03876     if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH)
03877         groupItem->baseLength += 2 + 2 + 4 + newItem->paddedDataLength;
03878 
03879     if (newItem->element.representation == DCM_OW ||
03880         newItem->element.representation == DCM_OB ||
03881         newItem->element.representation == DCM_SQ) {
03882         groupItem->longVRAttributes++;
03883         (*object)->longVRAttributes++;
03884     }
03885     if ((nextItem = (void *)LST_Head(&groupItem->elementList)) == NULL) {
03886         cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
03887         if (cond != LST_NORMAL)
03888             return COND_PushCondition(DCM_LISTFAILURE,
03889                                       DCM_Message(DCM_LISTFAILURE),
03890                                       "insertNewElement");
03891         else
03892             return DCM_NORMAL;
03893     }
03894     (void) LST_Position(&groupItem->elementList, (void *)nextItem);
03895     if (DCM_TAG_ELEMENT(nextItem->element.tag) == 0x0000)
03896         (void) memcpy(nextItem->element.d.ot, &groupItem->baseLength,
03897                       sizeof(groupItem->baseLength));
03898 
03899 /*  Now, search through the linked list for a place to insert/append
03900 **  this new item.
03901 */
03902 
03903     while (nextItem != NULL) {
03904         if (DCM_TAG_GROUP(element->tag) !=
03905             DCM_TAG_GROUP(nextItem->element.tag)) {
03906             return COND_PushCondition(DCM_BADELEMENTINGROUP,
03907                                       DCM_Message(DCM_BADELEMENTINGROUP),
03908                                       DCM_TAG_GROUP(nextItem->element.tag),
03909                                       DCM_TAG_ELEMENT(nextItem->element.tag),
03910                                       groupItem->group, "insertNewElement");
03911         } else if (DCM_TAG_ELEMENT(element->tag) <
03912                    DCM_TAG_ELEMENT(nextItem->element.tag)) {
03913             cond = LST_Insert(&groupItem->elementList, (void *)newItem, LST_K_BEFORE);
03914             if (cond != LST_NORMAL)
03915                 return COND_PushCondition(DCM_LISTFAILURE,
03916                                           DCM_Message(DCM_LISTFAILURE),
03917                                           "insertNewElement");
03918             else
03919                 return DCM_NORMAL;
03920         }
03921         nextItem = (void *)LST_Next(&groupItem->elementList);
03922     }
03923 
03924 /*  If we fall out of the loop, we must have reached the end of
03925 **  the group.  Add the element to the end of the list of elements
03926 **  in this group.
03927 */
03928 
03929     cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
03930     if (cond != LST_NORMAL)
03931         return COND_PushCondition(DCM_LISTFAILURE,
03932                                   DCM_Message(DCM_LISTFAILURE),
03933                                   "insertNewElement");
03934     else
03935         return DCM_NORMAL;
03936 }
03937 
03938 static CONDITION
03939 insertThisElementItem(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM* newItem)
03940 {
03941   PRV_ELEMENT_ITEM * nextItem;
03942   PRV_GROUP_ITEM * groupItem = 0;
03943   CONDITION cond;
03944 
03945 /* repair */
03946   cond = updateSpecialElements(object, newItem);
03947   if (cond != DCM_NORMAL)
03948     return cond;
03949 
03950   cond = findCreateGroup(object, DCM_TAG_GROUP(newItem->element.tag),
03951         &groupItem);
03952 
03953   if (groupItem == NULL)
03954     return COND_PushCondition(DCM_LISTFAILURE,
03955                           DCM_Message(DCM_LISTFAILURE), "insertThisElementItem");
03956 
03957   if (groupItem->baseLength != DCM_UNSPECIFIEDLENGTH)
03958     groupItem->baseLength += 2 + 2 + 4 + newItem->paddedDataLength;
03959 
03960   if (newItem->element.representation == DCM_OW ||
03961         newItem->element.representation == DCM_OB ||
03962         newItem->element.representation == DCM_SQ) {
03963         groupItem->longVRAttributes++;
03964         (*object)->longVRAttributes++;
03965   }
03966 
03967   if ((nextItem = (void *)LST_Head(&groupItem->elementList)) == NULL) {
03968     cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
03969     if (cond != LST_NORMAL)
03970       return COND_PushCondition(DCM_LISTFAILURE,
03971                                       DCM_Message(DCM_LISTFAILURE),
03972                                       "insertThisElementItem");
03973     else
03974       return DCM_NORMAL;
03975   }
03976 
03977   (void) LST_Position(&groupItem->elementList, (void *)nextItem);
03978   if (DCM_TAG_ELEMENT(nextItem->element.tag) == 0x0000)
03979     (void) memcpy(nextItem->element.d.ot, &groupItem->baseLength,
03980                       sizeof(groupItem->baseLength));
03981 
03982 /*  Now, search through the linked list for a place to insert/append
03983 **  this new item.
03984 */
03985 
03986   while (nextItem != NULL) {
03987     if (DCM_TAG_GROUP(newItem->element.tag) !=
03988             DCM_TAG_GROUP(nextItem->element.tag)) {
03989       return COND_PushCondition(DCM_BADELEMENTINGROUP,
03990                                       DCM_Message(DCM_BADELEMENTINGROUP),
03991                                       DCM_TAG_GROUP(nextItem->element.tag),
03992                                       DCM_TAG_ELEMENT(nextItem->element.tag),
03993                                       groupItem->group, "insertThisElementItem");
03994     } else if (DCM_TAG_ELEMENT(newItem->element.tag) <
03995                    DCM_TAG_ELEMENT(nextItem->element.tag)) {
03996       cond = LST_Insert(&groupItem->elementList, (void *)newItem, LST_K_BEFORE);
03997       if (cond != LST_NORMAL)
03998         return COND_PushCondition(DCM_LISTFAILURE,
03999                                           DCM_Message(DCM_LISTFAILURE),
04000                                           "insertThisElementItem");
04001       else
04002         return DCM_NORMAL;
04003       }
04004       nextItem = (void *)LST_Next(&groupItem->elementList);
04005   }
04006 
04007 /*  If we fall out of the loop, we must have reached the end of
04008 **  the group.  Add the element to the end of the list of elements
04009 **  in this group.
04010 */
04011 
04012   cond = LST_Enqueue(&groupItem->elementList, (void *)newItem);
04013   if (cond != LST_NORMAL)
04014     return COND_PushCondition(DCM_LISTFAILURE,
04015                                   DCM_Message(DCM_LISTFAILURE),
04016                                   "insertThisElementItem");
04017   else
04018     return DCM_NORMAL;
04019 }
04020 
04021 /* updateObjectType
04022 **
04023 ** Purpose:
04024 **      Possibly modify the objectType field of an DCM object to identify
04025 **      the object as COMMAND, DATASET or MESSAGE.
04026 **
04027 ** Parameter Dictionary:
04028 **      object          Pointer to caller's PRIVATE object to be updated
04029 **      element         Pointer to DCM_ELEMENT which will be added to
04030 **                      the object and possibly cause a change in the
04031 **                      type of the object.
04032 **
04033 ** Return Values:
04034 **      DCM_NORMAL
04035 **
04036 ** Algorithm:
04037 **      Description of the algorithm (optional) and any other notes.
04038 */
04039 
04040 static CONDITION
04041 updateObjectType(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
04042 {
04043     switch ((*object)->objectType) {
04044         case DCM_OBJECTUNKNOWN:
04045         if (DCM_TAG_GROUP(element->tag) == DCM_GROUPCOMMAND)
04046             (*object)->objectType = DCM_OBJECTCOMMAND;
04047         else
04048             (*object)->objectType = DCM_OBJECTELEMENTLIST;
04049         break;
04050     case DCM_OBJECTCOMMAND:
04051         if (DCM_TAG_GROUP(element->tag) != DCM_GROUPCOMMAND)
04052             (*object)->objectType = DCM_OBJECTELEMENTLIST;
04053         break;
04054     case DCM_OBJECTELEMENTLIST:
04055     case DCM_OBJECTIMAGE:
04056         break;
04057     default:
04058         break;
04059     }
04060     return DCM_NORMAL;
04061 }
04062 
04063 /* updateSpecialElements
04064 **
04065 ** Purpose:
04066 **      Update special elements in a DICOM object when a new data element
04067 **      is added to the object.  These special fields are used by other
04068 **      parts of the package which have to refer to those fields and wish
04069 **      to do so without searching through the entire list.  This could
04070 **      get messy and is a candidate for redesign.
04071 **
04072 ** Parameter Dictionary:
04073 **      object          Pointer to caller's PRIVATE DICOM object
04074 **      element         Pointer to DCM_ELEMENT that is being added to
04075 **                      the DICOM object
04076 **
04077 ** Return Values:
04078 **      DCM_NORMAL
04079 **
04080 ** Algorithm:
04081 **      Description of the algorithm (optional) and any other notes.
04082 */
04083 static CONDITION
04084 updateSpecialElements(PRIVATE_OBJECT ** object,
04085                       PRV_ELEMENT_ITEM * item)
04086 {
04087     int idx;
04088 
04089     switch (item->element.tag) {
04090     case DCM_IMGBITSALLOCATED:
04091         (*object)->pixelBitsAllocated = *item->element.d.us;
04092         break;
04093     case DCM_IMGPIXELREPRESENTATION:
04094         (*object)->pixelRepresentation = *item->element.d.us;
04095         break;
04096     case DCM_METAGROUPLENGTH:
04097         (*object)->metaHeaderLength = *item->element.d.ul;
04098         break;
04099     case DCM_METATRANSFERSYNTAX:
04100         if (strcmp(item->element.d.string, DICOM_TRANSFERLITTLEENDIAN) == 0) {
04101             (*object)->dataOptions = DCM_ORDERLITTLEENDIAN;
04102         } else if (strcmp(item->element.d.string, DICOM_TRANSFERLITTLEENDIANEXPLICIT) == 0) {
04103             (*object)->dataOptions = DCM_EXPLICITLITTLEENDIAN;
04104         } else if (strcmp(item->element.d.string, DICOM_TRANSFERBIGENDIANEXPLICIT) == 0) {
04105             (*object)->dataOptions = DCM_EXPLICITBIGENDIAN;
04106         } else {        /* Must be an encapsulated transfer syntax */
04107             (*object)->dataOptions = DCM_EXPLICITLITTLEENDIAN;
04108         }
04109         break;
04110     case DCM_MAKETAG(0x003a, 0x0103):
04111         strncpy((*object)->waveformDataVR, item->element.d.string,
04112                 item->element.length);
04113         (*object)->waveformDataVR[item->element.length] = '\0';
04114         idx = item->element.length - 1;
04115         while (idx >= 0 && (*object)->waveformDataVR[idx] == ' ') {
04116             (*object)->waveformDataVR[idx] = '\0';
04117             idx--;
04118         }
04119         break;
04120     default:
04121         break;
04122     }
04123     return DCM_NORMAL;
04124 }
04125 
04126 typedef struct {
04127     DCM_VALUEREPRESENTATION representation;
04128     char code[3];
04129 }   VRMAP;
04130 
04131 static VRMAP vrMap[] = {
04132     {DCM_AE, "AE"},
04133     {DCM_AS, "AS"},
04134     {DCM_AT, "AT"},
04135     {DCM_CS, "CS"},
04136     {DCM_DA, "DA"},
04137     {DCM_DD, "DD"},
04138     {DCM_DS, "DS"},
04139     {DCM_FD, "FD"},
04140     {DCM_FL, "FL"},
04141     {DCM_IS, "IS"},
04142     {DCM_LO, "LO"},
04143     {DCM_LT, "LT"},
04144     {DCM_OT, "OT"},
04145     {DCM_SH, "SH"},
04146     {DCM_SL, "SL"},
04147     {DCM_SQ, "SQ"},
04148     {DCM_SS, "SS"},
04149     {DCM_ST, "ST"},
04150     {DCM_TM, "TM"},
04151     {DCM_UI, "UI"},
04152     {DCM_UL, "UL"},
04153     {DCM_UN, "UN"},
04154     {DCM_US, "US"},
04155     {DCM_UT, "UT"},
04156     /*{DCM_UNKNOWN, "UK"},*/
04157     {DCM_RET, "RT"},
04158     {DCM_CTX, "  "},
04159     {DCM_PN, "PN"},
04160     {DCM_OB, "OB"},
04161     {DCM_OW, "OW"},
04162     {DCM_DT, "DT"},
04163     {DCM_DLM, ""}
04164 };
04165 
04166 static VRMAP *
04167 lookupVRCode(const char *code)
04168 {
04169     int i;
04170 
04171     for (i = 0; i < (int) DIM_OF(vrMap); i++) {
04172         if (strcmp(code, vrMap[i].code) == 0)
04173             return &vrMap[i];
04174     }
04175 
04176     return NULL;
04177 }
04178 
04179 static void
04180 mapVRtoASCII(DCM_VALUEREPRESENTATION vr, char *s)
04181 {
04182     int i;
04183 
04184     for (i = 0; i < (int) DIM_OF(vrMap); i++) {
04185         if (vr == vrMap[i].representation) {
04186             strcpy(s, vrMap[i].code);
04187             return;
04188         }
04189     }
04190 
04191     strcpy(s, "");
04192     return;
04193 }
04194 
04195 static void
04196 exportVRLength(DCM_ELEMENT * e, unsigned char *b, int byteOrder,
04197                U32 * rtnLength)
04198 {
04199     int i;
04200     char *c = "xx";
04201     unsigned char *p;
04202     U16 shortLength;
04203     DCM_VALUEREPRESENTATION vr;
04204 
04205     vr = e->representation;
04206     if (e->tag == DCM_MAKETAG(0x003a, 0x1000))
04207         vr = DCM_OB;
04208 
04209     for (i = 0; i < DIM_OF(vrMap); i++) {
04210         if (vr == vrMap[i].representation) {
04211             c = vrMap[i].code;
04212             break;
04213         }
04214     }
04215 
04216     *b++ = *c++;
04217     *b++ = *c++;
04218     *rtnLength += 2;
04219 
04220     if (vr == DCM_OB || vr == DCM_OW || vr == DCM_SQ || vr == DCM_UN) {
04221         *b++ = 0x00;
04222         *b++ = 0x00;
04223         if (byteOrder == BYTEORDER_SAME) {
04224             p = (unsigned char *) &e->length;
04225             *b++ = *p++;
04226             *b++ = *p++;
04227             *b++ = *p++;
04228             *b++ = *p++;
04229         } else {
04230             p = (unsigned char *) &e->length;
04231             *b++ = p[3];
04232             *b++ = p[2];
04233             *b++ = p[1];
04234             *b++ = p[0];
04235         }
04236         *rtnLength += 6;
04237     } else {
04238         shortLength = (U16) e->length;
04239         if (byteOrder == BYTEORDER_SAME) {
04240             p = (unsigned char *) &shortLength;
04241             *b++ = *p++;
04242             *b++ = *p++;
04243         } else {
04244             p = (unsigned char *) &shortLength;
04245             *b++ = p[1];
04246             *b++ = p[0];
04247         }
04248         *rtnLength += 2;
04249     }
04250 }
04251 
04252 static CONDITION
04253 exportPreamble(PRIVATE_OBJECT ** obj, unsigned char *dst,
04254                U32 bufferLength, U32 * rtnLength)
04255 {
04256     *rtnLength = 0;
04257     if (bufferLength < (DCM_PREAMBLELENGTH + 4))
04258         return COND_PushCondition(DCM_EXPORTBUFFERTOOSMALL,
04259                   DCM_Message(DCM_EXPORTBUFFERTOOSMALL), (int) bufferLength,
04260                                   "exportPreamble");
04261 
04262     (void) memcpy(dst, (*obj)->preamble, DCM_PREAMBLELENGTH);
04263     dst += DCM_PREAMBLELENGTH;
04264     (void) memcpy(dst, "DICM", 4);
04265     *rtnLength += DCM_PREAMBLELENGTH + 4;
04266 
04267     return DCM_NORMAL;
04268 }
04269 
04270 /* exportFixedFields
04271 **
04272 ** Purpose:
04273 **      This function exports the fixed length fields of an DCM_ELEMENT
04274 **      to the caller's buffer if there is sufficient space in the
04275 **      caller's buffer.
04276 **
04277 ** Parameter Dictionary:
04278 **      element         Pointer to the actual data element to be exported
04279 **      b               Pointer to the caller's buffer to hold exported data
04280 **      length          Length of the remaining space in the caller's
04281 **                      buffer
04282 **      byteOrder       flag giving the order of the bytes as they are
04283 **                      exported.  Should be one of:
04284 **                              BYTEORDER_SAME
04285 **                              BYTEORDER_REVERSE
04286 **      rtnLength       Pointer to caller variable to hold the length
04287 **                      of the data exported.  The length of the data
04288 **                      exported will be 0 if the caller's buffer is
04289 **                      too small to hold the fixed length fields.
04290 **
04291 ** Return Values:
04292 **      None
04293 **
04294 ** Algorithm:
04295 **      If caller buffer is too small to hold all fixed length fields
04296 **          Place 0 in caller's rtnLength variable
04297 **          return
04298 **      Else
04299 **          If byteOrder is the same
04300 **              Copy fixed length fields in same byte order
04301 **          Else
04302 **              Copy fixed length fields in reverse byte order
04303 **          Set caller's rtnLength variable to 8 (short, short, long)
04304 */
04305 
04306 static void
04307 exportFixedFields(DCM_ELEMENT * e,
04308                   unsigned char *b, U32 length, int byteOrder,
04309                   CTNBOOLEAN explicitVR, U32 * rtnLength)
04310 {
04311     unsigned char
04312        *p;
04313     unsigned short
04314         group,
04315         element;
04316     U32
04317         minimumLength;
04318 
04319     group = DCM_TAG_GROUP(e->tag);
04320     element = DCM_TAG_ELEMENT(e->tag);
04321     if (e->representation == DCM_DLM)
04322         explicitVR = FALSE;
04323 
04324     minimumLength = sizeof(group) + sizeof(element) + sizeof(e->length);
04325     if (explicitVR)
04326         minimumLength += 4;
04327 
04328     *rtnLength = 0;
04329     if (length >= minimumLength) {
04330         if (byteOrder == BYTEORDER_SAME) {
04331             p = (unsigned char *) &group;
04332             *b++ = *p++;
04333             *b++ = *p++;
04334             p = (unsigned char *) &element;
04335             *b++ = *p++;
04336             *b++ = *p++;
04337             *rtnLength += 4;
04338             if (explicitVR) {
04339                 exportVRLength(e, b, byteOrder, rtnLength);
04340             } else {
04341                 p = (unsigned char *) &e->length;
04342                 *b++ = *p++;
04343                 *b++ = *p++;
04344                 *b++ = *p++;
04345                 *b++ = *p++;
04346                 *rtnLength += 4;
04347             }
04348         } else {
04349             p = (unsigned char *) &group;
04350             *b++ = p[1];
04351             *b++ = p[0];
04352             p = (unsigned char *) &element;
04353             *b++ = p[1];
04354             *b++ = p[0];
04355             *rtnLength += 4;
04356             if (explicitVR) {
04357                 exportVRLength(e, b, byteOrder, rtnLength);
04358             } else {
04359                 p = (unsigned char *) &e->length;
04360                 *b++ = p[3];
04361                 *b++ = p[2];
04362                 *b++ = p[1];
04363                 *b++ = p[0];
04364                 *rtnLength += 4;
04365             }
04366         }
04367     }
04368 }
04369 
04370 /* exportData
04371 **
04372 ** Purpose:
04373 **      Export the data part of a DCM_ELEMENT.  This function exports
04374 **      all or part of the data portion of an DCM_ELEMENT in the byte order
04375 **      requested by the caller.  The caller specifies the byte order
04376 **      in a formal argument.  The function uses context information to
04377 **      know where to start the export in one data element.  The function
04378 **      does not update the context information but does return the
04379 **      number of bytes exported.
04380 **
04381 ** Parameter Dictionary:
04382 **      object          Pointer to the caller's ACR object which is
04383 **                      being exported.
04384 **      element         Pointer to the ACR_ELEMENT that is being exported
04385 **      b               Pointer to the caller's buffer to hold the
04386 **                      exported data.
04387 **      length          Length of the caller's buffer to hold the data.
04388 **      byteOrder       Flag giving the order of the bytes in the exported
04389 **                      stream.  Flag should be one of:
04390 **                          BYTEORDER_SAME
04391 **                          BYTEORDER_REVERSE
04392 **      rtnLength       Pointer to caller variable to hold number of bytes
04393 **                      that are actually exported.
04394 **
04395 ** Return Values:
04396 **
04397 **      DCM_FILEACCESSERROR
04398 **      DCM_NORMAL
04399 **
04400 ** Algorithm
04401 **
04402 **      Set caller's rtnLength variable to 0
04403 **      Export data based on representation of data element
04404 **      CASE 16 bit binary:
04405 **          While (length >= 2)
04406 **              If (byte order is same OR element is 8 bit pixel data)
04407 **                  Copy 2 bytes to output area
04408 **                  Increment input/output pointers by 2
04409 **              Else
04410 **                  Copy and swap 2 bytes to output area
04411 **                  Increment input/output pointers by 2
04412 **              Endif
04413 **              Decrement length by 2
04414 **              Increment caller's rtnLength by 2
04415 **          End while
04416 **
04417 **      CASE 32 bit binary:
04418 **          While (length >= 4)
04419 **              If (byte order is same)
04420 **                  Copy 4 bytes to output area
04421 **                  Increment input/output pointers by 4
04422 **              Else
04423 **                  Copy and swap 4 bytes to output area
04424 **                  Increment input/output pointers by 4
04425 **              Endif
04426 **              Decrement length by 4
04427 **              Increment caller's rtnLength by 4
04428 **
04429 **      CASE ascii text, ascii numeric, or unknown:
04430 **          Use memcpy to copy as of the remaining data as will fit
04431 **              in the caller's buffer.
04432 **          Set caller's rtnLength to the amount of data copied.
04433 **
04434 */
04435 union {
04436     unsigned short sh[2];
04437     unsigned char ch[4];
04438 }   groupElement;
04439 
04440 static CONDITION
04441 exportData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
04442            unsigned char *src,
04443            unsigned char *b, U32 length, int byteOrder,
04444            U32 * rtnLength)
04445 {
04446 /* repair OT for pixel data*/
04447     unsigned char
04448        *p;
04449     DCM_TAG
04450         * tag;
04451     DCM_ELEMENT
04452         * element;
04453     int nBytes;
04454     CONDITION cond;
04455 
04456     element = &item->element;
04457 
04458     *rtnLength = 0;
04459     if (element->d.ot == NULL) {
04460         if ((*object)->fd != -1) {
04461             (void) lseek((*object)->fd, item->currentOffset, SEEK_SET);
04462             nBytes = read((*object)->fd, b, (int) length);
04463         } else {
04464             (*object)->sk((*object)->userCtx, item->currentOffset, SEEK_SET);
04465             cond = (*object)->rd((*object)->userCtx, b, (long) length, &nBytes);
04466         }
04467         if ((U32) nBytes != length) {
04468             char b[512];
04469             sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
04470             (void) COND_PushCondition(DCM_GENERALWARNING,
04471                           DCM_Message(DCM_GENERALWARNING), "exportData", b);
04472             return COND_PushCondition(DCM_FILEACCESSERROR,
04473                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
04474                                       "exportData");
04475         }
04476         if( LITTLE_ENDIAN_ARCHITECTURE ){
04477           if (item->element.representation == DCM_AT) {
04478               DCM_ELEMENT e;
04479               e = *element;
04480               e.length = length;
04481               e.d.ot = b;
04482               swapATGroupElement(&e);
04483           }
04484         }
04485         if (byteOrder != item->byteOrder) {
04486             DCM_ELEMENT e;
04487             e = *element;
04488             e.length = length;
04489             e.d.ot = b;
04490             swapInPlace(object, &e);
04491         }
04492         *rtnLength = (U32) nBytes;
04493         item->currentOffset += nBytes;
04494     } else {
04495         p = src;
04496         switch (element->representation) {
04497         case DCM_AE:
04498         case DCM_AS:
04499         case DCM_CS:
04500         case DCM_DA:
04501         case DCM_DT:
04502         case DCM_DD:
04503         case DCM_DS:
04504         case DCM_FD:
04505         case DCM_IS:
04506         case DCM_LO:
04507         case DCM_LT:
04508         case DCM_OB:
04509         case DCM_OT:
04510         case DCM_PN:
04511         case DCM_SH:
04512         case DCM_SQ:
04513         case DCM_ST:
04514         case DCM_TM:
04515         case DCM_UI:
04516         case DCM_UT:
04517             (void) memcpy(b, p, length);
04518             *rtnLength = length;
04519             break;
04520         case DCM_AT:
04521             tag = (DCM_TAG *) p;
04522             while (length >= 4) {
04523                 groupElement.sh[0] = DCM_TAG_GROUP(*tag);
04524                 groupElement.sh[1] = DCM_TAG_ELEMENT(*tag);
04525                 if (byteOrder == BYTEORDER_SAME) {
04526                     *b++ = groupElement.ch[0];  /* Copy the group */
04527                     *b++ = groupElement.ch[1];
04528                     *b++ = groupElement.ch[2];  /* Now, the element */
04529                     *b++ = groupElement.ch[3];
04530                 } else {
04531                     *b++ = groupElement.ch[1];  /* Copy the group */
04532                     *b++ = groupElement.ch[0];
04533                     *b++ = groupElement.ch[3];  /* Now, the element */
04534                     *b++ = groupElement.ch[2];
04535                 }
04536                 tag++;
04537                 length -= 4;
04538                 *rtnLength += 4;
04539             }
04540             break;
04541         case DCM_SL:
04542         case DCM_UL:
04543         case DCM_FL:
04544             while (length >= 4) {
04545                 if (byteOrder == BYTEORDER_SAME) {
04546                     *b++ = *p++;
04547                     *b++ = *p++;
04548                     *b++ = *p++;
04549                     *b++ = *p++;
04550                 } else {
04551                     *b++ = p[3];
04552                     *b++ = p[2];
04553                     *b++ = p[1];
04554                     *b++ = p[0];
04555                     p += 4;
04556                 }
04557                 length -= 4;
04558                 *rtnLength += 4;
04559             }
04560             break;
04561         case DCM_SS:
04562         case DCM_US:
04563         case DCM_OW:
04564             /*
04565              * Temorary hack by Nilesh to support memory mapping for testing
04566              * purposes.
04567              */
04568             length &= ~1;
04569             *rtnLength += length;
04570             if (element->tag == DCM_PXLPIXELDATA) {
04571                 if (byteOrder == item->byteOrder)
04572                     (void) memcpy(b, p, length);
04573                 else
04574 #ifdef SOLARIS
04575                     swab((char *) p, (char *) b, length);
04576 #elif defined AIXV3
04577                 swab((short *) p, (short *) b, length);
04578 #elif defined MACOS
04579                 /* Not Yet Defined */
04580 #else
04581                     swab(p, b, length);
04582 #endif
04583             } else {
04584                 if (byteOrder == BYTEORDER_SAME)
04585                     (void) memcpy(b, p, length);
04586                 else
04587 #ifdef SOLARIS
04588                     swab((char *) p, (char *) b, length);
04589 #elif defined AIXV3
04590                 swab((short *) p, (short *) b, length);
04591 #elif defined MACOS
04592                 /* Not Yet Defined */
04593 #else
04594                     swab(p, b, length);
04595 #endif
04596             }
04597             break;
04598         /*case DCM_UNKNOWN:*/
04599         case DCM_UN:
04600         default:
04601 #if 0
04602             fprintf(stderr, "Should not get to default in exportData: %08x\n",
04603                     element->tag);
04604 #endif
04605             (void) memcpy(b, p, length);
04606             *rtnLength = length;
04607             break;
04608         }
04609     }
04610     return DCM_NORMAL;
04611 }
04612 
04613 static CONDITION
04614 exportEncapsulatedPixels(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
04615         unsigned char* buffer, U32 bufferlength, DCM_EXPORT_STREAM_CALLBACK* callback,
04616         void* ctx)
04617 {
04618   DCM_ELEMENT * element;
04619   int nBytes;
04620   CONDITION cond;
04621   U32 toExport;
04622   int length;
04623   DCM_FRAGMENT_ITEM* fragmentItem = 0;
04624   DCM_ELEMENT e;
04625   U32 rtnLength = 0;
04626 
04627   element = &item->element;
04628   if (element->d.ot == NULL) {
04629     if ((*object)->fd != -1) {
04630       /* Seek to the beginning of the data. Have to back up 12 bytes to
04631       ** get the pixel tag, VR, etc
04632       */
04633       (void) lseek((*object)->fd, item->dataOffset-12, SEEK_SET);
04634     } else {
04635       (*object)->sk((*object)->userCtx, item->dataOffset-12, SEEK_SET);
04636     }
04637 
04638     toExport = item->originalDataLength + 12;
04639     while(toExport > 0) {
04640       length = (toExport < bufferlength) ? toExport : bufferlength;
04641 
04642       if ((*object)->fd != -1) {
04643         nBytes = read((*object)->fd, buffer, length);
04644       } else {
04645         cond = (*object)->rd((*object)->userCtx, buffer, (long) length, &nBytes);
04646       }
04647       if ((U32) nBytes != length) {
04648         char b[512];
04649         sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
04650         (void) COND_PushCondition(DCM_GENERALWARNING,
04651                           DCM_Message(DCM_GENERALWARNING), "exportEncapsualtedPixels", b);
04652         return COND_PushCondition(DCM_FILEACCESSERROR,
04653                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
04654                                       "exportEncapsualtedPixels");
04655       }
04656       cond = callback(buffer, length, 0, ctx);
04657       if (cond != DCM_NORMAL) {
04658         return COND_PushCondition(DCM_CALLBACKABORTED,
04659               DCM_Message(DCM_CALLBACKABORTED), "exportStream");
04660       }
04661       toExport -= length;
04662     }
04663   } else {
04664     if (item->fragmentFlag != 1) {
04665       return COND_PushCondition(DCM_NOFRAGMENTSINOBJECT,
04666         "DCM Exporting pixels but did not find expected fragments in object");
04667     }
04668     e.tag = DCM_PXLPIXELDATA;
04669     e.d.ot = 0;
04670     e.representation = DCM_OB;
04671     e.length = 0xffffffff;
04672     exportFixedFields(&e, buffer, bufferlength,
04673                         LITTLE_ORDER /*byteOrder*/,
04674                         1 /* explicitV*/,
04675                         &rtnLength);
04676     toExport = rtnLength;
04677     e.tag = 0xfffee000;
04678     e.length = 0;
04679     e.representation = DCM_DLM;
04680     e.d.ot = 0;
04681     exportFixedFields(&e, buffer+toExport, bufferlength,
04682                         LITTLE_ORDER /*byteOrder*/,
04683                         1 /* explicitV*/,
04684                         &rtnLength);
04685     toExport += rtnLength;
04686 
04687     cond = callback(buffer, toExport, 0, ctx);
04688     if (cond != DCM_NORMAL) {
04689       return COND_PushCondition(DCM_CALLBACKABORTED,
04690               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04691     }
04692 
04693     fragmentItem = (DCM_FRAGMENT_ITEM*)LST_Head(&item->element.d.fragments);
04694     (void)LST_Position(&item->element.d.fragments, (void *)fragmentItem);
04695     while (fragmentItem != NULL) {
04696       RWC_printf("Fragment size: %6d\n", fragmentItem->length);
04697       e.tag = 0xfffee000;
04698       e.length = fragmentItem->length;
04699       e.representation = DCM_DLM;
04700       exportFixedFields(&e, buffer, bufferlength,
04701                         LITTLE_ORDER /*byteOrder*/,
04702                         1 /* explicitV*/,
04703                         &rtnLength);
04704       cond = callback(buffer, rtnLength, 0, ctx);
04705       if (cond != DCM_NORMAL) {
04706         return COND_PushCondition(DCM_CALLBACKABORTED,
04707               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04708       }
04709       cond = callback(fragmentItem->fragment, fragmentItem->length, 0, ctx);
04710       if (cond != DCM_NORMAL) {
04711         return COND_PushCondition(DCM_CALLBACKABORTED,
04712               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04713       }
04714 
04715       fragmentItem = (void *)LST_Next(&item->element.d.fragments);
04716     }
04717     e.tag = 0xfffee0dd;
04718     e.length = 0;
04719     e.representation = DCM_DLM;
04720     e.d.ot = 0;
04721     exportFixedFields(&e, buffer, bufferlength,
04722                         LITTLE_ORDER /*byteOrder*/,
04723                         1 /* explicitV*/,
04724                         &rtnLength);
04725     cond = callback(buffer, rtnLength, 0, ctx);
04726     if (cond != DCM_NORMAL) {
04727       return COND_PushCondition(DCM_CALLBACKABORTED,
04728               DCM_Message(DCM_CALLBACKABORTED), "exportEncapsulatedPixels");
04729     }
04730   }
04731   return DCM_NORMAL;
04732 }
04733 
04734 static CONDITION
04735 exportPixels(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * item,
04736         int encapsulatedPixels,
04737         unsigned char* buffer, U32 bufferlength, DCM_EXPORT_STREAM_CALLBACK* callback,
04738         void* ctx,
04739         int byteOrder, int explicitVR)
04740 {
04741   DCM_ELEMENT * element;
04742   int nBytes;
04743   CONDITION cond;
04744   U32 toExport;
04745   U32 bytesExported = 0;
04746   U32 exportLength = 0;
04747   int length;
04748   U32 rtnLength;
04749   U32 remainingData;
04750   unsigned char* dst;
04751   unsigned char* src;
04752   int c;
04753 
04754   if (encapsulatedPixels) {
04755     return exportEncapsulatedPixels(object, item, buffer,
04756         bufferlength, callback, ctx);
04757   }
04758 
04759   element = &item->element;
04760   rtnLength = 0;
04761   dst = buffer;
04762   c = bufferlength;
04763   exportFixedFields(element, dst, bufferlength, byteOrder,
04764                                   explicitVR, &rtnLength);
04765   dst += rtnLength;
04766   c -= rtnLength;
04767   bytesExported = rtnLength;
04768 
04769   remainingData = element->length;
04770   src = element->d.ot;
04771   item->currentOffset = item->dataOffset;
04772 
04773   while (remainingData > 0) {
04774     if (debug) {
04775       fprintf(stderr, "Export: (%08x) %d\n", element->tag, element->length);
04776     }
04777 
04778     if (element->d.ot != NULL) {
04779       remainingData = element->length -
04780                             (src - ((unsigned char *) element->d.ot));
04781     } else {
04782       remainingData = element->length -
04783                             (item->currentOffset - item->dataOffset);
04784     }
04785 
04786     exportLength = (remainingData < c) ? remainingData : c;
04787     cond = exportData(object, item, src, dst,
04788                       exportLength, byteOrder, &rtnLength);
04789     if (cond != DCM_NORMAL)
04790       return cond;
04791 
04792     src += rtnLength;
04793     dst += rtnLength;
04794     bytesExported += rtnLength;
04795     c -= rtnLength;
04796 
04797     if (c <= 20) {
04798       cond = callback(buffer, bytesExported, 0, ctx);
04799       if (cond != DCM_NORMAL) {
04800         return COND_PushCondition(DCM_CALLBACKABORTED,
04801               DCM_Message(DCM_CALLBACKABORTED), "exportPixels");
04802       }
04803       bytesExported = 0;
04804       c = bufferlength;
04805       dst = (unsigned char *) buffer;
04806     }
04807   }
04808   if (bytesExported > 0) {
04809     cond = callback(buffer, bytesExported, 0, ctx);
04810     if (cond != DCM_NORMAL) {
04811       return COND_PushCondition(DCM_CALLBACKABORTED,
04812               DCM_Message(DCM_CALLBACKABORTED), "exportPixels");
04813     }
04814   }
04815 
04816   return DCM_NORMAL;
04817 
04818 #if 0
04819   if (element->d.ot == NULL) {
04820     if ((*object)->fd != -1) {
04821       /* Seek to the beginning of the data. Have to back up 12 bytes to
04822       ** get the pixel tag, VR, etc
04823       */
04824       (void) lseek((*object)->fd, item->dataOffset-12, SEEK_SET);
04825     } else {
04826       (*object)->sk((*object)->userCtx, item->dataOffset-12, SEEK_SET);
04827     }
04828 
04829     toExport = item->originalDataLength + 12;
04830     while(toExport > 0) {
04831       length = (toExport < bufferlength) ? toExport : bufferlength;
04832 
04833       if ((*object)->fd != -1) {
04834         nBytes = read((*object)->fd, buffer, length);
04835       } else {
04836         cond = (*object)->rd((*object)->userCtx, buffer, (long) length, &nBytes);
04837       }
04838       if ((U32) nBytes != length) {
04839         char b[512];
04840         sprintf(b, "byte count: %d %d, errno: %d", nBytes, length, errno);
04841         (void) COND_PushCondition(DCM_GENERALWARNING,
04842                           DCM_Message(DCM_GENERALWARNING), "exportPixels", b);
04843         return COND_PushCondition(DCM_FILEACCESSERROR,
04844                       DCM_Message(DCM_FILEACCESSERROR), (*object)->fileName,
04845                                       "exportPixels");
04846       }
04847       cond = callback(buffer, length, 0, ctx);
04848       if (cond != DCM_NORMAL) {
04849         return COND_PushCondition(DCM_CALLBACKABORTED,
04850               DCM_Message(DCM_CALLBACKABORTED), "exportStream");
04851       }
04852       toExport -= length;
04853     }
04854   } else {
04855   }
04856   return DCM_NORMAL;
04857 #endif
04858 
04859 }
04860 
04861 /* fileSize
04862 **
04863 ** Purpose:
04864 **      Determine the file size of a file on an open descriptor.
04865 **
04866 ** Parameter Dictionary:
04867 **      fd      File descriptor for an open file.
04868 **
04869 ** Return Values:
04870 **      the size of the open file in bytes (nonnegative)
04871 **      a negative status value returned by fstat
04872 **
04873 ** Algorithm:
04874 **      call unix fstat system call to get file size.
04875 **      if successful call
04876 **          return file size
04877 **      else
04878 **          return status returned by fstat call (-1)
04879 */
04880 #ifdef MACOS
04881 static long
04882 #else
04883 static int
04884 #endif
04885 fileSize(int fd)
04886 {
04887     int
04888         status;
04889     struct stat
04890         im_stat;
04891 
04892     status = fstat(fd, &im_stat);
04893     if (status < 0) {
04894         return status;
04895     } else
04896         return im_stat.st_size;
04897 }
04898 
04899 /* swapInPlace
04900 **
04901 ** Purpose:
04902 **      Swap data in place for byte order adjustment.  Bytes are swapped
04903 **      for data with representations of DCM_US and DCM_UL (binary values).
04904 **      Special care is taken with pixel data which may be 8 bits.
04905 **
04906 ** Parameter Dictionary:
04907 **      object          Pointer to caller's DCM object containing the
04908 **                      element with the data to be swapped
04909 **      element         Pointer to DCM_ELEMENT that contains the data to be
04910 **                      swapped.
04911 **
04912 ** Return Values:
04913 **      None
04914 **
04915 ** Algorithm:
04916 **      If (element->representation is 16 bit binary)
04917 **          If (element is pixel data and pixel data is not 16 bits)
04918 **              return
04919 **          Swap in place short integers for this element.
04920 **      Else if (element->representation is 32 bit binary)
04921 **          Swap in place long integers for this element
04922 */
04923 
04924 static void
04925 swapInPlace(PRIVATE_OBJECT ** object, DCM_ELEMENT * e)
04926 {
04927     U32
04928     length;
04929     unsigned char
04930         tmp,
04931        *p1;
04932 
04933     length = e->length;
04934     p1 = e->d.ot;
04935     if (e->representation == DCM_US || e->representation == DCM_SS ||
04936         e->representation == DCM_OW || e->representation == DCM_AT) {
04937         if (e->tag == DCM_PXLPIXELDATA &&
04938             (*object)->pixelBitsAllocated != 16)
04939             return;
04940 
04941         while (length > 0) {
04942             tmp = p1[0];
04943             p1[0] = p1[1];
04944             p1[1] = tmp;
04945             p1 += 2;
04946             length -= 2;
04947         }
04948     } else if (e->representation == DCM_UL || e->representation == DCM_SL) {
04949         while (length > 0) {
04950             tmp = p1[0];
04951             p1[0] = p1[3];
04952             p1[3] = tmp;
04953             tmp = p1[1];
04954             p1[1] = p1[2];
04955             p1[2] = tmp;
04956             length -= 4;
04957             p1 += 4;
04958         }
04959     }
04960 }
04961 
04962 
04963 /* checkObject
04964 **
04965 ** Purpose:
04966 **      Examine a PRIVATE OBJECT to see if it looks like is has the proper
04967 **      fields defined.  This function is used to try to make certain that
04968 **      users call the DCM routines with the proper objects.  If the object
04969 **      is legal, the function returns DCM_NORMAL.  If the object is not
04970 **      legal, the function will return an error.
04971 **
04972 ** Parameter Dictionary:
04973 **      object          PRIVATE_OBJECT to be examined by this function
04974 **      caller          Name of the function (ASCIZ) that called this
04975 **                      function.  In case of failure, this becomes part of
04976 **                      the error message that is pushed on the stack.
04977 **
04978 ** Return Values:
04979 **      DCM_NORMAL
04980 **      DCM_NULLOBJECT
04981 **      DCM_ILLEGALOBJECT
04982 **
04983 ** Algorithm:
04984 **      Description of the algorithm (optional) and any other notes.
04985 */
04986 
04987 static CONDITION
04988 checkObject(PRIVATE_OBJECT ** object, char *caller)
04989 {
04990     if (object == NULL)
04991         return COND_PushCondition(DCM_NULLOBJECT, DCM_Message(DCM_NULLOBJECT),
04992                                   caller);
04993     if (*object == NULL)
04994         return COND_PushCondition(DCM_NULLOBJECT, DCM_Message(DCM_NULLOBJECT),
04995                                   caller);
04996 
04997     if (strcmp((*object)->keyType, KEY_DCM_OBJECT) != 0)
04998         return COND_PushCondition(DCM_ILLEGALOBJECT,
04999                                   DCM_Message(DCM_ILLEGALOBJECT), caller);
05000     return DCM_NORMAL;
05001 }
05002 
05003 
05004 /* writeFile
05005 **
05006 ** Purpose:
05007 **      Write the data in the buffer into the file specified by the file
05008 **      descriptor
05009 **
05010 ** Parameter Dictionary:
05011 **      buffer          Buffer holding the information to be written
05012 **      length          Length of the buffer
05013 **      flag            Unused
05014 **      fd              File descriptor
05015 **
05016 ** Return Values:
05017 **
05018 **      DCM_FILEIOERROR
05019 **      DCM_NORMAL
05020 **
05021 ** Notes:
05022 **
05023 ** Algorithm:
05024 **      Description of the algorithm (optional) and any other notes.
05025 */
05026 
05027 static CONDITION
05028 writeFile(void *buffer, U32 length, int flag,
05029           void /* int */ *fdPtr)
05030 {
05031     int
05032         bytesWritten;
05033     int *fd;
05034 
05035     fd = (int *) fdPtr;
05036 
05037     bytesWritten = write(*fd, buffer, (int) length);
05038     if (bytesWritten != (int) length)
05039         return COND_PushCondition(DCM_FILEIOERROR,
05040                           DCM_Message(DCM_FILEIOERROR), "", strerror(errno),
05041                                   "writeFile");
05042     else
05043         return DCM_NORMAL;
05044 }
05045 
05046 static CONDITION
05047 countBytes(void *buffer, U32 length, int flag,
05048            void /* unsigned long */ *sizePtr)
05049 {
05050     unsigned long *size;
05051 
05052     size = (unsigned long *) sizePtr;
05053 
05054     *size += length;
05055 
05056     return DCM_NORMAL;
05057 }
05058 
05059 static CONDITION
05060 setFileOptions(DCM_OBJECT ** obj, unsigned long *opt)
05061 {
05062     CONDITION cond;
05063     char xferSyntax[DICOM_UI_LENGTH + 1];
05064     DCM_ELEMENT e = {DCM_METATRANSFERSYNTAX, DCM_UI, "", 1, sizeof(xferSyntax),
05065     NULL};
05066 
05067     e.d.string = xferSyntax;
05068     cond = DCM_ParseObject(obj, &e, 1, NULL, 0, NULL);
05069     if (cond != DCM_NORMAL)
05070         return cond;
05071 
05072     *opt = 0;
05073     if (strcmp(xferSyntax, DICOM_TRANSFERLITTLEENDIAN) == 0) {
05074         *opt = DCM_ORDERLITTLEENDIAN;
05075     } else if (strcmp(xferSyntax, DICOM_TRANSFERLITTLEENDIANEXPLICIT) == 0) {
05076         *opt = DCM_EXPLICITLITTLEENDIAN;
05077     } else if (strcmp(xferSyntax, DICOM_TRANSFERBIGENDIANEXPLICIT) == 0) {
05078         *opt = DCM_EXPLICITBIGENDIAN;
05079     } else {    /* Must be an encapsulated xfer syntax */
05080         *opt = DCM_ENCAPSULATEDPIXELS;
05081     }
05082 
05083     return DCM_NORMAL;
05084 }
05085 
05086 static CONDITION
05087 extractFileOptions(unsigned long opt, CTNBOOLEAN * part10File,
05088                    CTNBOOLEAN * explicitVR, int *byteOrder,
05089                    CTNBOOLEAN* encapsulatedPixels)
05090 {
05091     *part10File = *explicitVR = FALSE;
05092 
05093     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
05094         *part10File = TRUE;
05095         opt &= ~DCM_ORDERMASK;
05096         opt |= DCM_EXPLICITLITTLEENDIAN;
05097     }
05098     if ((opt & DCM_ORDERMASK) == 0)
05099         return COND_PushCondition(DCM_ILLEGALOPTION,
05100                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
05101                                   "extractFileOptions");
05102 
05103     switch (opt & DCM_ORDERMASK) {
05104     case DCM_ORDERNATIVE:
05105         *byteOrder = NATIVE_ORDER;
05106         *encapsulatedPixels = FALSE;
05107         break;
05108     case DCM_ORDERLITTLEENDIAN:
05109         *byteOrder = LITTLE_ORDER;
05110         *encapsulatedPixels = FALSE;
05111         break;
05112     case DCM_EXPLICITLITTLEENDIAN:
05113         *byteOrder = LITTLE_ORDER;
05114         *explicitVR = TRUE;
05115         *encapsulatedPixels = FALSE;
05116         break;
05117     case DCM_ORDERBIGENDIAN:
05118         *byteOrder = BIG_ORDER;
05119         *encapsulatedPixels = FALSE;
05120         break;
05121     case DCM_EXPLICITBIGENDIAN:
05122         *byteOrder = BIG_ORDER;
05123         *explicitVR = TRUE;
05124         *encapsulatedPixels = FALSE;
05125         break;
05126     case DCM_ENCAPSULATEDPIXELS:
05127         *byteOrder = LITTLE_ORDER;
05128         *explicitVR = TRUE;
05129         *encapsulatedPixels = TRUE;
05130         break;
05131     default:
05132         *byteOrder = LITTLE_ORDER;
05133         *encapsulatedPixels = FALSE;
05134         break;
05135     }
05136 
05137     return DCM_NORMAL;
05138 }
05139 
05140 static U32
05141 computeGroupLength(PRV_GROUP_ITEM * groupItem,
05142                    CTNBOOLEAN explicitVR)
05143 {
05144     return (explicitVR) ?
05145     groupItem->baseLength + 4 * groupItem->longVRAttributes :
05146     groupItem->baseLength;
05147 
05148 }
05149 
05150 /* exportStream
05151 **
05152 ** Purpose:
05153 **      Export a DICOM object into the stream format suitable
05154 **      for network transmission or disk storage.
05155 **
05156 ** Parameter Dictionary:
05157 **      callerObject            Handle to caller's DICOM object
05158 **      opt                     Bit mask giving options for exporting data
05159 **      buffer                  Pointer to caller's buffer to hold next chunk
05160 **                              of DCM stream data
05161 **      bufferlength            Length of caller's buffer to hold stream data
05162 **      callback                Callback routine to be called.
05163 **      ctx                     Pointer to context variable we maintain to keep
05164 **                              track of our location in export process.
05165 **      sequenceLevel           Current level in the sequence hierarchy
05166 **
05167 ** Return Values:
05168 **
05169 **      DCM_FILEACCESSERROR
05170 **      DCM_ILLEGALOBJECT
05171 **      DCM_LISTFAILURE
05172 **      DCM_NORMAL
05173 **      DCM_NULLOBJECT
05174 **      DCM_CALLBACKABORTED
05175 **
05176 ** Notes:
05177 **
05178 ** Algorithm:
05179 **      Description of the algorithm (optional) and any other notes.
05180 */
05181 
05182 static CONDITION
05183 exportStream(DCM_OBJECT ** callerObject, unsigned long opt,
05184              void *buffer, U32 bufferlength, DCM_EXPORT_STREAM_CALLBACK* callback,
05185              void *ctx, int sequenceLevel)
05186 {
05187     PRIVATE_OBJECT
05188     ** object;
05189     PRV_GROUP_ITEM
05190         * groupItem;
05191     PRV_ELEMENT_ITEM
05192         * elementItem;
05193     DCM_ELEMENT
05194         element;
05195     int
05196         byteOrder;
05197     int
05198         lastFlag = 0;
05199     unsigned char
05200        *src,
05201        *dst;
05202     U32
05203         c,
05204         bytesExported = 0,
05205         rtnLength,
05206         remainingData,
05207         exportLength;
05208     CONDITION
05209         cond;
05210     DCM_SEQUENCE_ITEM
05211         * sequenceItem;
05212     DCM_ELEMENT
05213         itemMarker = {
05214         DCM_DLMITEM, DCM_DLM, "", 1, DCM_UNSPECIFIEDLENGTH, NULL
05215     },
05216         itemDelimiter = {
05217         DCM_DLMITEMDELIMITATIONITEM, DCM_DLM, "", 1, 0, NULL
05218     },
05219         sequenceDelimiter = {
05220         DCM_DLMSEQUENCEDELIMITATIONITEM, DCM_DLM, "", 1, 0, NULL
05221     };
05222     CTNBOOLEAN
05223         unspecifiedSQLength = FALSE,
05224         explicitVR = FALSE,
05225         part10File = FALSE,
05226         encapsulatedPixels = FALSE;
05227     unsigned long fileOptions = 0;
05228 
05229     object = (PRIVATE_OBJECT **) callerObject;
05230     cond = checkObject(object, "exportStream");
05231     if (cond != DCM_NORMAL)
05232         return cond;
05233 
05234     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
05235         part10File = TRUE;
05236         opt &= ~DCM_ORDERMASK;
05237         opt |= DCM_EXPLICITLITTLEENDIAN;
05238         cond = setFileOptions(callerObject, &fileOptions);
05239         if (cond != DCM_NORMAL)
05240             return cond;
05241     }
05242     if ((opt & DCM_ORDERMASK) == 0)
05243         return COND_PushCondition(DCM_ILLEGALOPTION,
05244                                DCM_Message(DCM_ILLEGALOPTION), "Byte order",
05245                                   "exportStream");
05246 
05247     switch (opt & DCM_ORDERMASK) {
05248     case DCM_ORDERNATIVE:
05249         byteOrder = NATIVE_ORDER;
05250         break;
05251     case DCM_ORDERLITTLEENDIAN:
05252         byteOrder = LITTLE_ORDER;
05253         break;
05254     case DCM_EXPLICITLITTLEENDIAN:
05255         byteOrder = LITTLE_ORDER;
05256         explicitVR = TRUE;
05257         break;
05258     case DCM_ORDERBIGENDIAN:
05259         byteOrder = BIG_ORDER;
05260         break;
05261     case DCM_EXPLICITBIGENDIAN:
05262         byteOrder = BIG_ORDER;
05263         explicitVR = TRUE;
05264         break;
05265     case DCM_ENCAPSULATEDPIXELS:
05266         byteOrder = LITTLE_ORDER;
05267         explicitVR = TRUE;
05268         encapsulatedPixels = TRUE;
05269         break;
05270     default:
05271         byteOrder = LITTLE_ORDER;
05272         break;
05273     }
05274 
05275 /*  We are making this step mandatory for now (smm)*/
05276 
05277     opt &= ~DCM_SEQUENCELENGTHMASK;
05278     opt |= DCM_UNSPECIFIEDLENGTHFLAG;
05279 
05280 /*  End of something that is out of place */
05281 
05282     if ((opt & DCM_SEQUENCELENGTHMASK) == DCM_UNSPECIFIEDLENGTHFLAG)
05283         unspecifiedSQLength = TRUE;
05284 
05285     dst = (unsigned char *) buffer;
05286     c = bufferlength;
05287 
05288     if (part10File) {
05289         cond = exportPreamble(object, dst, c, &rtnLength);
05290         if (cond != DCM_NORMAL)
05291             return cond;
05292 
05293         dst += rtnLength;
05294         c -= rtnLength;
05295         bytesExported += rtnLength;
05296     }
05297     if (sequenceLevel != 0) {
05298         if (!unspecifiedSQLength)
05299             itemMarker.length = (*object)->objectSize;
05300         exportFixedFields(&itemMarker, dst, bufferlength, byteOrder,
05301                           explicitVR, &rtnLength);
05302         dst += rtnLength;
05303         c -= rtnLength;
05304         bytesExported += rtnLength;
05305     }
05306     groupItem = (void *)LST_Head(&(*object)->groupList);
05307 
05308 /*  Take this code out to allow empty groups. */
05309 #if 0
05310     if (groupItem == NULL)
05311         return COND_PushCondition(DCM_LISTFAILURE,
05312                               DCM_Message(DCM_LISTFAILURE), "exportStream");
05313 #endif
05314     if (groupItem != NULL)
05315         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
05316 
05317     while (groupItem != NULL) {
05318         if (part10File && groupItem->group != DCM_GROUPFILEMETA) {
05319             if (opt != fileOptions) {
05320                 opt = fileOptions;
05321                 cond = extractFileOptions(opt, &part10File,
05322                                           &explicitVR, &byteOrder,
05323                                           &encapsulatedPixels);
05324                 if (cond != DCM_NORMAL)
05325                     return cond;
05326             }
05327         }
05328         elementItem = (void *)LST_Head(&groupItem->elementList);
05329         if (elementItem != NULL)
05330             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
05331         if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
05332             U32 l;
05333             l = computeGroupLength(groupItem, explicitVR);
05334             *elementItem->element.d.ul = l;
05335 
05336 /* We have some problems computing group length for groups with sequences.
05337 ** For now, just remove this attribute, except for group 0000 and 0002.
05338 */
05339             if (groupItem->group != 0x0000 && groupItem->group != 0x0002)
05340                 elementItem = (void *)LST_Next(&groupItem->elementList);
05341         }
05342         while (elementItem != NULL) {
05343             if (c <= 20) {
05344                 cond = callback(buffer, bytesExported, 0, ctx);
05345                 if (cond != DCM_NORMAL)
05346                     return COND_PushCondition(DCM_CALLBACKABORTED,
05347                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05348 
05349                 bytesExported = 0;
05350                 c = bufferlength;
05351                 dst = (unsigned char *) buffer;
05352             }
05353             element = elementItem->element;
05354 
05355             if (element.tag == DCM_PXLPIXELDATA) {
05356                 /* Lots of special rules for pixel data. Handle separately */
05357                 /* First, dump the current buffer */
05358                 cond = callback(buffer, bytesExported, 0, ctx);
05359                 if (cond != DCM_NORMAL)
05360                     return COND_PushCondition(DCM_CALLBACKABORTED,
05361                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05362 
05363                 cond = exportPixels(object, elementItem, encapsulatedPixels,
05364                         buffer, bufferlength, callback, ctx, byteOrder, explicitVR);
05365                 if (cond != DCM_NORMAL)
05366                     return cond;
05367 
05368                 bytesExported = 0;
05369                 c = bufferlength;
05370                 dst = (unsigned char *) buffer;
05371                 rtnLength = 0;
05372             } else if (element.representation == DCM_SQ) {
05373                 if (unspecifiedSQLength)
05374                     element.length = DCM_UNSPECIFIEDLENGTH;
05375 
05376                 exportFixedFields(&element, dst, bufferlength, byteOrder,
05377                                   explicitVR, &rtnLength);
05378             } else {
05379                 element.length = elementItem->paddedDataLength;
05380                 exportFixedFields(&element, dst, bufferlength, byteOrder,
05381                                   explicitVR, &rtnLength);
05382             }
05383             dst += rtnLength;
05384             c -= rtnLength;
05385             bytesExported += rtnLength;
05386 
05387             remainingData = element.length;
05388             src = element.d.ot;
05389             elementItem->currentOffset = elementItem->dataOffset;
05390 
05391             if (element.tag == DCM_PXLPIXELDATA) {
05392                 /* Then, we did that above */
05393                 ;
05394             } else if (element.representation == DCM_SQ) {
05395 
05396                 cond = callback(buffer, bytesExported, 0, ctx);
05397                 if (cond != DCM_NORMAL)
05398                     return COND_PushCondition(DCM_CALLBACKABORTED,
05399                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05400 
05401                 bytesExported = 0;
05402                 c = bufferlength;
05403                 dst = (unsigned char *) buffer;
05404 
05405                 if (element.d.sq != NULL) {
05406                     sequenceItem = (void *)LST_Head(&element.d.sq);
05407                     if (sequenceItem != NULL)
05408                         (void) LST_Position(&element.d.sq, (void *)sequenceItem);
05409                     while (sequenceItem != NULL) {
05410                         cond = exportStream(&sequenceItem->object, opt,
05411                                         buffer, bufferlength, callback, ctx,
05412                                             sequenceLevel + 1);
05413                         if (cond != DCM_NORMAL)
05414                             return cond;
05415                         sequenceItem = (void *)LST_Next(&element.d.sq);
05416                     }
05417                 }
05418                 if (element.length == DCM_UNSPECIFIEDLENGTH) {
05419                     sequenceDelimiter.length = 0;
05420                     exportFixedFields(&sequenceDelimiter, dst, bufferlength,
05421                                       byteOrder, explicitVR, &rtnLength);
05422                     dst += rtnLength;
05423                     c -= rtnLength;
05424                     bytesExported += rtnLength;
05425                 }
05426             } else {
05427                 while (remainingData > 0) {
05428                     if (debug)
05429                         fprintf(stderr, "Export: (%08x) %d\n",
05430                                 element.tag, element.length);
05431                     if (element.d.ot != NULL)
05432                         remainingData = element.length -
05433                             (src - ((unsigned char *) element.d.ot));
05434                     else
05435                         remainingData = element.length -
05436                             (elementItem->currentOffset - elementItem->dataOffset);
05437 
05438                     exportLength = (remainingData < c) ? remainingData : c;
05439                     cond = exportData(object, elementItem, src, dst,
05440                                       exportLength, byteOrder, &rtnLength);
05441                     if (cond != DCM_NORMAL)
05442                         return cond;
05443 
05444                     src += rtnLength;
05445                     dst += rtnLength;
05446                     bytesExported += rtnLength;
05447                     c -= rtnLength;
05448 
05449                     if (c <= 20) {
05450                         cond = callback(buffer, bytesExported, 0, ctx);
05451                         if (cond != DCM_NORMAL)
05452                             return COND_PushCondition(DCM_CALLBACKABORTED,
05453                                                       DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05454 
05455                         bytesExported = 0;
05456                         c = bufferlength;
05457                         dst = (unsigned char *) buffer;
05458                     }
05459                 }
05460             }
05461             elementItem = (void *)LST_Next(&groupItem->elementList);
05462         }
05463         groupItem = (void *)LST_Next(&(*object)->groupList);
05464     }
05465     if ((sequenceLevel != 0) && unspecifiedSQLength) {
05466         if (c <= 20) {
05467             cond = callback(buffer, bytesExported, 0, ctx);
05468             if (cond != DCM_NORMAL)
05469                 return COND_PushCondition(DCM_CALLBACKABORTED,
05470                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05471 
05472             bytesExported = 0;
05473             c = bufferlength;
05474             dst = (unsigned char *) buffer;
05475         }
05476         exportFixedFields(&itemDelimiter, dst, bufferlength, byteOrder,
05477                           explicitVR, &rtnLength);
05478         dst += rtnLength;
05479         c -= rtnLength;
05480         bytesExported += rtnLength;
05481     }
05482     lastFlag = (sequenceLevel == 0) ? 1 : 0;
05483     cond = callback(buffer, bytesExported, lastFlag, ctx);
05484     if (cond != DCM_NORMAL)
05485         return COND_PushCondition(DCM_CALLBACKABORTED,
05486                           DCM_Message(DCM_CALLBACKABORTED), "exportStream");
05487 
05488     return DCM_NORMAL;
05489 }
05490 
05491 /* verifyFormat
05492 **
05493 ** Purpose:
05494 **  This routine verifies the format of the data value of attributes according to
05495 **  the DICOM v3 standard.
05496 **
05497 ** Parameter Dictionary:
05498 **   element    Pointer to the DCM_ELEMENT containing the element to be examined.
05499 **
05500 ** Return Values:
05501 **      DCM_NORMAL
05502 **
05503 ** Algorithm:
05504 **      switch(representation) {
05505 **      case DCM_DA:
05506 **          Retain all characters that are digits, '-', or '\'
05507 **          If the resulting string is of odd length
05508 **              Pad the string with ' '
05509 **          break;
05510 **      case DCM_TM:
05511 **          Retain all characters that are digits, '.', '-', or '\'
05512 **          If the resulting string is of odd length
05513 **              Pad the string with ' '
05514 **          break;
05515 **      case DCM_CS, DCM_AS, DCM_DS, DCM_IS, DCM_LO, DCM_SH, DCM_UT:
05516 **          Delete all the leading and trailing spaces.
05517 **          If the resulting string is of odd length
05518 **              Pad the string with ' '
05519 **          break;
05520 **      case DCM_LT, DCM_ST, DCM_PN:
05521 **          Delete all the trailing spaces.
05522 **          If the resulting string is of odd length
05523 **              Pad the string with ' '
05524 **          break;
05525 **      }
05526 */
05527 
05528 static CONDITION
05529 verifyFormat(PRV_ELEMENT_ITEM * item)
05530 {
05531     int
05532         i,
05533         l;
05534     char
05535        *src,
05536        *dst,
05537        *p;
05538     DCM_ELEMENT
05539         * element;
05540     CTNBOOLEAN
05541         stopFlag = FALSE;
05542 
05543     element = &item->element;
05544     if (element->length > 0) {
05545         switch (element->representation) {
05546         case DCM_DA:
05547             src = dst = element->d.string;
05548             l = (int) element->length;
05549             for (i = 0; i < l; i++) {
05550                 if (isdigit(*src) || (*src == '-') || (*src == '\\')) {
05551                     *dst++ = *src++;
05552                 } else {
05553                     src++;
05554                     element->length--;
05555                 }
05556             }
05557             item->paddedDataLength = element->length;
05558             if (element->length & 1) {
05559                 *dst = ' ';
05560                 item->paddedDataLength++;
05561             }
05562             break;
05563         case DCM_TM:
05564             l = (int) element->length;
05565             src = dst = element->d.string;
05566             for (i = 0; i < l; i++) {
05567                 if (isdigit(*src) || (*src == '.') || (*src == '-') || (*src == '\\')) {
05568                     *dst++ = *src++;
05569                 } else {
05570                     src++;
05571                     element->length--;
05572                 }
05573             }
05574             item->paddedDataLength = element->length;
05575             if (element->length & 1) {
05576                 *dst = ' ';
05577                 item->paddedDataLength++;
05578             }
05579             break;
05580             /*
05581              * Both the leading and trailing spaces are non-significant.
05582              */
05583         case DCM_CS:
05584         case DCM_AS:
05585         case DCM_DS:
05586         case DCM_IS:
05587         case DCM_LO:
05588         case DCM_SH:
05589         case DCM_UT:
05590             l = (int) element->length;
05591             src = dst = element->d.string;
05592             for (i = 0; i < l; i++) {
05593                 if ((*src == ' ') && !stopFlag) {
05594                     src++;
05595                     element->length--;
05596                 } else {
05597                     stopFlag = TRUE;
05598                     *dst++ = *src++;
05599                 }
05600             }
05601             /*
05602              * Right now, dst points to the char follows the last char in the
05603              * string.
05604              */
05605             stopFlag = FALSE;
05606             l = (int) element->length;
05607             p = dst - 1;
05608             for (i = l; (i > 0) && !stopFlag; i--) {
05609                 if ((*p == ' ') && !stopFlag) {
05610                     p--;
05611                     dst--;
05612                     element->length--;
05613                 } else
05614                     stopFlag = TRUE;
05615             }
05616             item->paddedDataLength = element->length;
05617             if (element->length & 1) {
05618                 *dst = ' ';
05619                 item->paddedDataLength++;
05620             }
05621             break;
05622             /*
05623              * The trailing spaces are non-significant.
05624              */
05625         case DCM_LT:
05626         case DCM_ST:
05627             l = (int) element->length;
05628             src = element->d.string + l - 1;
05629             for (i = l; (i > 0) && !stopFlag; i--) {
05630                 if ((*src == ' ') && !stopFlag) {
05631                     src--;
05632                     element->length--;
05633                 } else
05634                     stopFlag = TRUE;
05635             }
05636             item->paddedDataLength = element->length;
05637             if (element->length & 1) {
05638                 *++src = ' ';
05639                 item->paddedDataLength++;
05640             }
05641             break;
05642         case DCM_PN:
05643             /*
05644              * Strip off the trailing spaces.
05645              */
05646             l = (int) element->length;
05647             src = element->d.string + l - 1;
05648             for (i = l; (i > 0) && !stopFlag; i--) {
05649                 if ((*src == ' ') && !stopFlag) {
05650                     src--;
05651                     element->length--;
05652                 } else
05653                     stopFlag = TRUE;
05654             }
05655             /*
05656              * Convert the name to the standard V3 format.
05657              */
05658             src = dst = element->d.string;
05659             l = element->length;
05660             for (i = 0; i < l;) {
05661                 if ((src[i] == ',') || (src[i] == '^')) {
05662                     *dst++ = '^';
05663                     i++;
05664                     while ((i < l) && (src[i] == ' ')) {
05665                         element->length--;
05666                         i++;
05667                     }
05668                 } else {
05669                     *dst++ = src[i++];
05670                 }
05671             }
05672 
05673             item->paddedDataLength = element->length;
05674             if (element->length & 1) {
05675                 *dst = ' ';
05676                 item->paddedDataLength++;
05677             }
05678             break;
05679         case DCM_UI:
05680             if (element->d.string[element->length - 1] == '\0')
05681                 element->length--;
05682             if (element->d.string[element->length - 1] == ' ') {
05683                 element->d.string[element->length - 1] = '\0';
05684                 element->length--;
05685             }
05686             break;
05687         default:
05688             break;
05689         }
05690     }
05691     return DCM_NORMAL;
05692 }
05693 
05694 /* readFile
05695 **
05696 ** Purpose:
05697 **      Read DICOM object from a file
05698 **
05699 ** Parameter Dictionary:
05700 **      name                    Name of the file
05701 **      callerBuf               Buffer from which to read the object
05702 **      fd                      File descriptor
05703 **      size                    Size of the file
05704 **      fileOffset              Offset in the file from which point read starts
05705 **      recursionLevel          Level of recursion
05706 **      opt                     Indicates in what byte order to read
05707 **      callerObject            The object into which the contents are stored
05708 **      scannedLength           Length of data scanned
05709 **      remainOpenFlag          Indicates whether the file remains open
05710 **
05711 ** Return Values:
05712 **
05713 **      DCM_ELEMENTCREATEFAILED
05714 **      DCM_ELEMENTLENGTHERROR
05715 **      DCM_ELEMENTOUTOFORDER
05716 **      DCM_FILEACCESSERROR
05717 **      DCM_ILLEGALSTREAMLENGTH
05718 **      DCM_LISTFAILURE
05719 **      DCM_NORMAL
05720 **      DCM_OBJECTCREATEFAILED
05721 **      DCM_UNEVENELEMENTLENGTH
05722 **
05723 ** Notes:
05724 **
05725 ** Algorithm:
05726 **      Description of the algorithm (optional) and any other notes.
05727 */
05728 static CONDITION
05729 readFile(char *name, unsigned char *callerBuf, int fd, long size,
05730          off_t fileOffset, int recursionLevel,
05731          unsigned long opt, DCM_OBJECT ** callerObject,
05732          U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
05733          void *ctx,
05734          CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
05735          CONDITION(*sk) (void *ctx, int offset, int flag))
05736 {
05737     CONDITION
05738     cond;
05739     int
05740         byteOrder;
05741     long
05742         lastGroup = -1,
05743         lastElement = -1;
05744     U32
05745         sequenceLength,
05746         localLength;
05747     PRIVATE_OBJECT
05748         ** object;
05749     PRV_GROUP_ITEM
05750         * groupItem = NULL;
05751     unsigned short
05752         group,
05753         element,
05754         tagGroup,
05755         tagElement;
05756     DCM_ELEMENT
05757         e,
05758         tagE;
05759     CTNBOOLEAN
05760         pixelFlag,
05761         convertFlag = FALSE,
05762         done = FALSE,
05763         knownLength = TRUE,
05764         sequenceDone = FALSE,
05765         createGroupFlag,
05766         explicitVR = FALSE;
05767     unsigned char
05768         buf[8],
05769        *ptr;
05770     int
05771         nBytes;
05772     PRV_ELEMENT_ITEM
05773         * elementItem = NULL;
05774     DCM_OBJECT
05775         * sequenceObject;
05776     DCM_SEQUENCE_ITEM
05777         * sequenceItem;
05778     CTNBOOLEAN
05779         fileFlag = TRUE;
05780 
05781     if (callerBuf != NULL) {
05782         ptr = callerBuf;
05783         fileFlag = FALSE;
05784     } else
05785         ptr = buf;
05786 
05787     switch (opt & DCM_ORDERMASK) {
05788     case DCM_ORDERNATIVE:
05789         byteOrder = NATIVE_ORDER;
05790         break;
05791     case DCM_ORDERLITTLEENDIAN:
05792         byteOrder = LITTLE_ORDER;
05793         break;
05794     case DCM_EXPLICITLITTLEENDIAN:
05795         byteOrder = LITTLE_ORDER;
05796         explicitVR = TRUE;
05797         break;
05798     case DCM_ORDERBIGENDIAN:
05799         byteOrder = BIG_ORDER;
05800         break;
05801     case DCM_EXPLICITBIGENDIAN:
05802         byteOrder = BIG_ORDER;
05803         explicitVR = TRUE;
05804         break;
05805     default:
05806         byteOrder = NATIVE_ORDER;
05807         break;
05808     }
05809     if ((opt & DCM_CONVERTMASK) == DCM_FORMATCONVERSION)
05810         convertFlag = TRUE;
05811 
05812     if (scannedLength != NULL)
05813         *scannedLength = 0;
05814 
05815     cond = DCM_CreateObject(callerObject, opt);
05816     if (cond != DCM_NORMAL)
05817         return cond;
05818 
05819     object = (PRIVATE_OBJECT **) callerObject;
05820     if (fileFlag)
05821         strcpy((*object)->fileName, name);
05822 
05823     (*object)->fd = -1;
05824     (*object)->rd = rd;
05825     (*object)->sk = sk;
05826     (*object)->userCtx = ctx;
05827     if (size == (long) DCM_UNSPECIFIEDLENGTH)
05828         knownLength = FALSE;
05829 
05830     if ((fileFlag) && ((opt & DCM_DELETEMASK) == DCM_DELETEONCLOSE) && (recursionLevel == 0))
05831         (*object)->deleteFlag = TRUE;
05832 
05833     if (knownLength && (size == 0))
05834         done = TRUE;
05835 
05836     while (!done) {
05837 
05838         if ((size < 8) && knownLength) {
05839             if (debug)
05840                 (void) DCM_DumpElements(callerObject, 0);
05841             (void) DCM_CloseObject(callerObject);
05842             return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
05843                                  DCM_Message(DCM_ILLEGALSTREAMLENGTH), size,
05844                                       "readFile");
05845         }
05846         if (fileFlag) {
05847             if (fd != -1) {
05848                 nBytes = read(fd, buf, 4);
05849             } else {
05850                 cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
05851             }
05852 
05853             if (nBytes != 4)
05854                 return COND_PushCondition(DCM_FILEACCESSERROR,
05855                                      DCM_Message(DCM_FILEACCESSERROR), name,
05856                                           "readFile");
05857             ptr = buf;
05858         }
05859         if (knownLength)
05860             size -= 4;
05861         fileOffset += (off_t) 4;
05862         if (scannedLength != NULL)
05863             (*scannedLength) += 4;
05864         (*object)->objectSize += 4;
05865 
05866         if (byteOrder == BYTEORDER_SAME) {
05867             GET_SHORT_SAME_ORDER(ptr, group);
05868             GET_SHORT_SAME_ORDER(ptr + 2, element);
05869             e.tag = DCM_MAKETAG(group, element);
05870         } else {
05871             GET_SHORT_REVERSE_ORDER(ptr, group);
05872             GET_SHORT_REVERSE_ORDER(ptr + 2, element);
05873             e.tag = DCM_MAKETAG(group, element);
05874         }
05875         ptr += 4;
05876 
05877         if (explicitVR) {
05878             if (fileFlag) {
05879                 if (fd != -1) {
05880                     nBytes = read(fd, buf, 4);
05881                 } else {
05882                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
05883                 }
05884 
05885                 if (nBytes != 4)
05886                     return COND_PushCondition(DCM_FILEACCESSERROR,
05887                                      DCM_Message(DCM_FILEACCESSERROR), name,
05888                                               "readFile");
05889                 ptr = buf;
05890             }
05891             if (knownLength)
05892                 size -= 4;
05893             fileOffset += (off_t) 4;
05894             if (scannedLength != NULL)
05895                 (*scannedLength) += 4;
05896             (*object)->objectSize += 4;
05897             if ((strncmp((char *) ptr, "OB", 2) == 0) ||
05898                 (strncmp((char *) ptr, "OW", 2) == 0) ||
05899                 (strncmp((char *) ptr, "SQ", 2) == 0)) {
05900             } else {
05901             }
05902         } else {
05903 
05904             if (fileFlag) {
05905                 if (fd != -1) {
05906                     nBytes = read(fd, buf, 4);
05907                 } else {
05908                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
05909                 }
05910 
05911                 if (nBytes != 4)
05912                     return COND_PushCondition(DCM_FILEACCESSERROR,
05913                                      DCM_Message(DCM_FILEACCESSERROR), name,
05914                                               "readFile");
05915                 ptr = buf;
05916             }
05917             if (knownLength)
05918                 size -= 4;
05919             fileOffset += (off_t) 4;
05920             if (scannedLength != NULL)
05921                 (*scannedLength) += 4;
05922             (*object)->objectSize += 4;
05923 
05924 
05925             if (byteOrder == BYTEORDER_SAME) {
05926                 GET_LONG_SAME_ORDER(ptr, e.length);
05927             } else {
05928                 GET_LONG_REVERSE_ORDER(ptr, e.length);
05929             }
05930             ptr += 4;
05931         }
05932 
05933         if (((e.length & 1) != 0) && (e.length != DCM_UNSPECIFIEDLENGTH)) {
05934             if (debug)
05935                 (void) DCM_DumpElements(callerObject, 0);
05936             (void) DCM_CloseObject(callerObject);
05937             return COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
05938                                       DCM_Message(DCM_UNEVENELEMENTLENGTH),
05939                                       group, element, e.length,
05940                                       "readFile");
05941         }
05942         if ((e.length != (U32) DCM_UNSPECIFIEDLENGTH) && (e.length > (U32) size)) {
05943             if (debug)
05944                 (void) DCM_DumpElements(callerObject, 0);
05945             (void) DCM_CloseObject(callerObject);
05946             return COND_PushCondition(DCM_ELEMENTLENGTHERROR,
05947                                       DCM_Message(DCM_ELEMENTLENGTHERROR),
05948                                 group, element, e.length, size, "readFile");
05949         }
05950         if ((e.tag == DCM_DLMITEMDELIMITATIONITEM) ||
05951             (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)) {
05952             return DCM_NORMAL;
05953         }
05954         cond = DCM_LookupElement(&e);
05955         if (cond != DCM_NORMAL)
05956             (void) COND_PopCondition(0);
05957         if (e.representation == DCM_CTX)
05958             ctxSensitiveLookup(object, &e);
05959 
05960         if (e.representation == DCM_SQ) {
05961             cond = newElementItem(&e, FALSE, &elementItem);
05962             if (cond != DCM_NORMAL)
05963                 return cond;
05964             elementItem->element.d.sq = LST_Create();
05965             if (elementItem->element.d.sq == NULL)
05966                 return COND_PushCondition(DCM_LISTFAILURE,
05967                                   DCM_Message(DCM_LISTFAILURE), "readFile");
05968 
05969             localLength = elementItem->element.length;
05970             sequenceDone = (localLength == 0);
05971 
05972             while (!sequenceDone) {
05973                 if (debug)
05974                     fprintf(stderr, "Sequence Length: %d %x\n", localLength,
05975                             localLength);
05976                 if (fileFlag) {
05977                     if (fd != -1) {
05978                         nBytes = read(fd, buf, 8);
05979                     } else {
05980                         cond = (*object)->rd((*object)->userCtx, buf, 8, &nBytes);
05981                     }
05982                     if (nBytes != 8)
05983                         return COND_PushCondition(DCM_FILEACCESSERROR,
05984                                      DCM_Message(DCM_FILEACCESSERROR), name,
05985                                                   "readFile");
05986                     ptr = buf;
05987                 }
05988                 if (size != (long) DCM_UNSPECIFIEDLENGTH)
05989                     size -= 8;
05990                 fileOffset += (off_t) 8;
05991                 if (scannedLength != NULL)
05992                     (*scannedLength) += 8;
05993                 (*object)->objectSize += 8;
05994                 if (localLength != DCM_UNSPECIFIEDLENGTH)
05995                     localLength -= 8;
05996 
05997                 if (byteOrder == BYTEORDER_SAME) {
05998                     GET_SHORT_SAME_ORDER(ptr, tagGroup);
05999                     GET_SHORT_SAME_ORDER(ptr + 2, tagElement);
06000                     tagE.tag = DCM_MAKETAG(tagGroup, tagElement);
06001                     GET_LONG_SAME_ORDER(ptr + 4, tagE.length);
06002                 } else {
06003                     GET_SHORT_REVERSE_ORDER(ptr, tagGroup);
06004                     GET_SHORT_REVERSE_ORDER(ptr + 2, tagElement);
06005                     tagE.tag = DCM_MAKETAG(tagGroup, tagElement);
06006                     GET_LONG_REVERSE_ORDER(ptr + 4, tagE.length);
06007                 }
06008                 ptr += 8;
06009                 if (debug)
06010                     fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
06011                             tagGroup, tagElement, tagE.length, tagE.length);
06012                 if (tagE.tag == DCM_DLMITEM) {
06013 /*                  if (size != DCM_UNSPECIFIEDLENGTH)
06014                         size -= 8;
06015 */
06016 /*                  fileOffset += 8;
06017 */
06018                     cond = readFile(name,
06019                                     (fileFlag) ? NULL : ptr,
06020                                     fd, tagE.length,
06021                                     fileOffset, recursionLevel + 1, opt,
06022                                     &sequenceObject, &sequenceLength,
06023                                     remainOpenFlag, ctx, rd, sk);
06024                     if (cond == DCM_NORMAL) {
06025                         sequenceItem = CTN_MALLOC(sizeof(*sequenceItem));
06026                         if (sequenceItem == NULL)
06027                             return COND_PushCondition(DCM_MALLOCFAILURE,
06028                                              DCM_Message(DCM_MALLOCFAILURE),
06029                                          sizeof(*sequenceItem), "readFile");
06030 
06031                         sequenceItem->object = sequenceObject;
06032                         cond = LST_Enqueue(&elementItem->element.d.sq,
06033                                            (void *)sequenceItem);
06034                         if (cond != LST_NORMAL)
06035                             return COND_PushCondition(DCM_LISTFAILURE,
06036                                   DCM_Message(DCM_LISTFAILURE), "readFile");
06037                         if (size != (long) DCM_UNSPECIFIEDLENGTH)
06038                             size -= sequenceLength;
06039                         fileOffset += (off_t) sequenceLength;
06040                         if (scannedLength != NULL)
06041                             *scannedLength += sequenceLength;
06042                         (*object)->objectSize += sequenceLength;
06043                         if (localLength != DCM_UNSPECIFIEDLENGTH)
06044                             localLength -= sequenceLength;
06045                         ptr += sequenceLength;
06046                     } else
06047                         return cond;
06048                 } else {
06049                     sequenceDone = TRUE;
06050                 }
06051                 if (localLength == 0)
06052                     sequenceDone = TRUE;
06053             }
06054         } else {
06055             pixelFlag = (e.tag == DCM_PXLPIXELDATA);
06056             cond = newElementItem(&e, (pixelFlag == FALSE), &elementItem);
06057             if (cond != DCM_NORMAL) {
06058                 (void) DCM_CloseObject(callerObject);
06059                 return cond;
06060             }
06061             if (pixelFlag) {
06062                 if (fileFlag)
06063                     *remainOpenFlag = TRUE;
06064                 elementItem->byteOrder = byteOrder;
06065                 elementItem->dataOffset = fileOffset;
06066                 elementItem->currentOffset = 0;
06067                 if (fileFlag)
06068                     elementItem->element.d.ot = NULL;
06069                 else
06070                     elementItem->element.d.ot = (void *) ptr;
06071                 if ((*object)->pixelBitsAllocated == 8)
06072                     elementItem->element.representation = DCM_OB;
06073                 else
06074                     elementItem->element.representation = DCM_OW;
06075                 if (fileFlag) {
06076                     if (fd != -1) {
06077                         (void) lseek(fd, (off_t) elementItem->element.length, SEEK_CUR);
06078                     } else {
06079                         (*object)->sk((*object)->userCtx,
06080                                       elementItem->element.length, SEEK_CUR);
06081                     }
06082                     (*object)->fd = fd;
06083                 }
06084             } else {
06085                 if (fileFlag) {
06086                     if (fd != -1) {
06087                         nBytes = read(fd, elementItem->element.d.ot,
06088                                       (int) elementItem->element.length);
06089                     } else {
06090                         cond = (*object)->rd((*object)->userCtx,
06091                                              elementItem->element.d.ot,
06092                                (long) elementItem->element.length, &nBytes);
06093                     }
06094                     if (nBytes != (int) elementItem->element.length) {
06095                         (void) DCM_CloseObject(callerObject);
06096                         return COND_PushCondition(DCM_FILEACCESSERROR,
06097                         DCM_Message(DCM_FILEACCESSERROR), name, "readFile");
06098                     }
06099                 } else {
06100                     (void) memcpy(elementItem->element.d.ot, ptr,
06101                                   elementItem->element.length);
06102                     ptr += elementItem->originalDataLength;
06103                 }
06104 
06105                 if( LITTLE_ENDIAN_ARCHITECTURE ){
06106                   if (elementItem->element.representation == DCM_AT)
06107                     swapATGroupElement(&elementItem->element);
06108                 }
06109                 if (byteOrder != BYTEORDER_SAME)
06110                     swapInPlace(object, &elementItem->element);
06111                 if (convertFlag) {
06112                     cond = verifyFormat(elementItem);
06113                     if (cond != DCM_NORMAL)
06114                         return cond;
06115                 }
06116             }
06117             if (size != (long) DCM_UNSPECIFIEDLENGTH)
06118                 size -= elementItem->originalDataLength;
06119             fileOffset += (off_t) elementItem->originalDataLength;
06120             if (scannedLength != NULL)
06121                 (*scannedLength) += elementItem->originalDataLength;
06122 
06123             elementItem->paddedDataLength = elementItem->element.length;
06124             if (elementItem->paddedDataLength & 1)
06125                 elementItem->paddedDataLength += 1;
06126             (*object)->objectSize += elementItem->paddedDataLength;
06127         }
06128 
06129         computeVM(object, &elementItem->element);
06130 
06131         if ((long) DCM_TAG_GROUP(e.tag) == lastGroup) {
06132             if ((long) DCM_TAG_ELEMENT(e.tag) <= lastElement)
06133                 return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06134                                           DCM_Message(DCM_ELEMENTOUTOFORDER),
06135                                           group, element, "readFile");
06136         } else if ((long) DCM_TAG_GROUP(e.tag) > lastGroup) {
06137         } else {
06138             return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06139                          DCM_Message(DCM_ELEMENTOUTOFORDER), group, element,
06140                                       "readFile");
06141         }
06142         lastGroup = (long) group;
06143         lastElement = (long) element;
06144 
06145         if (groupItem == NULL)
06146             createGroupFlag = TRUE;
06147         else if (groupItem->group != group)
06148             createGroupFlag = TRUE;
06149         else
06150             createGroupFlag = FALSE;
06151 
06152         if (createGroupFlag == TRUE) {
06153             groupItem = CTN_MALLOC(sizeof(*groupItem));
06154             if (groupItem == NULL) {
06155                 (void) DCM_CloseObject(callerObject);
06156                 return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
06157                                        DCM_Message(DCM_ELEMENTCREATEFAILED),
06158                                           "readFile",
06159                                           group, 0xffff, sizeof(*groupItem));
06160             }
06161             groupItem->group = group;
06162             groupItem->baseLength = 0;
06163             groupItem->longVRAttributes = 0;
06164             groupItem->elementList = LST_Create();
06165             if (groupItem->elementList == NULL) {
06166                 (void) DCM_CloseObject(callerObject);
06167                 return COND_PushCondition(DCM_LISTFAILURE,
06168                                           DCM_Message(DCM_LISTFAILURE),
06169                                           "readFile");
06170             }
06171             if (LST_Enqueue(&(*object)->groupList, (void *)groupItem) != LST_NORMAL) {
06172                 (void) DCM_CloseObject(callerObject);
06173                 return COND_PushCondition(DCM_LISTFAILURE,
06174                                           DCM_Message(DCM_LISTFAILURE),
06175                                           "readFile");
06176             }
06177         }
06178         if (element != 0x0000)
06179             groupItem->baseLength += 8 + elementItem->paddedDataLength;
06180         if ((element == 0x0000) && ((*object)->groupLengthFlag == FALSE)) {
06181             CTN_FREE(elementItem);
06182         } else {
06183             cond = LST_Enqueue(&groupItem->elementList, (void *)elementItem);
06184             if (cond != LST_NORMAL) {
06185                 (void) DCM_CloseObject(callerObject);
06186                 return COND_PushCondition(DCM_LISTFAILURE,
06187                                           DCM_Message(DCM_LISTFAILURE),
06188                                           "readFile");
06189             }
06190             cond = updateObjectType(object, &elementItem->element);     /* repair */
06191 
06192             cond = updateSpecialElements(object, elementItem);  /* repair */
06193         }
06194 
06195         if (size == 0)
06196             done = TRUE;
06197 
06198 #ifdef DEBUG
06199         if (debug) {
06200 /*lint -e644 */
06201             (void) fprintf(stderr, "Address: %px Group %2x, element %2x, length %ld ",
06202                            elementItem,
06203                            DCM_TAG_GROUP(elementItem->element.tag),
06204                            DCM_TAG_ELEMENT(elementItem->element.tag),
06205                            elementItem->element.length);
06206 /*lint +e644 */
06207             (void) fprintf(stderr, "Object size: %d\n", (*object)->objectSize);
06208         }
06209 #endif
06210     }
06211 
06212     groupItem = (void *)LST_Head(&(*object)->groupList);
06213     if (groupItem != NULL) {
06214         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
06215         while (groupItem != NULL) {
06216             elementItem = (void *)LST_Head(&groupItem->elementList);
06217             if (elementItem != NULL) {
06218                 if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
06219                     *elementItem->element.d.ul = groupItem->baseLength;
06220                 }
06221             }
06222             groupItem = (void *)LST_Next(&(*object)->groupList);
06223         }
06224     }
06225     return DCM_NORMAL;
06226 }
06227 
06228 static CONDITION
06229 readPreamble(const char *name, unsigned char **ptr, int fd, U32 * size,
06230              off_t * fileOffset, CTNBOOLEAN knownLength,
06231              PRIVATE_OBJECT ** object, U32 * scannedLength)
06232 {
06233     int nBytes,
06234         tmp;
06235     CONDITION cond;
06236     char label[4];
06237 
06238     if (*size == 0)
06239         return DCM_STREAMCOMPLETE;
06240 
06241     if ((*size < DCM_PREAMBLELENGTH + 4) && knownLength) {
06242         if (debug)
06243             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06244         (void) DCM_CloseObject((DCM_OBJECT **) object);
06245         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06246                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06247                                   "readPreamble");
06248     }
06249     if (*ptr == NULL) {
06250         if (fd != -1) {
06251             nBytes = read(fd, (*object)->preamble, DCM_PREAMBLELENGTH);
06252             nBytes += read(fd, label, sizeof(label));
06253         } else {
06254             cond = (*object)->rd((*object)->userCtx, (*object)->preamble,
06255                                  DCM_PREAMBLELENGTH, &nBytes);
06256             cond = (*object)->rd((*object)->userCtx, label,
06257                                  sizeof(label), &tmp);
06258             nBytes += tmp;
06259         }
06260 
06261         if (nBytes != DCM_PREAMBLELENGTH + sizeof(label))
06262             return COND_PushCondition(DCM_FILEACCESSERROR,
06263                                       DCM_Message(DCM_FILEACCESSERROR), name,
06264                                       "readPreamble");
06265     } else {
06266         (void) memcpy((*object)->preamble, *ptr, DCM_PREAMBLELENGTH);
06267         (void) memcpy(label, (*ptr) + DCM_PREAMBLELENGTH, sizeof(label));
06268     }
06269 
06270     if (knownLength)
06271         *size -= DCM_PREAMBLELENGTH + sizeof(label);
06272     *fileOffset += (off_t) DCM_PREAMBLELENGTH + sizeof(label);
06273     if (*ptr != NULL)
06274         *ptr += DCM_PREAMBLELENGTH + sizeof(label);
06275     (*object)->objectSize += DCM_PREAMBLELENGTH + sizeof(label);
06276 
06277     if (strncmp(label, "DICM", 4) != 0)
06278         return 0;
06279 
06280     (*object)->preambleFlag = TRUE;
06281     return DCM_NORMAL;
06282 }
06283 
06284 
06285 static CONDITION
06286 readGroupElement(const char *name, unsigned char **ptr, int fd, U32 * size,
06287                  off_t * fileOffset, CTNBOOLEAN knownLength, int byteOrder,
06288                  CTNBOOLEAN explicitVR, CTNBOOLEAN acceptVRMismatch,
06289                  PRIVATE_OBJECT ** object, U32 * scannedLength,
06290                  DCM_ELEMENT * e)
06291 {
06292     unsigned char *localPtr;
06293     unsigned char buf[4];
06294     int nBytes;
06295     CONDITION cond;
06296     unsigned short group,
06297         element;
06298 
06299     if (*size == 0)
06300         return DCM_STREAMCOMPLETE;
06301 
06302     if ((*size < 4) && knownLength) {
06303         if (debug)
06304             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06305         (void) DCM_CloseObject((DCM_OBJECT **) object);
06306         return COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06307                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06308                                   "readFile");
06309     }
06310     if (*ptr == NULL) {
06311         if (fd != -1) {
06312             nBytes = read(fd, buf, 4);
06313         } else {
06314             cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
06315         }
06316 
06317         if (nBytes != 4)
06318             return COND_PushCondition(DCM_FILEACCESSERROR,
06319                                       DCM_Message(DCM_FILEACCESSERROR), name,
06320                                       "readGroupElement");
06321         localPtr = buf;
06322     } else {
06323         localPtr = *ptr;
06324     }
06325 
06326     if (knownLength)
06327         *size -= 4;
06328     *fileOffset += (off_t) 4;
06329     if (scannedLength != NULL)
06330         (*scannedLength) += 4;
06331     (*object)->objectSize += 4;
06332 
06333     if (byteOrder == BYTEORDER_SAME) {
06334         GET_SHORT_SAME_ORDER(localPtr, group);
06335         GET_SHORT_SAME_ORDER(localPtr + 2, element);
06336         e->tag = DCM_MAKETAG(group, element);
06337     } else {
06338         GET_SHORT_REVERSE_ORDER(localPtr, group);
06339         GET_SHORT_REVERSE_ORDER(localPtr + 2, element);
06340         e->tag = DCM_MAKETAG(group, element);
06341     }
06342     if (*ptr != NULL)
06343         *ptr += 4;
06344 
06345     if (debug)
06346         fprintf(stderr, "%04x %04x ", group, element);
06347 
06348     cond = DCM_LookupElement(e);
06349     if (cond != DCM_NORMAL)
06350         (void) COND_PopCondition(0);
06351     if (e->representation == DCM_CTX)
06352         ctxSensitiveLookup(object, e);
06353 
06354     return DCM_NORMAL;
06355 }
06356 
06357 static CONDITION
06358 readVRLength(const char *name, unsigned char **ptr, int fd, U32 * size,
06359              off_t * fileOffset,
06360              CTNBOOLEAN knownLength, int byteOrder, CTNBOOLEAN explicitVR,
06361              CTNBOOLEAN acceptVRMismatch,
06362              PRIVATE_OBJECT ** object, U32 * scannedLength, DCM_ELEMENT * e)
06363 {
06364     unsigned char *localPtr;
06365     unsigned char buf[4];
06366     char vrCode[3];
06367     VRMAP *vrPtr;
06368     int nBytes;
06369     CONDITION cond;
06370     CTNBOOLEAN calculatedLength = FALSE;
06371 
06372 ENTRY("readVRLength") ;
06373 
06374     if (*size == 0)
06375         RETURN( DCM_STREAMCOMPLETE );
06376 
06377     if ((*size < 4) && knownLength) {
06378         if (debug)
06379             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06380         (void) DCM_CloseObject((DCM_OBJECT **) object);
06381         RETURN( COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06382                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06383                                   "readVRLength") );
06384     }
06385     if (*ptr == NULL) {
06386         if (fd != -1) {
06387             nBytes = read(fd, buf, 4);
06388         } else {
06389             cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
06390         }
06391 
06392         if (nBytes != 4)
06393             RETURN( COND_PushCondition(DCM_FILEACCESSERROR,
06394                                       DCM_Message(DCM_FILEACCESSERROR), name,
06395                                       "readVRLength") ) ;
06396         localPtr = buf;
06397     } else
06398         localPtr = *ptr;
06399 
06400     if (knownLength)
06401         *size -= 4;
06402     *fileOffset += (off_t) 4;
06403     if (scannedLength != NULL)
06404         (*scannedLength) += 4;
06405     (*object)->objectSize += 4;
06406 
06407     e->length = 0;
06408     if (e->representation == DCM_DLM) {
06409         explicitVR = FALSE;     /* Special rule for delimitors */
06410     }
06411     if (explicitVR) {
06412         vrCode[0] = buf[0];
06413         vrCode[1] = buf[1];
06414         vrCode[2] = '\0';
06415         vrPtr = lookupVRCode(vrCode);
06416         if (vrPtr == NULL){
06417             if( rwc_err ){
06418              fprintf(stderr,"** DICOM ERROR: unknown VR code %s in element (%04x,%04x)\n",  /* RWC */
06419                      vrCode,DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06420             }
06421             RETURN( COND_PushCondition(DCM_UNRECOGNIZEDVRCODE,
06422                                 DCM_Message(DCM_UNRECOGNIZEDVRCODE), vrCode,
06423                                       "readVRLength") );
06424         }
06425 
06426         if (vrPtr->representation != e->representation) {
06427             if (vrPtr->representation == DCM_OB) {
06428                 /* This is probably from the waveform supplement where they */
06429                 /* transmit as OB and expect us to pull it out later */
06430                 /* We will just keep our VR which was based on context in */
06431                 /* the object */
06432                 e->representation = vrPtr->representation;
06433             } else if (e->representation == DCM_UN ||
06434                        e->representation == DCM_CTX ||
06435                        e->representation == DCM_RET ||
06436                        vrPtr->representation == DCM_OW ||
06437                        acceptVRMismatch) {      /* Believe input */
06438                 e->representation = vrPtr->representation;
06439             } else {
06440 #if 0
06441                 if (e->tag != DCM_PXLPIXELDATA){
06442                     STATUS("VR mismatch") ;
06443                     RETURN( COND_PushCondition(DCM_VRMISMATCH,
06444                                DCM_Message(DCM_VRMISMATCH), vrCode, e->tag));
06445                 }
06446 #else
06447                if( rwc_err ){
06448                 fprintf(stderr,"++ DICOM WARNING: VR mismatch in element (%04x,%04x)\n",  /* RWC */
06449                         DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06450                }
06451                e->representation = vrPtr->representation;
06452 #endif
06453             }
06454         }
06455         if (vrPtr->representation != DCM_OW &&
06456             vrPtr->representation != DCM_OB &&
06457             vrPtr->representation != DCM_UN &&
06458             vrPtr->representation != DCM_UT &&
06459             vrPtr->representation != DCM_SQ) {
06460             unsigned short shortLength;
06461             if (byteOrder == BYTEORDER_SAME) {
06462                 GET_SHORT_SAME_ORDER(localPtr + 2, shortLength);
06463             } else {
06464                 GET_SHORT_REVERSE_ORDER(localPtr + 2, shortLength);
06465             }
06466             e->length = shortLength;
06467             if (*ptr != NULL)
06468                 *ptr += 4;
06469             calculatedLength = TRUE;
06470         } else {
06471             if ((*size < 4) && knownLength) {
06472                 if (debug)
06473                     (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06474                 (void) DCM_CloseObject((DCM_OBJECT **) object);
06475                 RETURN( COND_PushCondition(DCM_ILLEGALSTREAMLENGTH,
06476                                 DCM_Message(DCM_ILLEGALSTREAMLENGTH), *size,
06477                                           "readVRLength"));
06478             }
06479             if (*ptr == NULL) {
06480                 if (fd != -1) {
06481                     nBytes = read(fd, buf, 4);
06482                 } else {
06483                     cond = (*object)->rd((*object)->userCtx, buf, 4, &nBytes);
06484                 }
06485 
06486                 if (nBytes != 4)
06487                     RETURN( COND_PushCondition(DCM_FILEACCESSERROR,
06488                                      DCM_Message(DCM_FILEACCESSERROR), name,
06489                                               "readVRLength"));
06490                 localPtr = buf;
06491             } else
06492                 localPtr = *ptr;
06493 
06494             if (knownLength)
06495                 *size -= 4;
06496             *fileOffset += (off_t) 4;
06497             if (scannedLength != NULL)
06498                 (*scannedLength) += 4;
06499             (*object)->objectSize += 4;
06500         }
06501     }
06502     if (!calculatedLength) {
06503         if (byteOrder == BYTEORDER_SAME) {
06504             GET_LONG_SAME_ORDER(localPtr, e->length);
06505         } else {
06506             GET_LONG_REVERSE_ORDER(localPtr, e->length);
06507         }
06508         if (*ptr != NULL)
06509             *ptr += 4;
06510     }
06511     if (debug) {
06512         char localVR[10];
06513         mapVRtoASCII(e->representation, localVR);
06514         fprintf(stderr, "%2s %6d %06x %s\n", localVR, e->length,
06515                 (unsigned int)*fileOffset, e->description);
06516     }
06517     if (((e->length & 1) != 0) && (e->length != DCM_UNSPECIFIEDLENGTH)) {
06518         if (debug)
06519             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06520         (void) DCM_CloseObject((DCM_OBJECT **) object);
06521         if( rwc_err ){
06522          fprintf(stderr,"** DICOM ERROR: illegal odd length=%d in element (%04x,%04x)\n",  /* RWC */
06523                  e->length,DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06524         }
06525         RETURN( COND_PushCondition(DCM_UNEVENELEMENTLENGTH,
06526                                   DCM_Message(DCM_UNEVENELEMENTLENGTH),
06527                              DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag),
06528                                   e->length, "readFile"));
06529     }
06530     if ((e->length != (U32) DCM_UNSPECIFIEDLENGTH) && (e->length > (U32) (*size))) {
06531         if (debug)
06532             (void) DCM_DumpElements((DCM_OBJECT **) object, 0);
06533         (void) DCM_CloseObject((DCM_OBJECT **) object);
06534         if( rwc_err ){
06535          fprintf(stderr,"** DICOM ERROR: oversize length=%d in element (%04x,%04x)\n",  /* RWC */
06536                  e->length,DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag) ) ; rwc_err-- ;
06537         }
06538         RETURN( COND_PushCondition(DCM_ELEMENTLENGTHERROR,
06539                                   DCM_Message(DCM_ELEMENTLENGTHERROR),
06540                              DCM_TAG_GROUP(e->tag), DCM_TAG_ELEMENT(e->tag),
06541                                   e->length, *size, "readFile"));
06542     }
06543     RETURN( DCM_NORMAL);
06544 }
06545 
06546 static CONDITION
06547 readSequence(const char *name, unsigned char **ptr, int fd, U32 * size,
06548              off_t * fileOffset, int recursionLevel, unsigned long opt,
06549           int byteOrder, CTNBOOLEAN explicitVR, CTNBOOLEAN acceptVRMismatch,
06550              CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
06551              CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
06552              U32 * scannedLength, DCM_ELEMENT * e,
06553              PRV_ELEMENT_ITEM ** elementItem)
06554 {
06555     CTNBOOLEAN knownLength = TRUE;
06556     CONDITION cond;
06557     U32 sequenceLength;
06558 
06559     U32 localLength;
06560     CTNBOOLEAN sequenceDone;
06561     DCM_ELEMENT tagE;
06562     DCM_OBJECT
06563         * sequenceObject;
06564     DCM_SEQUENCE_ITEM *sequenceItem;
06565     CONDITION flag;
06566     unsigned char *localPtr;
06567     off_t itemTagOffset;
06568 
06569     if (*size == (long) DCM_UNSPECIFIEDLENGTH)
06570         knownLength = FALSE;
06571 
06572     cond = newElementItem(e, FALSE, elementItem);
06573     if (cond != DCM_NORMAL)
06574         return cond;
06575     (*elementItem)->element.d.sq = LST_Create();
06576     if ((*elementItem)->element.d.sq == NULL)
06577         return COND_PushCondition(DCM_LISTFAILURE,
06578                               DCM_Message(DCM_LISTFAILURE), "readSequence");
06579 
06580     localLength = (*elementItem)->element.length;
06581     sequenceDone = (localLength == 0);
06582 
06583     while (!sequenceDone) {
06584         if (debug)
06585             fprintf(stderr, "Sequence Length: %d %x\n", localLength,
06586                     localLength);
06587 
06588         sequenceLength = 0;
06589         itemTagOffset = *fileOffset;
06590 
06591         flag = readGroupElement(name, ptr, fd, &localLength, fileOffset, knownLength,
06592                                 byteOrder, explicitVR, acceptVRMismatch, object, &sequenceLength, &tagE);
06593         if (flag == DCM_STREAMCOMPLETE)
06594             break;
06595         else if (flag != DCM_NORMAL)
06596             return flag;
06597 
06598         flag = readVRLength(name, ptr, fd, &localLength, fileOffset, knownLength,
06599                             byteOrder, explicitVR, acceptVRMismatch, object,
06600                             &sequenceLength, &tagE);
06601         if (flag != DCM_NORMAL)
06602             return flag;
06603 
06604         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06605             *size -= sequenceLength;
06606         if (scannedLength != NULL)
06607             *scannedLength += sequenceLength;
06608 
06609         sequenceLength = 0;
06610 
06611 
06612         if (debug)
06613             fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
06614                     DCM_TAG_GROUP(tagE.tag),
06615                     DCM_TAG_ELEMENT(tagE.tag), tagE.length, tagE.length);
06616         if (tagE.tag == DCM_DLMITEM) {
06617             localPtr = *ptr;
06618             cond = readFile1(name,
06619                              localPtr,
06620                              fd, tagE.length,
06621                              fileOffset, recursionLevel + 1, opt,
06622                              object, &sequenceObject, &sequenceLength,
06623                           remainOpenFlag, (*object)->userCtx, (*object)->rd,
06624                              (*object)->sk);
06625             *ptr = localPtr;
06626             if (cond == DCM_NORMAL) {
06627                 sequenceItem = CTN_MALLOC(sizeof(*sequenceItem));
06628                 if (sequenceItem == NULL)
06629                     return COND_PushCondition(DCM_MALLOCFAILURE,
06630                                               DCM_Message(DCM_MALLOCFAILURE),
06631                                          sizeof(*sequenceItem), "readFile");
06632 
06633                 ((PRIVATE_OBJECT *) sequenceObject)->offset = itemTagOffset;
06634                 sequenceItem->object = sequenceObject;
06635                 cond = LST_Enqueue(&(*elementItem)->element.d.sq,
06636                                    (void *)sequenceItem);
06637                 if (cond != LST_NORMAL)
06638                     return COND_PushCondition(DCM_LISTFAILURE,
06639                                   DCM_Message(DCM_LISTFAILURE), "readFile");
06640                 if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06641                     *size -= sequenceLength;
06642                 if (scannedLength != NULL)
06643                     *scannedLength += sequenceLength;
06644                 (*object)->objectSize += sequenceLength;
06645                 if (localLength != DCM_UNSPECIFIEDLENGTH)
06646                     localLength -= sequenceLength;
06647             } else
06648                 return cond;
06649         } else {
06650             sequenceDone = TRUE;
06651         }
06652         if (localLength == 0)
06653             sequenceDone = TRUE;
06654     }
06655     return DCM_NORMAL;
06656 }
06657 
06658 static CONDITION
06659 scanCompressedPixels(char *name, unsigned char **ptr, int fd, U32 * size,
06660                   off_t * fileOffset, int recursionLevel, unsigned long opt,
06661                      int byteOrder, CTNBOOLEAN explicitVR,
06662                      CTNBOOLEAN acceptVRMismatch,
06663                      CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
06664                      CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
06665                      U32 * scannedLength, DCM_ELEMENT * e,
06666                      PRV_ELEMENT_ITEM ** elementItem)
06667 {
06668     CTNBOOLEAN knownLength = TRUE;
06669     U32 sequenceLength;
06670     U32 scannedBytes = 0;
06671 
06672     U32 localLength;
06673     CTNBOOLEAN sequenceDone;
06674     DCM_ELEMENT tagE;
06675     CONDITION flag;
06676     unsigned char *localPtr;
06677 
06678     if (*size == (long) DCM_UNSPECIFIEDLENGTH)
06679         knownLength = FALSE;
06680 
06681     localLength = (*elementItem)->element.length;
06682     sequenceDone = (localLength == 0);
06683 
06684     while (!sequenceDone) {
06685         sequenceLength = 0;
06686         flag = readGroupElement(name, ptr, fd, &localLength, fileOffset,
06687                              FALSE, byteOrder, explicitVR, acceptVRMismatch,
06688                                 object, &sequenceLength, &tagE);
06689         if (flag == DCM_STREAMCOMPLETE)
06690             break;
06691         else if (flag != DCM_NORMAL)
06692             return flag;
06693 
06694         flag = readVRLength(name, ptr, fd, &localLength, fileOffset, knownLength,
06695                             byteOrder, explicitVR, acceptVRMismatch, object,
06696                             &sequenceLength, &tagE);
06697         if (flag != DCM_NORMAL)
06698             return flag;
06699 
06700         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06701             *size -= sequenceLength;
06702         if (scannedLength != NULL)
06703             *scannedLength += sequenceLength;
06704         scannedBytes += sequenceLength;
06705 
06706         if (debug)
06707             fprintf(stderr, "Sequence item: %4x %4x %d (%x)\n",
06708                     DCM_TAG_GROUP(tagE.tag),
06709                     DCM_TAG_ELEMENT(tagE.tag), tagE.length, tagE.length);
06710         if (tagE.tag == DCM_DLMITEM) {
06711             localPtr = *ptr;
06712             if (tagE.length != 0) {
06713                 lseek(fd, tagE.length, SEEK_CUR);
06714                 *fileOffset += tagE.length;
06715                 if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06716                     *size -= tagE.length;
06717                 if (scannedLength != NULL)
06718                     *scannedLength += tagE.length;
06719             }
06720         } else {
06721             sequenceDone = TRUE;
06722         }
06723         if (localLength == 0)
06724             sequenceDone = TRUE;
06725 
06726         if (debug)
06727             fprintf(stderr, "Scanned Bytes: %d\n", scannedBytes);
06728     }
06729     if ((scannedBytes & 1) != 0) {
06730         lseek(fd, 1, SEEK_CUR);
06731         *fileOffset += 1;
06732         if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06733             *size -= 1;
06734     }
06735     return DCM_NORMAL;
06736 }
06737 
06738 static CONDITION
06739 readData(const char *name, unsigned char **ptr, int fd, U32 * size,
06740          off_t * fileOffset,
06741          CTNBOOLEAN knownLength, int byteOrder, CTNBOOLEAN explicitVR,
06742          CTNBOOLEAN acceptVRMismatch,
06743          CTNBOOLEAN fileFlag, CTNBOOLEAN * remainOpenFlag,
06744          CTNBOOLEAN convertFlag, PRIVATE_OBJECT ** object,
06745          U32 * scannedLength, DCM_ELEMENT * e,
06746          PRV_ELEMENT_ITEM ** elementItem)
06747 {
06748     CTNBOOLEAN pixelFlag;
06749     CONDITION cond;
06750     int nBytes;
06751 
06752     pixelFlag = (e->tag == DCM_PXLPIXELDATA);
06753     cond = newElementItem(e, (pixelFlag == FALSE), elementItem);
06754     if (cond != DCM_NORMAL) {
06755         (void) DCM_CloseObject((DCM_OBJECT **) object);
06756         return cond;
06757     }
06758     (*elementItem)->element.data_offset = 0 ;      /* RWCox */
06759     if (pixelFlag) {
06760         if (fileFlag)
06761             *remainOpenFlag = TRUE;
06762         (*elementItem)->byteOrder = byteOrder;
06763         (*elementItem)->dataOffset = *fileOffset;
06764         (*elementItem)->currentOffset = 0;
06765         (*elementItem)->element.d.ot = NULL;
06766         if ((*object)->pixelBitsAllocated == 8)
06767             (*elementItem)->element.representation = DCM_OB;
06768         else
06769             (*elementItem)->element.representation = DCM_OW;
06770         if (fileFlag) {
06771             if (fd != -1) {
06772                 if ((*elementItem)->element.length != DCM_UNSPECIFIEDLENGTH){
06773 
06774                     pxl_off = lseek( fd , 0 , SEEK_CUR ) ;
06775                     pxl_len = (*elementItem)->element.length ;
06776 
06777                     (*elementItem)->element.data_offset = pxl_off ;   /* RWCox */
06778 
06779                     (void) lseek(fd,
06780                                  (off_t) (*elementItem)->element.length,
06781                                  SEEK_CUR);
06782                 } else {
06783                     U32 l1 = 0;
06784                     U32 s1;
06785                     off_t f1 = 0;
06786 
06787                     s1 = *size;
06788                     scanCompressedPixels("", ptr, fd,
06789                                          &s1,   /* size */
06790                                          &f1,   /* fileOffset */
06791                                          0, 0,
06792                                          byteOrder, explicitVR,
06793                                          acceptVRMismatch,
06794                                          fileFlag, remainOpenFlag,
06795                                          convertFlag, object,
06796                                          &l1,   /* scannedLength */
06797                                          e, elementItem);
06798                     (*elementItem)->originalDataLength = l1;
06799                     (*elementItem)->paddedDataLength = l1;
06800                 }
06801             } else {
06802                 (*object)->sk((*object)->userCtx,
06803                               (*elementItem)->element.length, SEEK_CUR);
06804             }
06805             (*object)->fd = fd;
06806         }
06807     } else {
06808         if (fileFlag) {
06809             if (fd != -1) {
06810                 (*elementItem)->element.data_offset = lseek(fd,0,SEEK_CUR);  /* RWCox */
06811                 nBytes = read(fd, (*elementItem)->element.d.ot,
06812                               (int) (*elementItem)->element.length);
06813             } else {
06814                 cond = (*object)->rd((*object)->userCtx,
06815                                      (*elementItem)->element.d.ot,
06816                             (long) (*elementItem)->element.length, &nBytes);
06817             }
06818             if (nBytes != (int) (*elementItem)->element.length) {
06819                 (void) DCM_CloseObject((DCM_OBJECT **) object);
06820                 return COND_PushCondition(DCM_FILEACCESSERROR,
06821                         DCM_Message(DCM_FILEACCESSERROR), name, "readFile");
06822             }
06823         } else {
06824             (void) memcpy((*elementItem)->element.d.ot, ptr,
06825                           (*elementItem)->element.length);
06826             ptr += (*elementItem)->originalDataLength;
06827         }
06828         if( LITTLE_ENDIAN_ARCHITECTURE ){
06829           if ((*elementItem)->element.representation == DCM_AT)
06830             swapATGroupElement(&(*elementItem)->element);
06831         }
06832         if (byteOrder != BYTEORDER_SAME)
06833             swapInPlace(object, &(*elementItem)->element);
06834         if (convertFlag) {
06835             cond = verifyFormat(*elementItem);
06836             if (cond != DCM_NORMAL)
06837                 return cond;
06838         }
06839     }
06840     if (*size != (long) DCM_UNSPECIFIEDLENGTH)
06841         *size -= (*elementItem)->originalDataLength;
06842     *fileOffset += (off_t) (*elementItem)->originalDataLength;
06843     if (scannedLength != NULL)
06844         (*scannedLength) += (*elementItem)->originalDataLength;
06845 
06846     if ((*elementItem)->element.length != DCM_UNSPECIFIEDLENGTH) {
06847       (*elementItem)->paddedDataLength = (*elementItem)->element.length;
06848     }
06849     if (((*elementItem)->paddedDataLength != DCM_UNSPECIFIEDLENGTH) &&
06850         ((*elementItem)->paddedDataLength & 1) )
06851         (*elementItem)->paddedDataLength += 1;
06852     (*object)->objectSize += (*elementItem)->paddedDataLength;
06853 
06854     return DCM_NORMAL;
06855 
06856 }
06857 
06858 static CONDITION
06859 checkAttributeOrder(DCM_ELEMENT * e, long *lastGroup, long *lastElement,
06860                     CTNBOOLEAN allowRepeatElements)
06861 {
06862     unsigned short group;
06863     unsigned short element;
06864 
06865     group = DCM_TAG_GROUP(e->tag);
06866     element = DCM_TAG_ELEMENT(e->tag);
06867 
06868     if ((long) group == *lastGroup) {
06869         if (((long) element == *lastElement) && allowRepeatElements) {
06870           return DCM_REPEATEDELEMENT;
06871         }
06872         if ((long) element <= *lastElement)
06873             return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06874                                       DCM_Message(DCM_ELEMENTOUTOFORDER),
06875                                       group, element, "checkAttributeOrder");
06876     } else if ((long) group > *lastGroup) {
06877     } else {
06878         return COND_PushCondition(DCM_ELEMENTOUTOFORDER,
06879                                   DCM_Message(DCM_ELEMENTOUTOFORDER),
06880                                   group, element, "checkAttributeOrder");
06881     }
06882     *lastGroup = (long) group;
06883     *lastElement = (long) element;
06884 
06885     return DCM_NORMAL;
06886 }
06887 
06888 static CONDITION
06889 handleGroupItem(PRIVATE_OBJECT ** obj, PRV_GROUP_ITEM ** groupItem,
06890                 unsigned short group)
06891 {
06892     CTNBOOLEAN createGroupFlag;
06893 
06894     if (*groupItem == NULL)
06895         createGroupFlag = TRUE;
06896     else if ((*groupItem)->group != group)
06897         createGroupFlag = TRUE;
06898     else
06899         createGroupFlag = FALSE;
06900 
06901     if (createGroupFlag == TRUE) {
06902         *groupItem = CTN_MALLOC(sizeof(**groupItem));
06903         if (*groupItem == NULL) {
06904             (void) DCM_CloseObject((DCM_OBJECT **) obj);
06905             return COND_PushCondition(DCM_ELEMENTCREATEFAILED,
06906                                       DCM_Message(DCM_ELEMENTCREATEFAILED),
06907                                       "handleGroupItem",
06908                                       group, 0xffff, sizeof(**groupItem));
06909         }
06910         (*groupItem)->group = group;
06911         (*groupItem)->baseLength = 0;
06912         (*groupItem)->longVRAttributes = 0;
06913         (*groupItem)->elementList = LST_Create();
06914         if ((*groupItem)->elementList == NULL) {
06915             (void) DCM_CloseObject((DCM_OBJECT **) obj);
06916             return COND_PushCondition(DCM_LISTFAILURE,
06917                                       DCM_Message(DCM_LISTFAILURE),
06918                                       "handleGroupItem");
06919         }
06920         if (LST_Enqueue(&(*obj)->groupList, (void *)*groupItem) != LST_NORMAL) {
06921             (void) DCM_CloseObject((DCM_OBJECT **) obj);
06922             return COND_PushCondition(DCM_LISTFAILURE,
06923                                       DCM_Message(DCM_LISTFAILURE),
06924                                       "handleGroupItem");
06925         }
06926     }
06927     return DCM_NORMAL;
06928 }
06929 
06930 static CONDITION
06931 readFile1(const char *name, unsigned char *callerBuf, int fd, U32 size,
06932           off_t * fileOffset, int recursionLevel,
06933           unsigned long opt, PRIVATE_OBJECT ** parentObject,
06934           DCM_OBJECT ** callerObject,
06935           U32 * scannedLength, CTNBOOLEAN * remainOpenFlag,
06936           void *ctx,
06937           CONDITION(*rd) (void *ctx, void *buf, int toRead, int *bytesRead),
06938           CONDITION(*sk) (void *ctx, int offset, int flag))
06939 {
06940     CONDITION
06941     cond;
06942     int
06943         byteOrder;
06944     long
06945         lastGroup = -1,
06946         lastElement = -1;
06947     U32
06948         sequenceLength,
06949         scannedSequenceLength;
06950     PRIVATE_OBJECT
06951         ** object;
06952     PRV_GROUP_ITEM
06953         * groupItem = NULL;
06954     DCM_ELEMENT
06955         e;
06956     CTNBOOLEAN
06957         convertFlag = FALSE,
06958         done = FALSE,
06959         knownLength = TRUE,
06960         explicitVR = FALSE,
06961         acceptVRMismatch = FALSE,
06962         part10Flag = FALSE;
06963     unsigned char
06964        *ptr = NULL;
06965     PRV_ELEMENT_ITEM
06966         * elementItem = NULL;
06967     CTNBOOLEAN
06968         fileFlag = TRUE;
06969     CONDITION flag;
06970     CTNBOOLEAN allowRepeatElements = FALSE;
06971 
06972 ENTRY("readFile1") ;
06973 
06974     ptr = callerBuf;
06975     if (ptr != NULL)
06976         fileFlag = FALSE;
06977 
06978     if ((opt & DCM_FILEFORMATMASK) == DCM_PART10FILE) {
06979         part10Flag = TRUE;
06980         opt &= ~DCM_ORDERMASK;
06981         opt &= ~DCM_FILEFORMATMASK;
06982         opt |= DCM_EXPLICITLITTLEENDIAN;
06983     }
06984     if ((opt & DCM_SPECIALFORMATMASK) == DCM_EFILM) {
06985         part10Flag = TRUE;
06986         opt &= ~DCM_ORDERMASK;
06987         opt &= ~DCM_FILEFORMATMASK;
06988         opt |= DCM_ORDERLITTLEENDIAN;
06989     }
06990     if ((opt & DCM_REPEATELEMENTSMASK) == DCM_ALLOWREPEATELEMENTS) {
06991       allowRepeatElements = TRUE;
06992     }
06993 
06994     switch (opt & DCM_ORDERMASK) {
06995     case DCM_ORDERNATIVE:
06996         byteOrder = NATIVE_ORDER;
06997         break;
06998     case DCM_ORDERLITTLEENDIAN:
06999         byteOrder = LITTLE_ORDER;
07000         break;
07001     case DCM_EXPLICITLITTLEENDIAN:
07002         byteOrder = LITTLE_ORDER;
07003         explicitVR = TRUE;
07004         break;
07005     case DCM_ORDERBIGENDIAN:
07006         byteOrder = BIG_ORDER;
07007         break;
07008     case DCM_EXPLICITBIGENDIAN:
07009         byteOrder = BIG_ORDER;
07010         explicitVR = TRUE;
07011         break;
07012     default:
07013         byteOrder = NATIVE_ORDER;
07014         break;
07015     }
07016     if ((opt & DCM_CONVERTMASK) == DCM_FORMATCONVERSION)
07017         convertFlag = TRUE;
07018     if ((opt & DCM_VRMASK) == DCM_ACCEPTVRMISMATCH)
07019         acceptVRMismatch = TRUE;
07020 
07021     if (scannedLength != NULL)
07022         *scannedLength = 0;
07023 
07024     cond = DCM_CreateObject(callerObject, opt);
07025     if (cond != DCM_NORMAL)
07026         RETURN( cond ) ;
07027 
07028     object = (PRIVATE_OBJECT **) callerObject;
07029     if (fileFlag)
07030         strcpy((*object)->fileName, name);
07031 
07032     (*object)->fd = -1;
07033     (*object)->rd = rd;
07034     (*object)->sk = sk;
07035     (*object)->userCtx = ctx;
07036     (*object)->dataOptions = 0;
07037     if (size == (long) DCM_UNSPECIFIEDLENGTH)
07038         knownLength = FALSE;
07039 
07040     if ((fileFlag) && ((opt & DCM_DELETEMASK) == DCM_DELETEONCLOSE) && (recursionLevel == 0))
07041         (*object)->deleteFlag = TRUE;
07042 
07043     if (parentObject != NULL)
07044         (*object)->pixelRepresentation = (*parentObject)->pixelRepresentation;
07045 
07046     if (recursionLevel == 0 && part10Flag) {
07047         flag = readPreamble(name, &ptr, fd, &size, fileOffset, knownLength,
07048                             object, scannedLength);
07049         if (flag != DCM_NORMAL)
07050             { STATUS("readPreamble fails"); goto abort; }
07051     }
07052     while (!done) {
07053         flag = readGroupElement(name, &ptr, fd, &size, fileOffset, knownLength,
07054                             byteOrder, explicitVR, acceptVRMismatch, object,
07055                                 scannedLength, &e);
07056         if (flag == DCM_STREAMCOMPLETE)
07057             break;
07058         else if (flag != DCM_NORMAL)
07059             { STATUS("readGroupElement fails"); goto abort; }
07060 #if 0
07061         if (e.tag == DCM_MAKETAG(0x003a, 0x1000)) {
07062             fprintf(stderr, "Found waveform\n");
07063         }
07064 #endif
07065         flag = readVRLength(name, &ptr, fd, &size, fileOffset, knownLength,
07066                             byteOrder, explicitVR, acceptVRMismatch, object,
07067                             scannedLength, &e);
07068         if (flag != DCM_NORMAL)
07069             { STATUS("readVRLength fails"); goto abort; }
07070 
07071         if ((e.representation == DCM_UN) &&
07072             (e.length == DCM_UNSPECIFIEDLENGTH)) {
07073             e.representation = DCM_SQ;
07074         }
07075 #ifndef SMM
07076         if ((e.tag == DCM_DLMITEMDELIMITATIONITEM) ||
07077             (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)) {
07078             RETURN( DCM_NORMAL) ;
07079         }
07080 #else
07081         if (e.tag == DCM_DLMITEMDELIMITATIONITEM) {
07082             (*object)->objectSize -= 8;
07083             RETURN( DCM_NORMAL );
07084         }
07085         if (e.tag == DCM_DLMSEQUENCEDELIMITATIONITEM)
07086             RETURN( DCM_NORMAL );
07087 #endif
07088 
07089         if (e.representation == DCM_SQ) {
07090             sequenceLength = e.length;
07091             scannedSequenceLength = 0;
07092             flag = readSequence(name, &ptr, fd, &sequenceLength,
07093                                 fileOffset, recursionLevel, opt,
07094                                 byteOrder, explicitVR, acceptVRMismatch,
07095                                 fileFlag, remainOpenFlag,
07096                                 convertFlag, object, &scannedSequenceLength,
07097                                 &e, &elementItem);
07098             if (flag != DCM_NORMAL)
07099                 { STATUS("readSequence fails"); goto abort; }
07100             if (size != (long) DCM_UNSPECIFIEDLENGTH)
07101                 size -= scannedSequenceLength;
07102             if (scannedLength != NULL)
07103                 *scannedLength += scannedSequenceLength;
07104 
07105         } else {
07106 
07107             flag = readData(name, &ptr, fd, &size, fileOffset, knownLength,
07108                           byteOrder, explicitVR, acceptVRMismatch, fileFlag,
07109                             remainOpenFlag, convertFlag,
07110                             object, scannedLength, &e, &elementItem);
07111             if (flag != DCM_NORMAL)
07112                 { STATUS("readData fails"); goto abort; }
07113         }
07114         computeVM(object, &elementItem->element);
07115 
07116         cond = checkAttributeOrder(&e, &lastGroup, &lastElement, allowRepeatElements);
07117         if (cond != DCM_NORMAL) {
07118             if (cond == DCM_REPEATEDELEMENT) {
07119                 CTN_FREE(elementItem);
07120                 continue;
07121             } else {
07122                 CTN_FREE(elementItem);     /* 14 June 2005 [rickr] */
07123                 RETURN( cond ) ;
07124             }
07125         }
07126 
07127         cond = handleGroupItem(object, &groupItem, DCM_TAG_GROUP(e.tag));
07128         if (cond != DCM_NORMAL)
07129              /* goto abort; ASG */ RETURN( cond );
07130 
07131         if (DCM_TAG_ELEMENT(e.tag) != 0x0000) {
07132             groupItem->baseLength += 8 + elementItem->paddedDataLength;
07133             if (elementItem->element.representation == DCM_OB ||
07134                 elementItem->element.representation == DCM_OW ||
07135                 elementItem->element.representation == DCM_SQ) {
07136                 groupItem->longVRAttributes++;
07137                 (*object)->longVRAttributes++;
07138             }
07139         }
07140         if ((DCM_TAG_ELEMENT(e.tag) == 0x0000) && ((*object)->groupLengthFlag == FALSE)) {
07141             CTN_FREE(elementItem);
07142         } else {
07143             cond = LST_Enqueue(&groupItem->elementList, (void *)elementItem);
07144             if (cond != LST_NORMAL) {
07145                 (void) DCM_CloseObject(callerObject);
07146                 RETURN( COND_PushCondition(DCM_LISTFAILURE,
07147                                           DCM_Message(DCM_LISTFAILURE),
07148                                           "readFile") );
07149             }
07150             cond = updateObjectType(object, &elementItem->element);     /* repair */
07151 
07152             cond = updateSpecialElements(object, elementItem);  /* repair */
07153         }
07154 
07155         if (size == 0)
07156             done = TRUE;
07157 
07158         if (part10Flag) {
07159             if ((*object)->objectSize == (DCM_PREAMBLELENGTH + 4 + 12 + (*object)->metaHeaderLength)) {
07160                 opt &= ~DCM_ORDERMASK;
07161                 opt |= (*object)->dataOptions & DCM_ORDERMASK;
07162                 explicitVR = FALSE;
07163                 switch (opt & DCM_ORDERMASK) {
07164                 case DCM_ORDERNATIVE:
07165                     byteOrder = NATIVE_ORDER;
07166                     break;
07167                 case DCM_ORDERLITTLEENDIAN:
07168                     byteOrder = LITTLE_ORDER;
07169                     break;
07170                 case DCM_EXPLICITLITTLEENDIAN:
07171                     byteOrder = LITTLE_ORDER;
07172                     explicitVR = TRUE;
07173                     break;
07174                 case DCM_ORDERBIGENDIAN:
07175                     byteOrder = BIG_ORDER;
07176                     break;
07177                 case DCM_EXPLICITBIGENDIAN:
07178                     byteOrder = BIG_ORDER;
07179                     explicitVR = TRUE;
07180                     break;
07181                 default:
07182                     byteOrder = LITTLE_ORDER;
07183                     explicitVR = TRUE;
07184                     break;
07185                 }
07186             }
07187         }
07188     }
07189 
07190 #ifdef SMM
07191 #endif
07192 
07193     groupItem = (void *)LST_Head(&(*object)->groupList);
07194     if (groupItem != NULL) {
07195         (void) LST_Position(&(*object)->groupList, (void *)groupItem);
07196         while (groupItem != NULL) {
07197             elementItem = (void *)LST_Head(&groupItem->elementList);
07198             if (elementItem != NULL) {
07199                 if (DCM_TAG_ELEMENT(elementItem->element.tag) == 0x0000) {
07200                     *elementItem->element.d.ul = groupItem->baseLength;
07201                 }
07202             }
07203             groupItem = (void *)LST_Next(&(*object)->groupList);
07204         }
07205     }
07206     RETURN( DCM_NORMAL );
07207 
07208 abort:
07209     RETURN (flag);
07210 }
07211 
07212 /* locateElement
07213 **
07214 ** Purpose:
07215 **      Locate the DICOM element with the specified tag number in the given
07216 **      DICOM object
07217 **
07218 ** Parameter Dictionary:
07219 **      obj             Handle to the DICOM object to be searched
07220 **      tag             Tag number of the element to be searched
07221 **
07222 ** Return Values:
07223 **      Pointer to the element if found else NULL
07224 **
07225 ** Notes:
07226 **
07227 ** Algorithm:
07228 **      Description of the algorithm (optional) and any other notes.
07229 */
07230 static PRV_ELEMENT_ITEM *
07231 locateElement(PRIVATE_OBJECT ** obj, DCM_TAG tag)
07232 {
07233     PRV_GROUP_ITEM
07234     * groupItem;
07235     PRV_ELEMENT_ITEM
07236         * elementItem;
07237     CTNBOOLEAN
07238         found = FALSE;
07239 
07240     groupItem = (void *)LST_Head(&(*obj)->groupList);
07241     if (groupItem == NULL)
07242         return NULL;
07243 
07244     (void) LST_Position(&(*obj)->groupList, (void *)groupItem);
07245     while (groupItem != NULL) {
07246         if (groupItem->group == DCM_TAG_GROUP(tag))
07247             break;
07248 
07249         groupItem = (void *)LST_Next(&(*obj)->groupList);
07250     }
07251     if (groupItem == NULL)
07252         return NULL;
07253 
07254     elementItem = (void *)LST_Head(&groupItem->elementList);
07255     if (elementItem == NULL)
07256         return NULL;
07257 
07258     (void) LST_Position(&groupItem->elementList, (void *)elementItem);
07259     while (!found && (elementItem != NULL)) {
07260         if (elementItem->element.tag == tag) {
07261             found = TRUE;
07262         } else
07263             elementItem = (void *)LST_Next(&groupItem->elementList);
07264     }
07265     if (found)
07266         return elementItem;
07267     else
07268         return NULL;
07269 }
07270 
07271 /* computeVM
07272 **
07273 ** Purpose:
07274 **      Compute the multiplicity of the specified element in the DICOM
07275 **      object
07276 **
07277 ** Parameter Dictionary:
07278 **      object          Handle to the DICOM object
07279 **      element         Element whose value multiplicity is to be found out.
07280 **
07281 ** Return Values:
07282 **      None
07283 **
07284 ** Notes:
07285 **
07286 ** Algorithm:
07287 **      Description of the algorithm (optional) and any other notes.
07288 */
07289 static void
07290 computeVM(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
07291 {
07292     char
07293        *c;
07294     int
07295         i;
07296 
07297     switch (element->representation) {
07298     case DCM_AE:                /* Application Entity */
07299     case DCM_AS:                /* Age string */
07300     case DCM_CS:                /* Control string */
07301     case DCM_DA:                /* Date */
07302     case DCM_DS:                /* Decimal string */
07303     case DCM_DT:                /* Date/Time */
07304     case DCM_IS:                /* Integer string */
07305     case DCM_LO:                /* Long string */
07306     case DCM_PN:                /* Person Name */
07307     case DCM_SH:                /* Short string */
07308     case DCM_TM:                /* Time */
07309     case DCM_UI:                /* Unique identifier (UID) */
07310     case DCM_UT:                /* Unlimited text */
07311         element->multiplicity = 1;
07312         c = element->d.string;
07313         for (i = 0; i < (int) element->length; i++)
07314             if (*c++ == '\\')
07315                 element->multiplicity++;
07316         break;
07317 
07318     case DCM_FD:                /* Floating double */
07319         element->multiplicity = element->length / 8;
07320         break;
07321     case DCM_AT:                /* Attribute tag */
07322     case DCM_FL:                /* Float */
07323     case DCM_SL:                /* Signed long */
07324     case DCM_UL:                /* Unsigned long */
07325         element->multiplicity = element->length / 4;
07326         break;
07327     case DCM_SS:                /* Signed short */
07328     case DCM_US:                /* Unsigned short */
07329         element->multiplicity = element->length / 2;
07330         break;
07331     case DCM_LT:                /* Long text */
07332     case DCM_OT:                /* Other binary value */
07333     case DCM_SQ:                /* Sequence of items */
07334     case DCM_ST:                /* Short text */
07335     /*case DCM_UNKNOWN:*/
07336     case DCM_UN:
07337     case DCM_RET:
07338     case DCM_CTX:
07339     case DCM_DD:                /* Data set */
07340     default:
07341         element->multiplicity = 1;
07342         break;
07343     }
07344 }
07345 /* ctxSensitiveLookup
07346 **
07347 ** Purpose:
07348 **      Lookup representation of elements that are context sensitive
07349 **
07350 ** Parameter Dictionary:
07351 **      object          Handle to the DICOM object containing this element.
07352 **      element         Element who representation is to be determined.
07353 **
07354 ** Return Values:
07355 **      None
07356 **
07357 ** Notes:
07358 **
07359 */
07360 static void
07361 ctxSensitiveLookup(PRIVATE_OBJECT ** object, DCM_ELEMENT * element)
07362 {
07363     switch (element->tag) {
07364         case DCM_IMGSMALLESTIMAGEPIXELVALUE:
07365         case DCM_IMGLARGESTIMAGEPIXELVALUE:
07366         case DCM_IMGSMALLESTPIXELVALUESERIES:
07367         case DCM_IMGLARGESTPIXELVALUESERIES:
07368         case DCM_IMGSMALLESTIMAGEPIXELVALUEPLANE:
07369         case DCM_IMGLARGESTIMAGEPIXELVALUEPLANE:
07370         case DCM_IMGLUTDESCRIPTOR:
07371         case DCM_IMGLUTDATA:
07372         case DCM_IMGLOOKUPDATARED:
07373         case DCM_IMGLOOKUPDATAGREEN:
07374         case DCM_IMGLOOKUPDATABLUE:
07375         if ((*object)->pixelRepresentation == 0x0000)
07376             element->representation = DCM_US;
07377         else if ((*object)->pixelRepresentation == 0x0001)
07378             element->representation = DCM_SS;
07379         else
07380             element->representation = DCM_US;
07381         break;
07382     case DCM_MAKETAG(0x003a, 0x1000):
07383         if (strcmp((*object)->waveformDataVR, "SS") == 0)
07384             element->representation = DCM_SS;
07385         break;
07386 
07387     default:
07388         break;
07389     }
07390 }
07391 
07392 static CONDITION
07393 copyData(PRIVATE_OBJECT ** object, PRV_ELEMENT_ITEM * from,
07394          DCM_ELEMENT * to, U32 * rtnLength)
07395 {
07396     unsigned char *p = NULL;
07397     U32 l;
07398     int nBytes;
07399     CONDITION cond;
07400 
07401     if (from->element.representation == DCM_SQ)
07402         return COND_PushCondition(DCM_CANNOTGETSEQUENCEVALUE,
07403                                   DCM_Message(DCM_CANNOTGETSEQUENCEVALUE),
07404                               from->element.tag, "copyData (DCM internal)");
07405 
07406     l = MIN(from->element.length, to->length);
07407     if (rtnLength != NULL)
07408         *rtnLength = l;
07409 
07410     if (from->element.d.ot == NULL) {
07411         if ((*object)->fd != -1) {
07412             (void) lseek((*object)->fd,
07413                          from->dataOffset + (off_t) p, SEEK_SET);
07414             nBytes = read((*object)->fd, to->d.ot, (int) l);
07415         } else {
07416             (*object)->sk((*object)->userCtx,
07417                           (long) (from->dataOffset + (off_t) p), SEEK_SET);
07418             cond = (*object)->rd((*object)->userCtx, to->d.ot, (long) l, &nBytes);
07419         }
07420         if (nBytes != (int) l) {
07421             return COND_PushCondition(DCM_FILEACCESSERROR,
07422                                       DCM_Message(DCM_FILEACCESSERROR),
07423                                       (*object)->fileName,
07424                                       "copyData (DCM internal)");
07425         }
07426         if( LITTLE_ENDIAN_ARCHITECTURE ){
07427           if (from->element.representation == DCM_AT) {
07428             DCM_ELEMENT e;
07429             e = from->element;
07430             e.length = l;
07431             e.d.ot = to->d.ot;
07432             swapATGroupElement(&e);
07433           }
07434         }
07435         if (from->byteOrder == BYTEORDER_REVERSE) {
07436             DCM_ELEMENT e;
07437             e = from->element;
07438             e.length = l;
07439             e.d.ot = to->d.ot;
07440             swapInPlace(object, &e);
07441         }
07442     } else {
07443         unsigned char *q;
07444         q = (unsigned char *) from->element.d.ot +
07445             (U32) p;
07446         (void) memcpy(to->d.ot, q, l);
07447     }
07448     p += l;
07449     if ((unsigned) p == from->element.length)
07450         return DCM_NORMAL;
07451     else
07452         return DCM_GETINCOMPLETE;
07453 }
07454 
07455 static CONDITION
07456 readLengthToEnd(int fd, const char *fileName,
07457                 unsigned long opt, U32 * lengthToEnd)
07458 {
07459     unsigned char buf[24];
07460     DCM_OBJECT *obj;
07461     CONDITION cond;
07462     DCM_ELEMENT e = {DCM_MAKETAG(0x0008, 0x0001), DCM_UL, "", 1, 4, NULL};
07463     void *ctx = NULL;
07464     U32 rtnLength = 0;
07465 
07466     if (read(fd, buf, 24) != 24)
07467         return COND_PushCondition(DCM_FILEACCESSERROR,
07468                                   DCM_Message(DCM_FILEACCESSERROR), fileName,
07469                                   "(DCM)readLengthToEnd");
07470 
07471     cond = DCM_ImportStream(buf, 24, opt, &obj);
07472     if (cond != DCM_NORMAL)
07473         return cond;
07474 
07475     e.d.ul = lengthToEnd;
07476     cond = DCM_GetElementValue(&obj, &e, &rtnLength, &ctx);
07477 
07478     (void) DCM_CloseObject(&obj);
07479 
07480     return cond;
07481 }
07482 
07483 static void
07484 swapATGroupElement(DCM_ELEMENT * e)
07485 {
07486     U32
07487     length;
07488     unsigned short
07489         tmp,
07490        *us;
07491 
07492     length = e->length;
07493     us = e->d.us;
07494     while (length >= 4) {
07495         tmp = us[0];
07496         us[0] = us[1];
07497         us[1] = tmp;
07498         us += 2;
07499         length -= 4;
07500     }
07501 }
07502 
07503 static void
07504 dumpSS(short *ss, long vm)
07505 {
07506     long index = 0;
07507     RWC_printf("decimal SS:") ;
07508     while (index < vm) {
07509         RWC_printf("%7d ", *(ss++));
07510         if ((++index) % 8 == 0)
07511             RWC_printf("\n");
07512     }
07513     RWC_printf("\n");
07514 }
07515 
07516 static void
07517 dumpSL(S32 * sl, long vm)
07518 {
07519     long index = 0;
07520     RWC_printf("decimal SL:") ;
07521     while (index < vm) {
07522         RWC_printf("%7d ", *(sl++));
07523         if ((++index) % 8 == 0)
07524             RWC_printf("\n");
07525     }
07526     RWC_printf("\n");
07527 }
07528 
07529 static void
07530 dumpUS(unsigned short *us, long vm)
07531 {
07532     long index = 0;
07533     RWC_printf("decimal US:") ;
07534     while (index < vm) {
07535         RWC_printf("%7d ", *(us++));
07536         if ((++index) % 8 == 0)
07537             RWC_printf("\n");
07538     }
07539     RWC_printf("\n");
07540 }
07541 static void
07542 dumpUL(U32 * ul, long vm)
07543 {
07544     long index = 0;
07545     RWC_printf("decimal UL:") ;
07546     while (index < vm) {
07547         RWC_printf("%7d ", *(ul++));
07548         if ((++index) % 8 == 0)
07549             RWC_printf("\n");
07550     }
07551     RWC_printf("\n");
07552 }
07553 static void
07554 dumpOB(unsigned char* c, long vm)
07555 {
07556   long index = 0;
07557   RWC_printf("hex OB:") ;
07558   while (index < vm) {
07559     RWC_printf("%02x ", *(c++));
07560     if ((++index) % 8 == 0)
07561       RWC_printf("\n");
07562   }
07563   if( index%8 != 0 ) RWC_printf("\n");
07564 }
07565 
07566 static void
07567 dumpBinaryData(void *d, DCM_VALUEREPRESENTATION vr, long vm,
07568                long vmLimit)
07569 {
07570     vm = (vm < vmLimit) ? vm : vmLimit;
07571 
07572     if (vm <= 1)
07573         return;
07574 
07575     switch (vr) {
07576     case DCM_SL:
07577         dumpSL((S32 *) d, vm);
07578         break;
07579     case DCM_UL:
07580         dumpUL((U32 *) d, vm);
07581         break;
07582     case DCM_SS:
07583         dumpSS((short *) d, vm);
07584         break;
07585     case DCM_US:
07586         dumpUS((unsigned short *) d, vm);
07587         break;
07588     case DCM_OB:
07589     case DCM_UN:
07590         dumpOB((unsigned char*) d, vm);
07591         break;
07592     default:
07593         break;
07594     }
07595 }
07596 
07597 static void
07598 compareGroup(PRV_GROUP_ITEM * g1, PRV_GROUP_ITEM * g2,
07599              void (*callback) (const DCM_ELEMENT * e1,
07600                                const DCM_ELEMENT * e2,
07601                                void *ctx),
07602              void *ctx)
07603 {
07604     PRV_ELEMENT_ITEM *e1 = NULL,
07605        *e2 = NULL;
07606 
07607     if (g1 != NULL) {
07608         e1 = (void *)LST_Head(&g1->elementList);
07609         if (e1 != NULL)
07610             LST_Position(&g1->elementList, (void *)e1);
07611     }
07612     if (g2 != NULL) {
07613         e2 = (void *)LST_Head(&g2->elementList);
07614         if (e2 != NULL)
07615             LST_Position(&g2->elementList, (void *)e2);
07616     }
07617     while (e1 != NULL) {
07618         if (e2 == NULL) {
07619             callback(&e1->element, NULL, ctx);
07620             e1 = (void *)LST_Next(&g1->elementList);
07621         } else if (e1->element.tag == e2->element.tag) {
07622             callback(&e1->element, &e2->element, ctx);
07623             e1 = (void *)LST_Next(&g1->elementList);
07624             e2 = (void *)LST_Next(&g2->elementList);
07625         } else if (e1->element.tag < e2->element.tag) {
07626             callback(&e1->element, NULL, ctx);
07627             e1 = (void *)LST_Next(&g1->elementList);
07628         } else {
07629             callback(NULL, &e2->element, ctx);
07630             e2 = (void *)LST_Next(&g2->elementList);
07631         }
07632     }
07633 
07634     while (e2 != NULL) {
07635         callback(NULL, &e2->element, ctx);
07636         e2 = (void *)LST_Next(&g2->elementList);
07637     }
07638 }
07639 
07640 static void
07641 remapFileName(const char *name, char *mapName)
07642 {
07643     char c;
07644 
07645     while ((c = *name++) != '\0') {
07646         if (c == '\\')
07647             *mapName++ = '/';
07648         else if (isupper(c))
07649             *mapName++ = tolower(c);
07650         else
07651             *mapName++ = c;
07652     }
07653     *mapName = '\0';
07654 }
07655 
07656 static void
07657 copySequence(PRIVATE_OBJECT ** dstObj, DCM_ELEMENT * e)
07658 {
07659     LST_HEAD *lst;
07660     DCM_SEQUENCE_ITEM *sqItem;
07661     DCM_ELEMENT newElement;
07662 
07663     lst = LST_Create();
07664     if (e->d.sq != NULL) {
07665         sqItem = (void *)LST_Head(&e->d.sq);
07666         (void) LST_Position(&e->d.sq, (void *)sqItem);
07667     }
07668     while (sqItem != NULL) {
07669         DCM_OBJECT *copy;
07670         DCM_SEQUENCE_ITEM *copyItem;
07671 
07672         DCM_CopyObject(&sqItem->object, &copy);
07673         copyItem = AFMALL( DCM_SEQUENCE_ITEM, sizeof(*copyItem));
07674         copyItem->object = copy;
07675         (void) LST_Enqueue(&lst, (void *)copyItem);
07676 
07677         sqItem = (void *)LST_Next(&e->d.sq);
07678     }
07679 
07680     memset(&newElement, 0, sizeof(newElement));
07681     newElement.tag = e->tag;
07682     newElement.representation = e->representation;
07683     newElement.d.sq = lst;
07684     DCM_AddSequenceElement((DCM_OBJECT **) dstObj, &newElement);
07685 }
07686 
07687 /* Restart public functions */
07688 
07689 CONDITION
07690 DCM_GetCompressedValue(DCM_OBJECT ** callerObject, DCM_TAG tag, void *buf,
07691                        size_t bufSize, DCM_GET_COMPRESSED_CALLBACK* callback,
07692                        void *ctx)
07693 {
07694     PRIVATE_OBJECT
07695         ** object;
07696     PRV_ELEMENT_ITEM
07697         * elementItem;
07698     S32 nBytes;
07699     S32 toRead;
07700     CONDITION cond;
07701     int doneFlag = 0;
07702     size_t elementLength;
07703     unsigned char *ptr;
07704     U32 size = 0;
07705     off_t fileOffset = 0;
07706     unsigned long opt;
07707     int byteOrder;
07708     int explicitVR;
07709     CTNBOOLEAN acceptVRMismatch = FALSE;
07710     DCM_ELEMENT e;
07711     U32 sequenceLength = 0;
07712     CONDITION flag;
07713     int index = 0;
07714     CTNBOOLEAN firstBuffer = TRUE;
07715     U32 *offsetBuffer = NULL;
07716     U32 offsetBufferCount = 0;
07717     U32 streamOffset = 0;
07718     int startOfFragment = 1;
07719 
07720     object = (PRIVATE_OBJECT **) callerObject;
07721     cond = checkObject(object, "DCM_GetCompressedValue");
07722     if (cond != DCM_NORMAL)
07723         return cond;
07724 
07725     elementItem = locateElement(object, tag);
07726 
07727     if (elementItem == NULL)
07728         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
07729                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
07730                                   DCM_TAG_ELEMENT(tag),
07731                                   "DCM_GetEncodedValue");
07732 
07733     elementLength = elementItem->originalDataLength;
07734     ptr = NULL;                 /* Means reading from a file */
07735     size = DCM_UNSPECIFIEDLENGTH;
07736     fileOffset = elementItem->dataOffset;
07737 
07738     opt |= (*object)->dataOptions & DCM_ORDERMASK;
07739     explicitVR = FALSE;
07740     switch (opt & DCM_ORDERMASK) {
07741     case DCM_ORDERNATIVE:
07742         byteOrder = NATIVE_ORDER;
07743         break;
07744     case DCM_ORDERLITTLEENDIAN:
07745         byteOrder = LITTLE_ORDER;
07746         break;
07747     case DCM_EXPLICITLITTLEENDIAN:
07748         byteOrder = LITTLE_ORDER;
07749         explicitVR = TRUE;
07750         break;
07751     case DCM_ORDERBIGENDIAN:
07752         byteOrder = BIG_ORDER;
07753         break;
07754     case DCM_EXPLICITBIGENDIAN:
07755         byteOrder = BIG_ORDER;
07756         explicitVR = TRUE;
07757         break;
07758     default:
07759         byteOrder = LITTLE_ORDER;
07760         explicitVR = TRUE;
07761         break;
07762     }
07763     if ((opt & DCM_VRMASK) == DCM_ACCEPTVRMISMATCH)
07764         acceptVRMismatch = TRUE;
07765 
07766     (void) lseek((*object)->fd, elementItem->dataOffset, SEEK_SET);
07767     while (elementLength != 0) {
07768         sequenceLength = 0;
07769         memset(&e, 0, sizeof(e));
07770         flag = readGroupElement("", &ptr, (*object)->fd, &size, &fileOffset,
07771                              FALSE, byteOrder, explicitVR, acceptVRMismatch,
07772                                 object, &sequenceLength, &e);
07773         if (flag == DCM_STREAMCOMPLETE)
07774             break;
07775         else if (flag != DCM_NORMAL)
07776             return flag;
07777 
07778         flag = readVRLength("", &ptr, (*object)->fd, &size, &fileOffset,
07779                             FALSE,      /* Known length */
07780                             byteOrder, explicitVR, acceptVRMismatch, object,
07781                             &sequenceLength, &e);
07782         if (flag != DCM_NORMAL)
07783             return flag;
07784 
07785         elementLength -= sequenceLength + e.length;
07786 
07787         if (firstBuffer) {
07788             firstBuffer = FALSE;
07789             if (e.length != 0) {
07790                 offsetBuffer = CTN_MALLOC(e.length);
07791                 offsetBufferCount = e.length / sizeof(U32);
07792                 if (offsetBuffer == NULL)
07793                     exit(1);    /* repair */
07794                 nBytes = read((*object)->fd, offsetBuffer, e.length);
07795                 if (nBytes != e.length) {
07796                     exit(1);    /* repair */
07797                 }
07798                 if (byteOrder == BYTEORDER_REVERSE) {
07799                     DCM_ELEMENT offsetBufferElement;
07800                     memset(&offsetBufferElement, 0, sizeof(DCM_ELEMENT));
07801                     offsetBufferElement.length = e.length;
07802                     offsetBufferElement.d.ul = offsetBuffer;
07803                     offsetBufferElement.representation = DCM_UL;
07804                     swapInPlace(object, &offsetBufferElement);
07805                 }
07806                 callback(offsetBuffer, e.length, index, 1, 0, 1, ctx);
07807                 streamOffset = 0;
07808             } else {
07809                 streamOffset = 0xffffffff;
07810             }
07811         } else {
07812             U32 l = e.length;
07813             int j;
07814             int lastIndex;
07815 
07816             lastIndex = index;
07817             for (j = 0; j < offsetBufferCount; j++) {
07818                 if (streamOffset == offsetBuffer[j])
07819                     index = j + 1;
07820             }
07821             startOfFragment = 1;
07822             while (l != 0) {
07823                 toRead = MIN(bufSize, l);
07824                 nBytes = read((*object)->fd, buf, toRead);
07825                 if (nBytes != toRead) {
07826                     exit(1);    /* repair */
07827                 }
07828                 callback(buf, toRead, index,
07829                          (index != lastIndex) ? 1 : 0,
07830                          0, startOfFragment, ctx);
07831                 l -= toRead;
07832                 lastIndex = index;      /* Guarantee first flag is off */
07833                 startOfFragment = 0;
07834             }
07835             streamOffset += sequenceLength + e.length;
07836         }
07837         fileOffset += e.length;
07838         index++;
07839     }
07840     callback(buf, 0, index, 0, 1, 1, ctx);
07841     return DCM_NORMAL;
07842 }
07843 
07844 CONDITION
07845 DCM_PrintSequenceList(DCM_OBJECT ** object, DCM_TAG tag)
07846 {
07847     PRIVATE_OBJECT **obj,
07848        *sqObject;
07849     CONDITION cond;
07850     PRV_ELEMENT_ITEM *elementItem;
07851     LST_HEAD *lst;
07852     DCM_SEQUENCE_ITEM *sqItem;
07853 
07854     obj = (PRIVATE_OBJECT **) object;
07855     cond = checkObject(obj, "DCM_PrintSequenceList");
07856     if (cond != DCM_NORMAL)
07857         return cond;
07858 
07859     elementItem = locateElement(obj, tag);
07860 
07861     if (elementItem == NULL)
07862         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
07863                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
07864                                   DCM_TAG_ELEMENT(tag),
07865                                   "DCM_PrintSequenceList");
07866 
07867     lst = elementItem->element.d.sq;
07868     sqItem = (void *)LST_Head(&lst);
07869     (void) LST_Position(&lst, (void *)sqItem);
07870     while (sqItem != NULL) {
07871         sqObject = (PRIVATE_OBJECT *) sqItem->object;
07872         RWC_printf("size: %6d offset: %6d, pixel offset: %6d\n",
07873                sqObject->objectSize,
07874                sqObject->offset,
07875                sqObject->pixelOffset);
07876         sqItem = (void *)LST_Next(&lst);
07877     }
07878 }
07879 
07880 CONDITION
07881 DCM_GetSequenceByOffset(DCM_OBJECT ** object, DCM_TAG tag, unsigned long offset,
07882                         DCM_OBJECT ** rtnObject)
07883 {
07884     PRIVATE_OBJECT **obj,
07885        *sqObject;
07886     CONDITION cond;
07887     PRV_ELEMENT_ITEM *elementItem;
07888     LST_HEAD *lst;
07889     DCM_SEQUENCE_ITEM *sqItem;
07890 
07891     obj = (PRIVATE_OBJECT **) object;
07892     cond = checkObject(obj, "DCM_PrintSequenceList");
07893     if (cond != DCM_NORMAL)
07894         return cond;
07895 
07896     elementItem = locateElement(obj, tag);
07897 
07898     if (elementItem == NULL)
07899         return COND_PushCondition(DCM_ELEMENTNOTFOUND,
07900                        DCM_Message(DCM_ELEMENTNOTFOUND), DCM_TAG_GROUP(tag),
07901                                   DCM_TAG_ELEMENT(tag),
07902                                   "DCM_PrintSequenceList");
07903 
07904     lst = elementItem->element.d.sq;
07905     sqItem = (void *)LST_Head(&lst);
07906     (void) LST_Position(&lst, (void *)sqItem);
07907     while (sqItem != NULL) {
07908         sqObject = (PRIVATE_OBJECT *) sqItem->object;
07909         if (sqObject->offset == offset) {
07910             *rtnObject = sqItem->object;
07911             return DCM_NORMAL;
07912         }
07913         sqItem = (void *)LST_Next(&lst);
07914     }
07915     return 0;
07916 }
07917 
07918 CONDITION
07919 DCM_CopyObject(DCM_OBJECT ** src, DCM_OBJECT ** dst)
07920 {
07921     PRIVATE_OBJECT **srcObj;
07922     PRIVATE_OBJECT *dstObj;
07923     PRV_GROUP_ITEM *groupItem;
07924     PRV_ELEMENT_ITEM *elementItem;
07925 
07926     if (src == NULL) {
07927         (void) COND_PushCondition(DCM_NULLADDRESS,
07928                             DCM_Message(DCM_NULLADDRESS), "DCM_CopyObject");
07929         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
07930                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CopyObject");
07931     }
07932     dstObj = (PRIVATE_OBJECT *) CTN_MALLOC(sizeof(PRIVATE_OBJECT));
07933     if (dstObj == NULL) {
07934         (void) COND_PushCondition(DCM_MALLOCFAILURE,
07935                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
07936                                   "DCM_CopyObject");
07937         *dst = NULL;
07938         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
07939                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_CopyObject");
07940     }
07941     (void) memset(dstObj, 0, sizeof(PRIVATE_OBJECT));
07942     (void) strcpy(dstObj->keyType, KEY_DCM_OBJECT);
07943 
07944     dstObj->objectType = DCM_OBJECTUNKNOWN;
07945     dstObj->accessMethod = DCM_MEMORY_ACCESS;
07946     dstObj->deleteFlag = FALSE;
07947     dstObj->groupLengthFlag = FALSE;
07948     dstObj->objectSize = 0;
07949     dstObj->offset = 0;
07950     dstObj->pixelSize = 0;
07951     dstObj->pixelOffset = 0;
07952     dstObj->pixelBitsAllocated = 0;
07953     dstObj->pixelRepresentation = 0xffff;
07954     dstObj->groupCtx = NULL;
07955     dstObj->elementCtx = NULL;
07956     dstObj->fd = -1;
07957     dstObj->fileName[0] = '\0';
07958     dstObj->preambleFlag = FALSE;
07959     dstObj->preamble[0] = '\0';
07960     dstObj->dataOptions = 0;
07961     dstObj->metaHeaderLength = 0xffffffff;
07962     dstObj->longVRAttributes = 0;
07963     dstObj->waveformDataVR[0] = '\0';
07964 
07965     dstObj->groupList = LST_Create();
07966     if (dstObj->groupList == NULL) {
07967         CTN_FREE(dstObj);
07968         *dst = NULL;
07969         return COND_PushCondition(DCM_LISTFAILURE,
07970                                   DCM_Message(DCM_LISTFAILURE),
07971                                   "DCM_CreateObject");
07972     }
07973     srcObj = (PRIVATE_OBJECT **) src;
07974 
07975     groupItem = (void *)LST_Head(&(*srcObj)->groupList);
07976     if (groupItem != NULL)
07977         (void) LST_Position(&(*srcObj)->groupList, (void *)groupItem);
07978 
07979     while (groupItem != NULL) {
07980         elementItem = (void *)LST_Head(&groupItem->elementList);
07981         if (elementItem != NULL)
07982             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
07983         while (elementItem != NULL) {
07984             if (elementItem->element.representation == DCM_SQ) {
07985                 copySequence(&dstObj, &elementItem->element);
07986             } else {
07987                 DCM_AddElement((DCM_OBJECT **) & dstObj, &elementItem->element);
07988             }
07989             elementItem = (void *)LST_Next(&groupItem->elementList);
07990         }
07991         groupItem = (void *)LST_Next(&(*srcObj)->groupList);
07992     }
07993 
07994     *dst = (DCM_OBJECT *) dstObj;
07995     return DCM_NORMAL;
07996 }
07997 
07998 CONDITION
07999 DCM_MergeObject(DCM_OBJECT ** src, DCM_OBJECT ** dst)
08000 {
08001     PRIVATE_OBJECT **srcObj;
08002     PRIVATE_OBJECT *dstObj;
08003     PRV_GROUP_ITEM *groupItem;
08004     PRV_ELEMENT_ITEM *elementItem;
08005 
08006     if (src == NULL) {
08007         (void) COND_PushCondition(DCM_NULLADDRESS,
08008                             DCM_Message(DCM_NULLADDRESS), "DCM_MergeObject");
08009         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
08010                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_MergeObject");
08011     }
08012     dstObj = *((PRIVATE_OBJECT **)dst);
08013     if (dstObj == NULL) {
08014         (void) COND_PushCondition(DCM_MALLOCFAILURE,
08015                      DCM_Message(DCM_MALLOCFAILURE), sizeof(PRIVATE_OBJECT),
08016                                   "DCM_MergeObject");
08017         *dst = NULL;
08018         return COND_PushCondition(DCM_OBJECTCREATEFAILED,
08019                      DCM_Message(DCM_OBJECTCREATEFAILED), "DCM_MergeObject");
08020     }
08021     srcObj = (PRIVATE_OBJECT **) src;
08022 
08023     groupItem = (void *)LST_Head(&(*srcObj)->groupList);
08024     if (groupItem != NULL)
08025         (void) LST_Position(&(*srcObj)->groupList, (void *)groupItem);
08026 
08027     while (groupItem != NULL) {
08028         elementItem = (void *)LST_Head(&groupItem->elementList);
08029         if (elementItem != NULL)
08030             (void) LST_Position(&groupItem->elementList, (void *)elementItem);
08031         while (elementItem != NULL) {
08032             if (elementItem->element.representation == DCM_SQ) {
08033                 copySequence(&dstObj, &elementItem->element);
08034             } else {
08035                 DCM_AddElement((DCM_OBJECT **) & dstObj, &elementItem->element);
08036             }
08037             elementItem = (void *)LST_Next(&groupItem->elementList);
08038         }
08039         groupItem = (void *)LST_Next(&(*srcObj)->groupList);
08040     }
08041 
08042     /**dst = (DCM_OBJECT *) dstObj;*/
08043     return DCM_NORMAL;
08044 }
08045 
08046 
08047 CONDITION
08048 DCM_GetFirstElement(DCM_OBJECT ** callerObject, DCM_ELEMENT** e)
08049 {
08050   PRIVATE_OBJECT** object;
08051   PRV_GROUP_ITEM* groupItem;
08052   PRV_ELEMENT_ITEM* elementItem;
08053   CONDITION cond;
08054 
08055   object = (PRIVATE_OBJECT **) callerObject;
08056   cond = checkObject(object, "DCM_GetFirstElement");
08057   if (cond != DCM_NORMAL)
08058     return cond;
08059 
08060   groupItem = (void *)LST_Head(&(*object)->groupList);
08061 
08062   if (groupItem == NULL) {
08063     *e = 0;
08064     return DCM_EMPTYOBJECT;
08065   }
08066   (void) LST_Position(&(*object)->groupList, (void *)groupItem);
08067   (*object)->groupCtx = groupItem;
08068 
08069   elementItem = (void *)LST_Head(&groupItem->elementList);
08070   (*object)->elementCtx = elementItem;
08071   if (elementItem == NULL) {
08072     return DCM_GetNextElement(callerObject, e);
08073   }
08074 
08075   *e = &elementItem->element;
08076   return DCM_NORMAL;
08077 }
08078 
08079 CONDITION
08080 DCM_GetNextElement(DCM_OBJECT ** callerObject, DCM_ELEMENT** e)
08081 {
08082   PRIVATE_OBJECT** object;
08083   PRV_GROUP_ITEM* groupItem;
08084   PRV_ELEMENT_ITEM* elementItem;
08085   CONDITION cond;
08086 
08087   object = (PRIVATE_OBJECT **) callerObject;
08088   cond = checkObject(object, "DCM_GetNextElement");
08089   if (cond != DCM_NORMAL)
08090     return cond;
08091 
08092   groupItem = (*object)->groupCtx;
08093   elementItem = (*object)->elementCtx;
08094 
08095   if (elementItem != 0) {
08096     (void)LST_Position(&groupItem->elementList, (void *)elementItem);
08097     elementItem = (PRV_ELEMENT_ITEM*)LST_Next(&groupItem->elementList);
08098   }
08099 
08100   if (elementItem == 0) {
08101     (void)LST_Position(&(*object)->groupList, (void *)groupItem);
08102     groupItem = (PRV_GROUP_ITEM*)LST_Next(&(*object)->groupList);
08103     if (groupItem != 0) {
08104       elementItem = (PRV_ELEMENT_ITEM*)LST_Head(&groupItem->elementList);
08105     }
08106   }
08107 
08108   if (groupItem == 0) {
08109     *e = 0;
08110     return DCM_GETNEXTELEMENTCOMPLETE;
08111   }
08112 
08113   (*object)->groupCtx = groupItem;
08114   (*object)->elementCtx = elementItem;
08115 
08116   if (elementItem == 0)
08117     return DCM_GetNextElement(callerObject, e);
08118 
08119   *e = &elementItem->element;
08120   return DCM_NORMAL;
08121 }
08122 
08123 CONDITION
08124 DCM_AddFragment(DCM_OBJECT** callerObject, void* fragment, U32 fragmentLength)
08125 {
08126   PRIVATE_OBJECT** object;
08127   PRV_ELEMENT_ITEM* elementItem;
08128   PRV_ELEMENT_ITEM* newItem;
08129   CONDITION cond;
08130   PRV_GROUP_ITEM *groupItem = 0;
08131   DCM_FRAGMENT_ITEM* fragmentItem;
08132   U32 mallocLength;
08133 
08134   if ((fragmentLength & 1) != 0) {
08135     return COND_PushCondition(DCM_UNEVENFRAGMENTLENGTH,
08136          DCM_Message(DCM_UNEVENFRAGMENTLENGTH), fragmentLength, "DCM_AddFragment");
08137   }
08138 
08139   object = (PRIVATE_OBJECT **) callerObject;
08140   cond = checkObject(object, "DCM_AddFragment");
08141   if (cond != DCM_NORMAL)
08142     return cond;
08143 
08144   cond = findCreateGroup(object, 0x7fe0, &groupItem);
08145   if (cond != DCM_NORMAL)
08146     return COND_PushCondition(DCM_INSERTFAILED,
08147          DCM_Message(DCM_INSERTFAILED), 0x7fe0, 0x0010, "DCM_AddFragment");
08148 
08149   elementItem = locateElement(object, 0x7fe00010);
08150   if (elementItem == NULL) {
08151     DCM_ELEMENT e;
08152     memset(&e, 0, sizeof(e));
08153     e.tag = DCM_PXLPIXELDATA;
08154     e.representation = DCM_OB;
08155     e.multiplicity = 1;
08156     e.length = 0;
08157     e.d.fragments = 0;
08158     cond = newElementItem(&e, FALSE, &newItem);
08159     if (cond != DCM_NORMAL)
08160       return cond;
08161     newItem->element.d.fragments = LST_Create();
08162     if (newItem->element.d.fragments == NULL) {
08163       return COND_PushCondition(DCM_LISTFAILURE,
08164                 DCM_Message(DCM_LISTFAILURE), "DCM_AddFragment");
08165     }
08166     cond = insertThisElementItem(object, newItem);
08167     if (cond != DCM_NORMAL)
08168       return cond;
08169   }
08170 
08171   elementItem = locateElement(object, 0x7fe00010);
08172 
08173   mallocLength = sizeof(DCM_FRAGMENT_ITEM) + fragmentLength;
08174   fragmentItem = CTN_MALLOC(mallocLength);
08175   if (fragmentItem == NULL) {
08176     return COND_PushCondition(DCM_MALLOCFAILURE,
08177                                 DCM_Message(DCM_MALLOCFAILURE), mallocLength,
08178                                 "DCM_AddFragment");
08179   }
08180 
08181   fragmentItem->fragment = ((char*)fragmentItem)+ sizeof(DCM_FRAGMENT_ITEM);
08182   fragmentItem->length = fragmentLength;
08183   memcpy(fragmentItem->fragment, fragment, fragmentLength);
08184   elementItem->fragmentFlag = 1;
08185   LST_Enqueue(&elementItem->element.d.fragments, (void *)fragmentItem);
08186 
08187   return DCM_NORMAL;
08188 }
08189 /*
08190           Copyright (C) 1993, 1994, RSNA and Washington University
08191 
08192           The software and supporting documentation for the Radiological
08193           Society of North America (RSNA) 1993, 1994 Digital Imaging and
08194           Communications in Medicine (DICOM) Demonstration were developed
08195           at the
08196                   Electronic Radiology Laboratory
08197                   Mallinckrodt Institute of Radiology
08198                   Washington University School of Medicine
08199                   510 S. Kingshighway Blvd.
08200                   St. Louis, MO 63110
08201           as part of the 1993, 1994 DICOM Central Test Node project for, and
08202           under contract with, the Radiological Society of North America.
08203 
08204           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
08205           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
08206           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
08207           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
08208           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
08209           THE SOFTWARE IS WITH THE USER.
08210 
08211           Copyright of the software and supporting documentation is
08212           jointly owned by RSNA and Washington University, and free access
08213           is hereby granted as a license to use this software, copy this
08214           software and prepare derivative works based upon this software.
08215           However, any distribution of this software source code or
08216           supporting documentation or derivative works (source code and
08217           supporting documentation) must include the three paragraphs of
08218           the copyright notice.
08219 */
08220 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
08221 
08222 /*
08223 **                              DICOM 93
08224 **                   Electronic Radiology Laboratory
08225 **                 Mallinckrodt Institute of Radiology
08226 **              Washington University School of Medicine
08227 **
08228 ** Module Name(s):      DCM_Message
08229 ** Author, Date:        Stephen M. Moore, 27-Apr-93
08230 ** Intent:              Define the ASCIZ messages that go with each DCM
08231 **                      error number and provide a function for looking up
08232 **                      the error message.
08233 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
08234 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
08235 ** Revision:            $Revision: 1.2 $
08236 ** Status:              $State: Exp $
08237 */
08238 
08239 typedef struct vector {
08240     CONDITION cond;
08241     char *message;
08242 }   VECTOR;
08243 
08244 static VECTOR messageVector[] = {
08245     {DCM_NORMAL, "Normal return from DCM routine"},
08246     {DCM_FILEOPENFAILED, "DCM failed to open file: %s in %s"},
08247     {DCM_FILEACCESSERROR, "DCM failed to access file: %s in %s"},
08248     {DCM_OBJECTCREATEFAILED, "DCM failed to create object in %s"},
08249     {DCM_NULLOBJECT, "NULL object passed to routine %s"},
08250     {DCM_ILLEGALOBJECT, "Illegal object passed to routine %s"},
08251     {DCM_ELEMENTNOTFOUND, "Requested element (%x %x) not found in %s"},
08252     {DCM_ILLEGALSTREAMLENGTH,
08253     "DCM Illegal Stream Length (%ld) (Not enough data to define a full element) in %s"},
08254     {DCM_ELEMENTCREATEFAILED, "DCM failed to create element in %s (%04x %04x %d)"},
08255     {DCM_UNRECOGNIZEDGROUP, "DCM unrecognized group: %04x in %s"},
08256     {DCM_UNRECOGNIZEDELEMENT, "DCM unrecognized element: (%04x %04x) in %s"},
08257     {DCM_ELEMENTOUTOFORDER, "DCM group/element out of order (%04x %04x) in %s"},
08258     {DCM_LISTFAILURE, "DCM routine failed on list operation in %s"},
08259     {DCM_ILLEGALOPTION, "DCM illegal stream option: %s"},
08260     {DCM_ILLEGALADD, "DCM attempt to add illegal element: %x %x in %s"},
08261     {DCM_GETINCOMPLETE, "DCM Get Element incomplete in %s"},
08262     {DCM_ILLEGALCONTEXT, "DCM Illegal context value in %s"},
08263     {DCM_ILLEGALREPRESENTATION,
08264     "DCM Caller specified illegal representation for element (%04x %04x) in %s"},
08265     {DCM_UNEVENELEMENTLENGTH,
08266     "DCM attempt to add data element (%x %x) with uneven length (%ld)  in %s"},
08267     {DCM_ELEMENTLENGTHERROR,
08268     "DCM Data Element (%04x %04x) longer (%ld) than remaining length (%ld) of \
08269 data in stream or file in %s"},
08270     {DCM_GROUPNOTFOUND, "Requested group (%x) not found in %s"},
08271     {DCM_FILECREATEFAILED, "DCM failed to create file %s (%s)"},
08272     {DCM_FILEIOERROR, "DCM io error on file %s (%s)"},
08273     {DCM_INSERTFAILED,
08274     "DCM failed to insert new element (%04x %04x) in %s"},
08275     {DCM_CANNOTGETSEQUENCEVALUE,
08276     "DCM Cannot retrieve value of element with SQ representation (%08x) in (%s)"},
08277     {DCM_FILEDELETEFAILED, "DCM Failed to delete file %s in %s"},
08278     {DCM_MALLOCFAILURE, "DCM Failed to malloc %ld bytes in %s"},
08279     {DCM_NULLADDRESS, "DCM NULL address passed to routine %s"},
08280     {DCM_UNEXPECTEDREPRESENTATION,
08281     "DCM Routine %s expected %s representation for element %04x %04x"},
08282     {DCM_BADELEMENTINGROUP,
08283     "DCM Bad element (%04x %04x) found in group %04x in %s"},
08284     {DCM_CALLBACKABORTED, "DCM Callback aborted by user in %s"},
08285     {DCM_READSTREAMFAILED, "DCM Failed to read stream in %s"},
08286     {DCM_UNRECOGNIZEDVRCODE, "DCM Unrecognized VR code (%s) in %s"},
08287     {DCM_VRMISMATCH, "DCM Incorrect VR (%s) for attribute with tag %08x"},
08288     {DCM_EXPORTBUFFERTOOSMALL,
08289     "DCM Caller's export buffer length (%d) is too short in %s"},
08290     {DCM_BADOFFSET,
08291     "DCM Offset value (%d) larger than attribute length (%d) in %s"},
08292     {DCM_BADLENGTH,
08293     "DCM Combination of offset, length (%d %d) is longer than element length (%d) in %s"},
08294     {DCM_NOTASEQUENCE,
08295     "DCM Attempt to perform sequence operation on element (%04x %04x) not a sequence in %s"},
08296     {DCM_GENERALWARNING, "DCM General warning in %s: %s"},
08297     {DCM_UNEVENFRAGMENTLENGTH,
08298     "DCM attempt to add fragment with uneven length (%ld) in %s"},
08299     {0, NULL}
08300 
08301 };
08302 
08303 
08304 /* DCM_Message
08305 **
08306 ** Purpose:
08307 **      Find the ASCIZ message that goes with an DCM error number and
08308 **      return a pointer to static memory containing that error message.
08309 **
08310 ** Parameter Dictionary:
08311 **      condition       The error condition for which the message is to be
08312 **                      returned
08313 **
08314 ** Return Values:
08315 **      The error message if a valid error condition was reported else NULL.
08316 **
08317 ** Algorithm:
08318 **      Description of the algorithm (optional) and any other notes.
08319 */
08320 
08321 char *
08322 DCM_Message(CONDITION condition)
08323 {
08324     int
08325         index;
08326 
08327     for (index = 0; messageVector[index].message != NULL; index++)
08328         if (condition == messageVector[index].cond)
08329             return messageVector[index].message;
08330 
08331     return NULL;
08332 }
08333 
08334 DCM_DumpVector()
08335 {
08336     int index;
08337 
08338     for (index = 0; index < (int) DIM_OF(messageVector); index++) {
08339         if (messageVector[index].message != NULL)
08340             RWC_printf("%8x %8d %s\n", messageVector[index].cond,
08341                    messageVector[index].cond,
08342                    messageVector[index].message);
08343     }
08344 }
08345 /*
08346           Copyright (C) 1993, 1994, RSNA and Washington University
08347 
08348           The software and supporting documentation for the Radiological
08349           Society of North America (RSNA) 1993, 1994 Digital Imaging and
08350           Communications in Medicine (DICOM) Demonstration were developed
08351           at the
08352                   Electronic Radiology Laboratory
08353                   Mallinckrodt Institute of Radiology
08354                   Washington University School of Medicine
08355                   510 S. Kingshighway Blvd.
08356                   St. Louis, MO 63110
08357           as part of the 1993, 1994 DICOM Central Test Node project for, and
08358           under contract with, the Radiological Society of North America.
08359 
08360           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
08361           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
08362           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
08363           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
08364           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
08365           THE SOFTWARE IS WITH THE USER.
08366 
08367           Copyright of the software and supporting documentation is
08368           jointly owned by RSNA and Washington University, and free access
08369           is hereby granted as a license to use this software, copy this
08370           software and prepare derivative works based upon this software.
08371           However, any distribution of this software source code or
08372           supporting documentation or derivative works (source code and
08373           supporting documentation) must include the three paragraphs of
08374           the copyright notice.
08375 */
08376 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
08377 
08378 /*
08379 **                              DICOM 93
08380 **                   Electronic Radiology Laboratory
08381 **                 Mallinckrodt Institute of Radiology
08382 **              Washington University School of Medicine
08383 **
08384 ** Module Name(s):      DCM_LookupElement(DCM_ELEMENT *element)
08385 ** Author, Date:        Stephen M. Moore, 30-Apr-93
08386 ** Intent:              This module contains the routine and data which
08387 **                      define the DICOM data dictionary.  A number of
08388 **                      static objects are maintained which define how
08389 **                      elements in the DICOM V3.0 standard are to be
08390 **                      interpreted.
08391 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
08392 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
08393 ** Revision:            $Revision: 1.2 $
08394 ** Status:              $State: Exp $
08395 */
08396 
08397 /*  The DCM dictionary consists of a list of lists.  Each group (COMMAND,
08398 **  IMAGE, ...) is defined in a list separately.  The object DCMDICT
08399 **  below is used to define the entry for a single data element in a
08400 **  known group.  We define the fields:
08401 **      element
08402 **      representation
08403 **      english Description
08404 **  The outer layer DCM dictionary consists of a list of groups.  The
08405 **  group entries define the "group" number and give a pointer to the
08406 **  DCMDICT list for that group.  The intent is to search the outer layer
08407 **  dictionary to find the proper group, then search the particular group
08408 **  list to find the proper element.
08409 */
08410 typedef struct {
08411     DCM_TAG tag;
08412     DCM_VALUEREPRESENTATION representation;
08413     char englishDescription[48];
08414 }   DCMDICT;
08415 
08416 typedef struct {
08417     unsigned short group;
08418     unsigned long entries;
08419     DCMDICT *dict;
08420 }   GROUPPTR;
08421 
08422 
08423 /*  Define the entries for the COMMAND group
08424 */
08425 static DCMDICT CMD_dictionary[] = {
08426     {DCM_CMDGROUPLENGTH, DCM_UL, "CMD Group Length"},
08427     {DCM_CMDAFFECTEDCLASSUID, DCM_UI, "CMD Affected SOP Class UID"},
08428     {DCM_CMDREQUESTEDCLASSUID, DCM_UI, "CMD Requested SOP Class UID"},
08429     {DCM_CMDCOMMANDFIELD, DCM_US, "CMD Command Field"},
08430     {DCM_CMDMSGID, DCM_US, "CMD Message ID"},
08431     {DCM_CMDMSGIDRESPOND, DCM_US, "CMD Message ID Responded to"},
08432     {DCM_CMDMOVEDESTINATION, DCM_AE, "CMD Move Destination"},
08433     {DCM_CMDPRIORITY, DCM_US, "CMD Priority"},
08434     {DCM_CMDDATASETTYPE, DCM_US, "CMD Data Set Type"},
08435     {DCM_CMDSTATUS, DCM_US, "CMD Status"},
08436     {DCM_CMDOFFENDINGELEMENT, DCM_AT, "CMD Offending Element"},
08437     {DCM_CMDERRORCOMMENT, DCM_LO, "CMD Error Comment"},
08438     {DCM_CMDERRORID, DCM_US, "CMD Error ID"},
08439     {DCM_CMDREQUESTEDINSTANCEUID, DCM_UI, "CMD SOP Requested Instance UID"},
08440     {DCM_CMDAFFECTEDINSTANCEUID, DCM_UI, "CMD SOP Affected Instance UID"},
08441     {DCM_CMDEVENTTYPEID, DCM_US, "CMD Event Type ID"},
08442     {DCM_CMDACTIONTYPEID, DCM_US, "CMD Action Type ID"},
08443     {DCM_CMDREMAININGSUBOPERATIONS, DCM_US, "CMD Remaining Suboperations"},
08444     {DCM_CMDCOMPLETEDSUBOPERATIONS, DCM_US, "CMD Completed Suboperations"},
08445     {DCM_CMDFAILEDSUBOPERATIONS, DCM_US, "CMD Failed Suboperations"},
08446     {DCM_CMDWARNINGSUBOPERATIONS, DCM_US, "CMD Warning Suboperations"},
08447     {DCM_CMDMOVEAETITLE, DCM_AE, "CMD AE Title"},
08448     {DCM_CMDMOVEMESSAGEID, DCM_US, "CMD Message ID"},
08449     {DCM_CMDATTRIBUTEIDLIST, DCM_AT, "CMD Attribute Identifier List"},
08450 
08451 };
08452 
08453 /* Define the entries for the file Meta Header group
08454 */
08455 
08456 static DCMDICT META_dictionary[] = {
08457     {DCM_METAGROUPLENGTH, DCM_UL, "META Group Length"},
08458     {DCM_METAINFORMATIONVERSION, DCM_OB, "META File Meta Information Version"},
08459     {DCM_METAMEDIASTORAGESOPCLASS, DCM_UI, "META Media Stored SOP Class UID"},
08460     {DCM_METAMEDIASTORAGESOPINSTANCE, DCM_UI, "META Media Stored SOP Instance UID"},
08461     {DCM_METATRANSFERSYNTAX, DCM_UI, "META Transfer Syntax UID"},
08462     {DCM_METAIMPLEMENTATIONCLASS, DCM_UI, "META Implementation Class UID"},
08463     {DCM_METAIMPLEMENTATIONVERSION, DCM_SH, "META Implementation Version Name"},
08464     {DCM_METASOURCEAETITLE, DCM_AE, "META Source Application Entity Title"},
08465     {DCM_METAPRIVATEINFORMATIONCREATOR, DCM_UI, "META Private Information Creator"},
08466     {DCM_METAPRIVATEINFORMATION, DCM_OB, "META Private Information"}
08467 };
08468 
08469 /* Define the elements in the Basic Directory Information Group, 0x0004 */
08470 
08471 static DCMDICT BASICDIR_dictionary[] = {
08472     {DCM_DIRFILESETID, DCM_CS, "DIR File-set ID"},
08473     {DCM_DIRFILESETDESCRFILEID, DCM_CS, "DIR File-set descriptor ID"},
08474     {DCM_DIRSPECIFICCHARACTER, DCM_CS, "DIR Specific character set"},
08475     {DCM_DIRFIRSTOFFSET, DCM_UL, "DIR Offset of the first dir of root dir entity"},
08476     {DCM_DIRLASTOFFSET, DCM_UL, "DIR Offset of the last dir of root dir entity"},
08477     {DCM_DIRFILESETCONSISTENCY, DCM_US, "DIR File-set consistency flag"},
08478     {DCM_DIRRECORDSEQUENCE, DCM_SQ, "DIR Directory record sequence"},
08479     {DCM_DIRNEXTRECORDOFFSET, DCM_UL, "DIR Offset of next directory record"},
08480     {DCM_DIRRECORDINUSE, DCM_US, "DIR Record in use flag"},
08481     {DCM_DIRLOWERLEVELOFFSET, DCM_UL, "DIR Offset of referenced lower-level dir entity"},
08482     {DCM_DIRRECORDTYPE, DCM_CS, "DIR Directory Record Type"},
08483     {DCM_DIRPRIVATERECORDUID, DCM_UI, "DIR Private Record UID"},
08484     {DCM_DIRREFERENCEDFILEID, DCM_CS, "DIR Referenced File ID"},
08485     {DCM_DIRMRDRRECORDOFFSET, DCM_UL, "DIR Directory Record Offset"},
08486     {DCM_DIRREFSOPCLASSUID, DCM_UI, "DIR Referenced SOP Class UID in File"},
08487     {DCM_DIRREFSOPINSTANCEUID, DCM_UI, "DIR Referenced SOP Instance UID in File"},
08488     {DCM_DIRREFTRANSFERSYNTAXUID, DCM_UI, "DIR Referenced Transfer Syntax in File"},
08489     {DCM_DIRNUMREFERENCES, DCM_UL, "DIR Number of References"}
08490 };
08491 
08492 /* Define the entries for the IDENTIFYING group
08493 */
08494 static DCMDICT ID_dictionary[] = {
08495     {DCM_IDGROUPLENGTH, DCM_UL, "ID Group Length"},
08496 /*    {DCM_IDLENGTHTOEND, DCM_RET, "ID Length to End (RET)"}, */
08497     {DCM_IDLENGTHTOEND, DCM_UL, "ID Length to End (RET)"},
08498     {DCM_IDSPECIFICCHARACTER, DCM_CS, "ID Specific Character Set"},
08499     {DCM_IDIMAGETYPE, DCM_CS, "ID Image Type"},
08500     {DCM_IDRECOGNITIONCODE, DCM_RET, "ID Recognition Code (RET)"},
08501     {DCM_IDINSTANCECREATEDATE, DCM_DA, "ID Instance Creation Date"},
08502     {DCM_IDINSTANCECREATETIME, DCM_TM, "ID Instance Creation Time"},
08503     {DCM_IDINSTANCECREATORUID, DCM_UI, "ID Instance Creator UID"},
08504     {DCM_IDSOPCLASSUID, DCM_UI, "ID SOP Class UID"},
08505     {DCM_IDSOPINSTANCEUID, DCM_UI, "ID SOP Instance UID"},
08506     {DCM_IDSTUDYDATE, DCM_DA, "ID Study Date"},
08507     {DCM_IDSERIESDATE, DCM_DA, "ID Series Date"},
08508     {DCM_IDACQUISITIONDATE, DCM_DA, "ID Acquisition Date"},
08509     {DCM_IDIMAGEDATE, DCM_DA, "ID Image Date"},
08510     {DCM_IDOVERLAYDATE, DCM_DA, "ID Overlay Date"},
08511     {DCM_IDCURVEDATE, DCM_DA, "ID Curve Date"},
08512     {DCM_IDSTUDYTIME, DCM_TM, "ID Study Time"},
08513     {DCM_IDSERIESTIME, DCM_TM, "ID Series Time"},
08514     {DCM_IDACQUISITIONTIME, DCM_TM, "ID Acquisition Time"},
08515     {DCM_IDIMAGETIME, DCM_TM, "ID Image Time"},
08516     {DCM_IDOVERLAYTIME, DCM_TM, "ID Overlay Time"},
08517     {DCM_IDCURVETIME, DCM_TM, "ID Curve Time"},
08518     {DCM_IDDATASETTYPE, DCM_RET, "ID Data Set Type (RET)"},
08519     {DCM_IDDATASETSUBTYPE, DCM_RET, "ID Data Set Subtype (RET)"},
08520     {DCM_IDNMSERIESTYPE, DCM_CS, "ID Nuc Med Series Type (RET)"},
08521     {DCM_IDACCESSIONNUMBER, DCM_SH, "ID Accession Number"},
08522     {DCM_IDQUERYLEVEL, DCM_CS, "ID Query Level"},
08523     {DCM_IDRETRIEVEAETITLE, DCM_AE, "ID Retrieve AE Title"},
08524     {DCM_IDINSTANCEAVAILABILITY, DCM_CS, "ID Instance Availability"},
08525     {DCM_IDFAILEDINSTANCEUIDLIST, DCM_UI, "ID Failed SOP Instances"},
08526     {DCM_IDMODALITY, DCM_CS, "ID Modality"},
08527     {DCM_IDMODALITIESINSTUDY, DCM_CS, "ID Modalities in Study"},
08528     {DCM_IDMODALITYSUBTYPE, DCM_SQ, "ID Modality Subtype"},     /* Sup 30 0.6 */
08529     {DCM_IDPRESENTATIONINTENTTYPE, DCM_CS, "ID Presentation Intent Type"},
08530     {DCM_IDCONVERSIONTYPE, DCM_CS, "ID Conversion Type"},
08531     {DCM_IDMANUFACTURER, DCM_LO, "ID Manufacturer"},
08532     {DCM_IDINSTITUTIONNAME, DCM_LO, "ID Institution Name"},
08533     {DCM_IDINSTITUTIONADDR, DCM_ST, "ID Institution Address"},
08534     {DCM_IDINSTITUTECODESEQUENCE, DCM_SQ, "ID Institution Code Sequence"},
08535     {DCM_IDREFERRINGPHYSICIAN, DCM_PN, "ID Referring Physician's Name"},
08536     {DCM_IDREFERRINGPHYSADDR, DCM_ST, "ID Referring Physician's Address"},
08537     {DCM_IDREFERRINGPHYSPHONE, DCM_SH, "ID Referring Physician's Telephone"},
08538     {DCM_IDCODEVALUE, DCM_SH, "ID Code Value"},
08539     {DCM_IDCODINGSCHEMEDESIGNATOR, DCM_SH, "ID Coding Scheme Designator"},
08540     {DCM_IDCODINGSCHEMEVERSION, DCM_SH, "ID Coding Scheme Version"},
08541     /* Sup 15, Version 1.2_interim_971226 */
08542     {DCM_IDCODEMEANING, DCM_LO, "ID Code Meaning"},
08543     {DCM_IDMAPPINGRESOURCE, DCM_CS, "ID Mapping Resource"},     /* Sup 15, 1.1a */
08544     {DCM_IDCONTEXTGROUPVERSION, DCM_DT, "ID Context Group Version"},
08545     /* Sup 15, Version 1.1a */
08546     {DCM_IDCODESETEXTENSIONFLAG, DCM_CS, "ID Code Set Extension Flag"},
08547     /* 0x010B: Sup 15, Version 1.a */
08548     {DCM_IDPRIVATECODINGSCHEMECREATORUID, DCM_UI, "ID Private Coding Scheme Creator UID"},
08549     /* 0x010C: Sup 15, Version 1.1 */
08550     {DCM_IDCODESETEXTENSIONCREATORUID, DCM_UI, "ID Coding Scheme Creator UID"},
08551     /* 0x010D: Sup 15, Version 1.1 */
08552     {DCM_IDMAPPINGRESOURCESEQ, DCM_SQ, "ID Mapping Resource Sequence"},
08553     /* Sup 15, Version 1.1 */
08554     {DCM_IDCONTEXTIDENTIFIER, DCM_CS, "ID Context Identifier"}, /* Sup 15 */
08555     {DCM_IDNETWORKID, DCM_LO, "ID Network ID (RET)"},
08556     {DCM_IDSTATIONNAME, DCM_SH, "ID Station Name"},
08557     {DCM_IDSTUDYDESCRIPTION, DCM_LO, "ID Study Description"},
08558     {DCM_IDPROCEDURECODESEQUENCE, DCM_SQ, "ID Procedure Code Sequence"},
08559     {DCM_IDSERIESDESCR, DCM_LO, "ID Series Description"},
08560     {DCM_IDINSTITUTIONALDEPT, DCM_LO, "ID Institutional Department Name"},
08561     {DCM_IDPHYSICIANOFRECORD, DCM_PN, "ID Physician of Record"},
08562     {DCM_IDPERFORMINGPHYSICIAN, DCM_PN, "ID Performing Physician's Name"},
08563     {DCM_IDPHYSREADINGSTUDY, DCM_PN, "ID Name of Physician(s) Reading Study"},
08564     {DCM_IDOPERATORNAME, DCM_PN, "ID Operator's Name"},
08565     {DCM_IDADMITTINGDIAGDESCR, DCM_LO, "ID Admitting Diagnoses Description"},
08566     {DCM_IDADMITDIAGCODESEQUENCE, DCM_SQ, "ID Admitting Diagnosis Code Sequence"},
08567     {DCM_IDMANUFACTURERMODEL, DCM_LO, "ID Manufacturer Model Name"},
08568     {DCM_IDREFERENCEDRESULTSSEQ, DCM_SQ, "ID Referenced Results Sequence"},
08569     {DCM_IDREFERENCEDSTUDYSEQ, DCM_SQ, "ID Referenced Study Sequence"},
08570     {DCM_IDREFERENCEDSTUDYCOMPONENTSEQ, DCM_SQ, "ID Referenced Study Component Sequence"},
08571     {DCM_IDREFERENCEDSERIESSEQ, DCM_SQ, "ID Referenced Series Sequence"},
08572     {DCM_IDREFERENCEDPATIENTSEQ, DCM_SQ, "ID Referenced Patient Sequence"},
08573     {DCM_IDREFERENCEDVISITSEQ, DCM_SQ, "ID Referenced Visit Sequence"},
08574     {DCM_IDREFERENCEDOVERLAYSEQ, DCM_SQ, "ID Referenced Overlay Sequence"},
08575     {DCM_IDREFERENCEDIMAGESEQ, DCM_SQ, "ID Referenced Image Sequence"},
08576     {DCM_IDREFERENCEDCURVESEQ, DCM_SQ, "ID Referenced Curve Sequence"},
08577     {DCM_IDREFERENCEDPREVIOUSWAVEFORM, DCM_SQ, "ID Referenced Previous Waveform"},      /* Sup 30 0.6 */
08578     {DCM_IDREFERENCEDSIMULTANEOUSWAVEFORMS, DCM_SQ, "ID Referenced Simultaneous Waveforms"},    /* Sup 30 0.6 */
08579     {DCM_IDREFERENCEDSUBSEQUENTWAVEFORM, DCM_SQ, "ID Referenced Subsequent Waveform"},  /* Sup 30 0.6 */
08580     {DCM_IDREFERENCEDSOPCLASSUID, DCM_UI, "ID Referenced SOP Class UID"},
08581     {DCM_IDREFERENCEDSOPINSTUID, DCM_UI, "ID Referenced SOP Instance UID"},
08582     {DCM_IDREFERENCEDFRAMENUMBER, DCM_IS, "ID Referenced Frame Number"},
08583     {DCM_IDTRANSACTIONUID, DCM_UI, "ID Transaction UID"},
08584     {DCM_IDFAILUREREASON, DCM_US, "ID Failure Reason"},
08585     {DCM_IDFAILEDSOPSEQUENCE, DCM_SQ, "ID Failed SOP Sequence"},
08586     {DCM_IDREFERENCEDSOPSEQUENCE, DCM_SQ, "ID Referenced SOP Sequence"},
08587     {DCM_IDLOSSYIMAGECOMPRESSION, DCM_CS, "ID Lossy Image Compression (RET)"},
08588     {DCM_IDDERIVATIONDESCR, DCM_ST, "ID Derivation Description"},
08589     {DCM_IDSOURCEIMAGESEQ, DCM_SQ, "ID Source Image Sequence"},
08590     {DCM_IDSTAGENAME, DCM_SH, "ID Stage Name"},
08591     {DCM_IDSTAGENUMBER, DCM_IS, "ID Stage Number"},
08592     {DCM_IDNUMBEROFSTAGES, DCM_IS, "ID Number of Stages"},
08593     {DCM_IDVIEWNUMBER, DCM_IS, "ID View Number"},
08594     {DCM_IDNUMBEROFEVENTTIMERS, DCM_IS, "ID Number of Event Timers"},
08595     {DCM_IDNUMBERVIEWSINSTAGE, DCM_IS, "ID Number of Views in Stage"},
08596     {DCM_IDEVENTELAPSEDTIME, DCM_DS, "ID Event Elapsed Time(s)"},
08597     {DCM_IDEVENTTIMERNAME, DCM_LO, "ID Event Event Timer Name(s)"},
08598     {DCM_IDSTARTTRIM, DCM_IS, "ID Start Trim"},
08599     {DCM_IDSTOPTRIM, DCM_IS, "ID Stop Trim"},
08600     {DCM_IDDISPLAYFRAMERATE, DCM_IS, "ID Recommended Display Frame Rate"},
08601     {DCM_IDTRANSDUCERPOSITION, DCM_CS, "ID Transducer Position (RET)"},
08602     {DCM_IDTRANSDUCERORIENTATION, DCM_CS, "ID Transducer Orientation (RET)"},
08603     {DCM_IDANATOMICSTRUCTURE, DCM_CS, "ID Anatomic Structure (RET)"},
08604     {DCM_IDANATOMICREGIONSEQUENCE, DCM_SQ, "ID Anatomic Region of Interest Sequence"},
08605     {DCM_IDANATOMICREGIONMODIFIERSEQ, DCM_SQ,
08606     "ID Anatomic Region Modifier Sequence"},
08607     {DCM_IDPRIMARYANATOMICSTRUCTURESEQ, DCM_SQ,
08608     "ID Primary Anatomic Structure Sequence"},
08609     {DCM_IDPRIMARYANATOMICSTRUCTUREMODIFIERSEQ, DCM_SQ,
08610     "ID Primary Anatomic Structure Modifier Sequence"},
08611     {DCM_IDTRANSDUCERPOSITIONSEQ, DCM_SQ, "ID Transducer Position Sequence"},
08612     {DCM_IDTRANSDUCERPOSITIONMODIFIERSEQ, DCM_SQ, "ID Transducer Position Modifer Sequence"},
08613     {DCM_IDTRANSDUCERORIENTATIONSEQ, DCM_SQ, "ID Transducer Orientation Sequence"},
08614     {DCM_IDTRANSDUCERORIENTATIONMODIFIERSEQ, DCM_SQ, "ID Transducer Orientation Modifer Sequence"},
08615     {DCM_IDCOMMENTS, DCM_RET, "ID Comments (RET)"}
08616 };
08617 
08618 /* Define the entries for the PATIENT INFORMATION group
08619 */
08620 static DCMDICT PAT_dictionary[] = {
08621     {DCM_PATGROUPLENGTH, DCM_UL, "PAT Group Length"},
08622     {DCM_PATNAME, DCM_PN, "PAT Patient Name"},
08623     {DCM_PATID, DCM_LO, "PAT Patient ID"},
08624     {DCM_ISSUERPATIENTID, DCM_LO, "PAT Issuer of Patient ID"},
08625     {DCM_PATBIRTHDATE, DCM_DA, "PAT Patient Birthdate"},
08626     {DCM_PATBIRTHTIME, DCM_TM, "PAT Patient Birth Time"},
08627     {DCM_PATSEX, DCM_CS, "PAT Patient Sex"},
08628     {DCM_PATINSURANCEPLANCODESEQ, DCM_SQ, "PAT Patient's Insurance Plan Code Sequence"},
08629     {DCM_PATOTHERIDS, DCM_LO, "PAT Other Patient IDs"},
08630     {DCM_PATOTHERNAMES, DCM_PN, "PAT Other Patient Names"},
08631     {DCM_PATBIRTHNAME, DCM_PN, "PAT Patient's Birth Name "},
08632     {DCM_PATAGE, DCM_AS, "PAT Patient Age"},
08633     {DCM_PATSIZE, DCM_DS, "PAT Patient Size"},
08634     {DCM_PATWEIGHT, DCM_DS, "PAT Patient Weight"},
08635     {DCM_PATADDRESS, DCM_LO, "PAT Patient Address"},
08636     {DCM_PATINSURANCEPLANID, DCM_RET, "PAT Insurance Plan Identifier"},
08637     {DCM_PATMOTHERBIRTHNAME, DCM_PN, "PAT Patient's Mother's Birth Name"},
08638     {DCM_PATMILITARYRANK, DCM_LO, "PAT Military Rank"},
08639     {DCM_PATBRANCHOFSERVICE, DCM_LO, "PAT Branch of Service"},
08640     {DCM_PATMEDICALRECORDLOCATOR, DCM_LO, "PAT Medical Record Locator"},
08641     {DCM_PATMEDICALALERTS, DCM_LO, "PAT Medical Alerts"},
08642     {DCM_PATCONTRASTALLERGIES, DCM_LO, "PAT Contrast Allergies"},
08643     {DCM_COUNTRYOFRESIDENCE, DCM_LO, "PAT Country of Residence"},
08644     {DCM_REGIONOFRESIDENCE, DCM_LO, "PAT Region of Residence"},
08645     {DCM_PATTELEPHONENUMBER, DCM_SH, "PAT Patient's Telephone Numbers"},
08646     {DCM_PATETHNICGROUP, DCM_SH, "PAT Ethnic Group"},
08647     {DCM_PATOCCUPATION, DCM_SH, "PAT Occupation"},
08648     {DCM_PATSMOKINGSTATUS, DCM_CS, "PAT Smoking Status"},
08649     {DCM_PATADDITIONALPATHISTORY, DCM_LT, "PAT Additional Patient History"},
08650     {DCM_PATPREGNANCYSTATUS, DCM_US, "PAT Pregnancy Status"},
08651     {DCM_PATLASTMENSTRUALDATE, DCM_DA, "PAT Last Menstrual Date"},
08652     {DCM_PATRELIGIOUSPREFERENCE, DCM_LO, "PAT Religious Preference"},
08653     {DCM_PATCOMMENTS, DCM_LT, "PAT Comments"}
08654 };
08655 
08656 /* Define the entries for the ACQUISITION group, 0018
08657 */
08658 
08659 static DCMDICT ACQ_dictionary[] = {
08660     {DCM_ACQGROUPLENGTH, DCM_UL, "ACQ Group Length"},
08661     {DCM_ACQCONTRASTBOLUSAGENT, DCM_LO, "ACQ Contrast/Bolus Agent"},
08662     {DCM_ACQCONTRASTBOLUSAGENTSEQ, DCM_SQ, "ACQ Contrast/Bolus Agent Sequence"},
08663     {DCM_ACQCONTRASTBOLUSADMINROUTESEQ, DCM_SQ, "ACQ Contrast/Bolus Administration Route Seq"},
08664     {DCM_ACQBODYPARTEXAMINED, DCM_CS, "ACQ Body Part Examined"},
08665     {DCM_ACQSCANNINGSEQUENCE, DCM_CS, "ACQ Scanning Sequence"},
08666     {DCM_ACQSEQUENCEVARIANT, DCM_CS, "ACQ Sequence Variant"},
08667     {DCM_ACQSCANOPTIONS, DCM_CS, "ACQ Scan Options"},
08668     {DCM_ACQMRACQUISITIONTYPE, DCM_CS, "ACQ MR Acquisition Type "},
08669     {DCM_ACQSEQUENCENAME, DCM_SH, "ACQ Sequence Name"},
08670     {DCM_ACQANGIOFLAG, DCM_CS, "ACQ Angio Flag"},
08671     {DCM_ACQINTERVENTIONDRUGINFOSEQ, DCM_SQ, "ACQ Intervention Drug Information Sequence"},
08672     {DCM_ACQINTERVENTIONDRUGSTOPTIME, DCM_TM, "ACQ Intervention Drug Stop Time"},
08673     {DCM_ACQINTERVENTIONDRUGDOSE, DCM_DS, "ACQ Intervention Drug Dose"},
08674     {DCM_ACQINTERVENTIONDRUGCODESEQ, DCM_SQ, "ACQ Intervention Drug Code Sequence"},
08675     {DCM_ACQADDITIONALDRUGSEQ, DCM_SQ, "ACQ Additional Drug Sequence"},
08676     {DCM_ACQRADIONUCLIDE, DCM_LO, "ACQ Radionuclide (RET)"},
08677     {DCM_ACQRADIOPHARMACEUTICAL, DCM_LO, "ACQ Radiopharmaceutical"},
08678     {DCM_ACQENERGYWCENTERLINE, DCM_DS, "ACQ Energy Window Centerline (RET)"},
08679     {DCM_ACQENERGYWTOTALWIDTH, DCM_DS, "ACQ Energy Window Total Width (RET)"},
08680     {DCM_ACQINTERVENTIONDRUGNAME, DCM_LO, "ACQ Intervention Drug Name"},
08681     {DCM_ACQINTERVENTIONDRUGSTART, DCM_TM, "ACQ Intervention Drug Start Time"},
08682     {DCM_ACQINTERVENTIONALTHERAPYSEQ, DCM_SQ, "ACQ Interventional Therapy Sequence"},
08683     {DCM_ACQTHERAPYTYPE, DCM_CS, "ACQ Therapy type"},
08684     {DCM_ACQINTERVENTIONALSTATUS, DCM_CS, "ACQ Interventional status"},
08685     {DCM_ACQTHERAPYDESCRIPTION, DCM_CS, "ACQ Therapy descriptionm"},
08686     {DCM_ACQCINERATE, DCM_IS, "ACQ Cine Rate"},
08687     {DCM_ACQSLICETHICKNESS, DCM_DS, "ACQ Slice Thickness"},
08688     {DCM_ACQKVP, DCM_DS, "ACQ KVP"},
08689     {DCM_ACQCOUNTSACCUMULATED, DCM_IS, "ACQ Counts Accumulated"},
08690     {DCM_ACQTERMINATIONCONDITION, DCM_CS, "ACQ Acquisition Termination Condition"},
08691     {DCM_ACQEFFECTIVESERIESDURATION, DCM_DS, "ACQ Effective Series Duration"},
08692     {DCM_ACQSTARTCONDITION, DCM_CS, "ACQ Start Condition"},
08693     {DCM_ACQSTARTCONDITIONDATA, DCM_IS, "ACQ Start Condition Data"},
08694     {DCM_ACQTERMINATIONCONDITIONDATA, DCM_IS, "ACQ Termination Condition Data"},
08695     {DCM_ACQREPETITIONTIME, DCM_DS, "ACQ Repetition Time"},
08696     {DCM_ACQECHOTIME, DCM_DS, "ACQ Echo Time"},
08697     {DCM_ACQINVERSIONTIME, DCM_DS, "ACQ Inversion Time"},
08698     {DCM_ACQNUMBEROFAVERAGES, DCM_DS, "ACQ Number of Averages"},
08699     {DCM_ACQIMAGINGFREQUENCY, DCM_DS, "ACQ Imaging Frequency"},
08700     {DCM_ACQIMAGEDNUCLEUS, DCM_SH, "ACQ Imaged Nucleus"},
08701     {DCM_ACQECHONUMBER, DCM_IS, "ACQ Echo Number"},
08702     {DCM_ACQMAGNETICFIELDSTRENGTH, DCM_DS, "ACQ Magnetic Field Strength"},
08703     {DCM_ACQSLICESPACING, DCM_DS, "ACQ Spacing Between Slices"},
08704     {DCM_ACQPHASEENCODINGSTEPS, DCM_IS, "ACQ Number of Phase Encoding Steps"},
08705     {DCM_ACQDATACOLLECTIONDIAMETER, DCM_DS, "ACQ Data Collection Diameter"},
08706     {DCM_ACQECHOTRAINLENGTH, DCM_IS, "ACQ Echo Train Length"},
08707     {DCM_ACQPERCENTSAMPLING, DCM_DS, "ACQ Percent Sampling"},
08708     {DCM_ACQPERCENTPHASEFIELDVIEW, DCM_DS, "ACQ Percent Phase Field of View"},
08709     {DCM_ACQPIXELBANDWIDTH, DCM_DS, "ACQ Pixel Bandwidth"},
08710     {DCM_ACQDEVICESERIALNUM, DCM_LO, "ACQ Device Serial Number"},
08711     {DCM_ACQPLATEID, DCM_LO, "ACQ Plate ID"},
08712     {DCM_ACQSECONDARYCAPTUREDEVID, DCM_LO, "ACQ Secondary Capture Device ID"},
08713     {DCM_ACQDATESECONDARYCAPTURE, DCM_DA, "ACQ Date of Secondary Capture"},
08714     {DCM_ACQTIMESECONDARYCAPTURE, DCM_TM, "ACQ Time of Secondary Capture"},
08715     {DCM_ACQSECONDARYCAPTMANUFACTURER, DCM_LO,
08716     "ACQ Secondary Capture Device Manufacturer"},
08717     {DCM_ACQSECONDARYCAPTMODEL, DCM_LO, "ACQ Secondary Capture Device Model Name"},
08718     {DCM_ACQSECONDARYCAPTSOFTWAREVERSION, DCM_LO,
08719     "ACQ Secondary Capture Device Software Version"},
08720     {DCM_ACQSOFTWAREVERSION, DCM_LO, "ACQ Software Version"},
08721     {DCM_ACQVIDEOIMAGEFORMATACQ, DCM_SH, "ACQ Video Image Format Acquired"},
08722     {DCM_ACQDIGITALIMAGEFORMATACQ, DCM_LO, "ACQ Digital Image Format Acquired"},
08723     {DCM_ACQPROTOCOLNAME, DCM_LO, "ACQ Protocol Name"},
08724     {DCM_ACQCONTRASTBOLUSROUTE, DCM_LO, "ACQ Contrast/Bolus Route"},
08725     {DCM_ACQCONTRASTBOLUSVOL, DCM_DS, "ACQ Contrast/Bolus Volume"},
08726     {DCM_ACQCONTRASTBOLUSSTARTTIME, DCM_TM, "ACQ Contrast/Bolus Start Time"},
08727     {DCM_ACQCONTRASTBOLUSSTOPTIME, DCM_TM, "ACQ Contrast/Bolus Stop Time"},
08728     {DCM_ACQCONTRASTBOLUSTOTALDOSE, DCM_DS, "ACQ Contrast/Bolus Total Dose"},
08729     {DCM_ACQSYRINGECOUNTS, DCM_IS, "ACQ Syringe Counts"},
08730     {DCM_ACQCONTRASTFLOWRATE, DCM_DS, "ACQ Contrast Flow Rate (ml/sec)"},
08731     {DCM_ACQCONTRASTFLOWDURATION, DCM_DS, "ACQ Contrast Flow Duration (sec)"},
08732     {DCM_ACQCONTRASTBOLUSINGREDIENT, DCM_CS, "ACQ Contrast Bolus Ingredient"},
08733     {DCM_ACQCONTRASTBOLUSINGREDIENTCONCENTRATION, DCM_DS, "ACQ Contrast Bolus Ingredient Concentration"},
08734     {DCM_ACQSPATIALRESOLUTION, DCM_DS, "ACQ Spatial Resolution"},
08735     {DCM_ACQTRIGGERTIME, DCM_DS, "ACQ Trigger Time"},
08736     {DCM_ACQTRIGGERSRCTYPE, DCM_LO, "ACQ Trigger Source or Type"},
08737     {DCM_ACQNOMINALINTERVAL, DCM_IS, "ACQ Nominal Interval"},
08738     {DCM_ACQFRAMETIME, DCM_DS, "ACQ Frame Time"},
08739     {DCM_ACQFRAMINGTYPE, DCM_LO, "ACQ Framing Type"},
08740     {DCM_ACQFRAMETIMEVECTOR, DCM_DS, "ACQ Frame Time Vector"},
08741     {DCM_ACQFRAMEDELAY, DCM_DS, "ACQ Frame Delay"},
08742     {DCM_ACQIMAGETRIGGERDELAY, DCM_DS, "ACQ Image Trigger Delay"},      /* Sup 30 0.6 */
08743     {DCM_ACQGROUPTIMEOFFSET, DCM_DS, "ACQ Group Time Offset"},  /* Sup 30 0.6 */
08744     {DCM_ACQTRIGGERTIMEOFFSET, DCM_DS, "ACQ Trigger Time Offset"},      /* Sup 30 0.6 */
08745     {DCM_ACQSYNCTRIGGER, DCM_CS, "ACQ Synchronization Trigger"},        /* Sup 30 0.6 */
08746     {DCM_ACQSYNCFRAMEOFREFERENCE, DCM_UI, "ACQ Synchronization Frame of Reference"},    /* Sup 30 0.6 */
08747     {DCM_ACQTRIGGERSAMPLEPOSITION, DCM_UL, "ACQ Trigger Sample Position"},      /* Sup 30 0.6 */
08748     {DCM_ACQRADIOPHARMROUTE, DCM_LO, "ACQ Radiopharmaceutical Route"},
08749     {DCM_ACQRADIOPHARMVOLUME, DCM_DS, "ACQ Radiopharmaceutical Volume"},
08750     {DCM_ACQRADIOPHARMSTARTTIME, DCM_TM, "ACQ Radiopharmaceutical Start Time"},
08751     {DCM_ACQRADIOPHARMSTOPTIME, DCM_TM, "ACQ Radiopharmaceutical Stop Time"},
08752     {DCM_ACQRADIONUCLIDETOTALDOSE, DCM_DS, "ACQ Radionuclide Total Dose"},
08753     {DCM_ACQRADIONUCLIDEHALFLIFE, DCM_DS, "ACQ Radionuclide Half Life"},
08754     {DCM_ACQRADIONUCLIDEPOSITRONFRACTION, DCM_DS, "ACQ Radionuclide Positron Fraction"},
08755     {DCM_ACQRADIOPHARMACEUTICALSPECIFICACTIVITY, DCM_DS,
08756     "ACQ Radiopharmaceutical Specific Activity"},
08757     {DCM_ACQBEATREJECTIONFLAG, DCM_CS, "ACQ Beat Rejection Flag"},
08758     {DCM_ACQLOWRRVALUE, DCM_IS, "ACQ Low R-R Value"},
08759     {DCM_ACQHIGHRRVALUE, DCM_IS, "ACQ High R-R Value"},
08760     {DCM_ACQINTERVALSACQUIRED, DCM_IS, "ACQ Intervals Acquired"},
08761     {DCM_ACQINTERVALSREJECTED, DCM_IS, "ACQ Intervals Rejected"},
08762     {DCM_ACQPVCREJECTION, DCM_LO, "ACQ PVC Rejection"},
08763     {DCM_ACQSKIPBEATS, DCM_IS, "ACQ Skip Beats"},
08764     {DCM_ACQHEARTRATE, DCM_IS, "ACQ Heart Rate"},
08765     {DCM_ACQCARDIACNUMBEROFIMAGES, DCM_IS, "ACQ Cardiac Number of Images"},
08766     {DCM_ACQTRIGGERWINDOW, DCM_IS, "ACQ Trigger Window"},
08767     {DCM_ACQRECONSTRUCTIONDIAMETER, DCM_DS, "ACQ Reconstruction Diameter"},
08768     {DCM_ACQDISTANCESRCTODETECTOR, DCM_DS, "ACQ Distance Source-Detector"},
08769     {DCM_ACQDISTANCESRCTOPATIENT, DCM_DS, "ACQ Distance Source-Patient"},
08770     {DCM_ACQESTIMATEDRADIOGRAPHICMAGFACTOR, DCM_DS, "ACQ Estimated Radiographic Mag Factor"},
08771     {DCM_ACQGANTRYTILT, DCM_DS, "ACQ Gantry/Detector Tilt"},
08772     {DCM_ACQGANTRYSLEW, DCM_DS, "ACQ Gantry/Detector Slew"},
08773     {DCM_ACQTABLEHEIGHT, DCM_DS, "ACQ Table Height"},
08774     {DCM_ACQTABLETRAVERSE, DCM_DS, "ACQ Table Traverse"},
08775     {DCM_ACQTABLEMOTION, DCM_CS, "ACQ Table Motion (STATIC, DYNAMIC)"},
08776     {DCM_ACQTABLEVERTICALINCREMENT, DCM_DS, "ACQ Table Vertical Increment (mm)"},
08777     {DCM_ACQTABLELATERALINCREMENT, DCM_DS, "ACQ Table Lateral Increment (mm)"},
08778     {DCM_ACQTABLELONGITUDINALINCREMENT, DCM_DS, "ACQ Table Longitudinal Increment (mm)"},
08779     {DCM_ACQTABLEANGLE, DCM_DS, "ACQ Table Angle (relative to horizontal: deg)"},
08780     {DCM_ACQROTATIONDIRECTION, DCM_CS, "ACQ Rotation Direction"},
08781     {DCM_ACQANGULARPOSITION, DCM_DS, "ACQ Angular Position"},
08782     {DCM_ACQRADIALPOSITION, DCM_DS, "ACQ Radial Position"},
08783     {DCM_ACQSCANARC, DCM_DS, "ACQ Scan Arc"},
08784     {DCM_ACQANGULARSTEP, DCM_DS, "ACQ Angular Step"},
08785     {DCM_ACQCENTERROTATIONOFFSET, DCM_DS, "ACQ Center of Rotation Offset"},
08786     {DCM_ACQROTATIONOFFSET, DCM_DS, "ACQ Rotation Offset (RET)"},
08787     {DCM_ACQFIELDOFVIEWSHAPE, DCM_CS, "ACQ Field of View Shape"},
08788     {DCM_ACQFIELDOFVIEWDIMENSION, DCM_IS, "ACQ Field of View Dimension(s)"},
08789     {DCM_ACQEXPOSURETIME, DCM_IS, "ACQ Exposure Time"},
08790     {DCM_ACQXRAYTUBECURRENT, DCM_IS, "ACQ X-ray Tube Current"},
08791     {DCM_ACQEXPOSURE, DCM_IS, "ACQ Exposure"},
08792     {DCM_ACQAVERAGEPULSEWIDTH, DCM_DS, "ACQ Average width of X-Ray pulse (ms)"},
08793     {DCM_ACQRADIATIONSETTING, DCM_CS, "ACQ General level of X-Ray dose exposure"},
08794     {DCM_ACQRADIATIONMODE, DCM_CS, "ACQ X-Ray radiation mode (CONTINUOUS, PULSED)"},
08795     {DCM_ACQIMAGEAREADOSEPRODUCT, DCM_DS, "ACQ X-Ray dose to which patient was exposed"},
08796     {DCM_ACQFILTERTYPE, DCM_SH, "ACQ Filter Type, extremity"},
08797     {DCM_ACQTYPEOFFILTERS, DCM_LO, "ACQ Type of filter(s) inserted into X-Ray beam"},
08798     {DCM_ACQINTENSIFIERSIZE, DCM_DS, "ACQ Intensifier Size (mm)"},
08799     {DCM_ACQIMAGERPIXELSPACING, DCM_DS, "ACQ Image Pixel Spacing"},
08800     {DCM_ACQGRID, DCM_CS, "ACQ Grid (IN, NONE)"},
08801     {DCM_ACQGENERATORPOWER, DCM_IS, "ACQ Generator Power"},
08802     {DCM_ACQCOLLIMATORGRIDNAME, DCM_SH, "ACQ Collimator/Grid Name"},
08803     {DCM_ACQCOLLIMATORTYPE, DCM_CS, "ACQ Collimator Type"},
08804     {DCM_ACQFOCALDISTANCE, DCM_IS, "ACQ Focal Distance"},
08805     {DCM_ACQXFOCUSCENTER, DCM_DS, "ACQ X Focus Center"},
08806     {DCM_ACQYFOCUSCENTER, DCM_DS, "ACQ Y Focus Center"},
08807     {DCM_ACQFOCALSPOT, DCM_DS, "ACQ Focal Spot"},
08808     {DCM_ACQDATELASTCALIBRATION, DCM_DA, "ACQ Date of Last Calibration"},
08809     {DCM_ACQTIMELASTCALIBRATION, DCM_TM, "ACQ Time of Last Calibration"},
08810     {DCM_ACQCONVOLUTIONKERNEL, DCM_SH, "ACQ Convolution Kernel"},
08811     {DCM_ACQUPPERLOWERPIXELVALUES, DCM_RET, "ACQ Upper/Lower Pixel Values (RET)"},
08812     {DCM_ACQACTUALFRAMEDURATION, DCM_IS, "ACQ Actual Frame Duration"},
08813     {DCM_ACQCOUNTRATE, DCM_IS, "ACQ Count Rate"},
08814     {DCM_ACQPREFPLAYBACKSEQUENCING, DCM_US, "ACQ Preferred Playback Sequencing"},
08815     {DCM_ACQRECEIVINGCOIL, DCM_SH, "ACQ Receiving Coil"},
08816     {DCM_ACQTRANSMITTINGCOIL, DCM_SH, "ACQ Transmitting Coil"},
08817     {DCM_ACQPLATETYPE, DCM_SH, "ACQ Plate Type"},
08818     {DCM_ACQPHOSPHORTYPE, DCM_LO, "ACQ Phosphor Type"},
08819 #if STANDARD_VERSION < VERSION_APR1995
08820     {DCM_ACQSCANVELOCITY, DCM_IS, "ACQ Scan Velocity"},
08821 #else
08822     {DCM_ACQSCANVELOCITY, DCM_DS, "ACQ Scan Velocity"},
08823 #endif
08824     {DCM_ACQWHOLEBODYTECHNIQUE, DCM_CS, "ACQ Whole Body Technique"},
08825     {DCM_ACQSCANLENGTH, DCM_IS, "ACQ Scan Length"},
08826     {DCM_ACQACQUISITIONMATRIX, DCM_US, "ACQ Acquisition Matrix"},
08827     {DCM_ACQPHASEENCODINGDIRECTION, DCM_CS, "ACQ Phase Encoding Direction"},
08828     {DCM_ACQFLIPANGLE, DCM_DS, "ACQ Flip Angle"},
08829     {DCM_ACQVARIABLEFLIPANGLE, DCM_CS, "ACQ Variable Flip Angle"},
08830     {DCM_ACQSAR, DCM_DS, "ACQ SAR"},
08831     {DCM_ACQDBDT, DCM_DS, "ACQ DB/DT"},
08832     {DCM_ACQDEVICEPROCESSINGDESCR, DCM_LO, "ACQ Acquisition Device Processing Description"},
08833     {DCM_ACQDEVICEPROCESSINGCODE, DCM_LO, "ACQ Acquisition Device Processing Code"},
08834     {DCM_ACQCASSETTEORIENTATION, DCM_CS, "ACQ Cassette Orientation"},
08835     {DCM_ACQCASSETTESIZE, DCM_CS, "ACQ Cassette Size"},
08836     {DCM_ACQEXPOSURESONPLATE, DCM_US, "ACQ Exposures on Plate"},
08837     {DCM_ACQRELATIVEXRAYEXPOSURE, DCM_IS, "ACQ Relative X-ray Exposure"},
08838     {DCM_ACQCOLUMNANGULATION, DCM_CS, "ACQ Column Angulation"},
08839     {DCM_ACQTOMOLAYERHEIGHT, DCM_DS, "ACQ Tomo Layer Height (mm)"},
08840     {DCM_ACQTOMOANGLE, DCM_DS, "ACQ Tomo Angle"},
08841     {DCM_ACQTOMOTIME, DCM_DS, "ACQ Tomo Time"},
08842     {0x00181490, DCM_CS, "ACQ Tomo Type"},                      /* 2002.04.26 */
08843     {0x00181491, DCM_CS, "ACQ Tomo Class"},                     /* 2002.04.26 */
08844     {0x00181495, DCM_IS, "ACQ Number of Tomosynthesis Source Images"}, /* 2002.04.26 */
08845     {DCM_ACQPOSITIONERMOTION, DCM_CS, "ACQ Positioner Motion"},
08846     {0x00181508, DCM_CS, "ACQ Positioner Type"},                /* 2002.04.26 */
08847     {DCM_ACQPOSITIONERPRIMARYANGLE, DCM_DS, "ACQ Positioner Primary Angle"},
08848     {DCM_ACQPOSITIONERSECONDARYANGLE, DCM_DS, "ACQ Positioner Secondary Angle"},
08849     {DCM_ACQPOSITIONERPRIMARYANGLEINCR, DCM_DS, "ACQ Positioner Primary Angle Increment"},
08850     {DCM_ACQPOSITIONERSECONDARYANGLEINCR, DCM_DS, "ACQ Positioner Secondary Angle Increment"},
08851     {DCM_ACQDETECTORPRIMARYANGLE, DCM_DS, "ACQ Detector Primary Angle"},
08852     {DCM_ACQDETECTORSECONDARYANGLE, DCM_DS, "ACQ Detector Secondary Angle"},
08853     {DCM_ACQSHUTTERSHAPE, DCM_CS, "ACQ Shutter Shape"},
08854     {DCM_ACQSHUTTERLEFTVERTICALEDGE, DCM_IS, "ACQ Shutter Left Vertical Edge"},
08855     {DCM_ACQSHUTTERRIGHTVERTICALEDGE, DCM_IS, "ACQ Shutter Right Vertical Edge"},
08856     {DCM_ACQSHUTTERUPPERHORIZONTALEDGE, DCM_IS, "ACQ Shutter Upper Horizontal Edge"},
08857     {DCM_ACQSHUTTERLOWERHORIZONTALEDGE, DCM_IS, "ACQ Shutter Lower Horizontal Edge"},
08858     {DCM_ACQCENTEROFCIRCULARSHUTTER, DCM_IS, "ACQ Center of Circular Shutter"},
08859     {DCM_ACQRADIUSOFCIRCULARSHUTTER, DCM_IS, "ACQ Radius of Circular Shutter"},
08860     {DCM_ACQVERTICESOFPOLYGONALSHUTTER, DCM_IS, "ACQ Vertices of the Polygonal Shutter"},
08861     {DCM_ACQCOLLIMATORSHAPE, DCM_CS, "ACQ Collimator Shape"},
08862     {DCM_ACQCOLLIMATORLEFTVERTICALEDGE, DCM_IS, "ACQ Collimator Left Vertical Edge"},
08863     {DCM_ACQCOLLIMATORRIGHTVERTICALEDGE, DCM_IS, "ACQ Collimator Right Vertical Edge"},
08864     {DCM_ACQCOLLIMATORUPPERHORIZONTALEDGE, DCM_IS, "ACQ Collimator Upper Horizontal Edge"},
08865     {DCM_ACQCOLLIMATORLOWERHORIZONTALEDGE, DCM_IS, "ACQ Collimator Lower Horizontal Edge"},
08866     {DCM_ACQCENTEROFCIRCULARCOLLIMATOR, DCM_IS, "ACQ Center of Circular Collimator"},
08867     {DCM_ACQRADIUSOFCIRCULARCOLLIMATOR, DCM_IS, "ACQ Radius of Circular Collimator"},
08868     {DCM_ACQVERTICESOFPOLYGONALCOLLIMATOR, DCM_IS, "ACQ Vertices of the Polygonal Collimator"},
08869     {DCM_ACQACQUISITIONTIMESYNCHRONIZED, DCM_CS,
08870     "ACQ Acquisition Time Synchronized"},       /* Sup 30 0.7 */
08871     {DCM_ACQTIMESOURCE, DCM_SH, "ACQ Time Source"},     /* Sup 30 0.7 */
08872     {DCM_ACQTIMEDISTRIBUTIONPROTOCOL, DCM_CS,
08873     "ACQ Time Distribution Protocol"},  /* Sup 30 0.7 */
08874     {DCM_ACQCOMMENTS, DCM_RET, "ACQ Comments"},
08875     {DCM_ACQOUTPUTPOWER, DCM_SH, "ACQ Output Power"},
08876     {DCM_ACQTRANSDUCERDATA, DCM_LO, "ACQ Transducer Data"},
08877     {DCM_ACQFOCUSDEPTH, DCM_DS, "ACQ Focus Depth"},
08878 #if STANDARD_VERSION < VERSION_APR1995
08879     {DCM_ACQPREPROCESSINGFUNCTION, DCM_LO, "ACQ Preprocessing Function"},
08880 #else
08881     {DCM_ACQPROCESSINGFUNCTION, DCM_LO, "ACQ Processing Function"},
08882 #endif
08883     {DCM_ACQPOSTPROCESSINGFUNCTION, DCM_LO, "ACQ Postprocessing Function"},
08884     {DCM_ACQMECHANICALINDEX, DCM_DS, "ACQ Mechanical Index"},
08885     {DCM_ACQTHERMALINDEX, DCM_DS, "ACQ Thermal Index"},
08886     {DCM_ACQCRANIALTHERMALINDEX, DCM_DS, "ACQ Cranial Thermal Index"},
08887     {DCM_ACQSOFTTISSUETHERMALINDEX, DCM_DS, "ACQ Soft Tissue Thermal Index"},
08888     {DCM_ACQSOFTTISSUEFOCUSTHERMALINDEX, DCM_DS,
08889     "ACQ Soft Tissue-focus Thermal Index"},
08890     {DCM_ACQSOFTTISSUESURFACETHERMALINDEX, DCM_CS,
08891     "ACQ Soft Tissue-surface Thermal Index"},
08892     {DCM_ACQDEPTHOFSCANFIELD, DCM_IS, "ACQ Depth of Scan Field"},
08893     {DCM_ACQPATIENTPOSITION, DCM_CS, "ACQ Patient Position"},
08894     {DCM_ACQVIEWPOSITION, DCM_CS, "ACQ View Position"},
08895     {DCM_ACQIMAGETRANSFORMATIONMATRIX, DCM_DS,
08896     "ACQ Image Transformation Matrix"},
08897     {DCM_ACQIMAGETRANSLATIONVECTOR, DCM_DS,
08898     "ACQ Image Translation Vector"},
08899     {DCM_ACQSENSITIVITY, DCM_DS, "ACQ Sensitivity"},
08900     {DCM_ACQUSREGIONSEQUENCE, DCM_SQ, "ACQ Ultrasound Region Sequence"},
08901     {DCM_ACQREGIONSPATIALFORMAT, DCM_US, "ACQ Region Spatial Format"},
08902     {DCM_ACQREGIONDATATYPE, DCM_US, "ACQ Region Data Type"},
08903     {DCM_ACQREGIONFLAGS, DCM_UL, "ACQ Region Flags"},
08904     {DCM_ACQREGIONLOCATIONMINX0, DCM_UL, "ACQ Region Location Min X(0)"},
08905     {DCM_ACQREGIONLOCATIONMINY0, DCM_UL, "ACQ Region Location Min Y(0)"},
08906     {DCM_ACQREGIONLOCATIONMAXX1, DCM_UL, "ACQ Region Location Max X(1)"},
08907     {DCM_ACQREGIONLOCATIONMAXY1, DCM_UL, "ACQ Region Location Max Y(1)"},
08908     {DCM_ACQREFERENCEPIXELX, DCM_SL, "ACQ Reference Pixel X"},
08909     {DCM_ACQREFERENCEPIXELY, DCM_SL, "ACQ Reference Pixel Y"},
08910     {DCM_ACQPHYSICALUNITSXDIRECTION, DCM_US, "ACQ Physical Units X Direction"},
08911     {DCM_ACQPHYSICALUNITSYDIRECTION, DCM_US, "ACQ Physical Units Y Direction"},
08912     {DCM_ACQREFPIXELPHYSICALVALUEX, DCM_FD, "ACQ Reference Pixel Physical Value X"},
08913     {DCM_ACQREFPIXELPHYSICALVALUEY, DCM_FD, "ACQ Reference Pixel Physical Value Y"},
08914     {DCM_ACQPHYSICALDELTAX, DCM_FD, "ACQ Physical Delta X"},
08915     {DCM_ACQPHYSICALDELTAY, DCM_FD, "ACQ Physical Delta Y"},
08916     {DCM_ACQTRANSDUCERFREQUENCY, DCM_UL, "ACQ Transducer Frequency"},
08917     {DCM_ACQTRANSDUCERTYPE, DCM_CS, "ACQ Transducer Type"},
08918     {DCM_ACQPULSEREPETITIONFREQ, DCM_UL, "ACQ Pulse Repetition Frequency"},
08919     {DCM_ACQDOPPLERCORRECTIONANGLE, DCM_FD, "ACQ Doppler Correction Angle"},
08920     {DCM_ACQSTERRINGANGLE, DCM_FD, "ACQ Sterring Angle"},
08921     {DCM_ACQDOPPLERSAMPLEVOLXPOS, DCM_UL, "ACQ Doppler Sample Volume X Position"},
08922     {DCM_ACQDOPPLERSAMPLEVOLYPOS, DCM_UL, "ACQ Doppler Sample Volume Y Position"},
08923     {DCM_ACQTMLINEPOSITIONX0, DCM_UL, "ACQ TM-Line Position X(0)"},
08924     {DCM_ACQTMLINEPOSITIONY0, DCM_UL, "ACQ TM-Line Position Y(0)"},
08925     {DCM_ACQTMLINEPOSITIONX1, DCM_UL, "ACQ TM-Line Position X(1)"},
08926     {DCM_ACQTMLINEPOSITIONY1, DCM_UL, "ACQ TM-Line Position Y(1)"},
08927     {DCM_ACQPIXELCOMPORGANIZATION, DCM_US, "ACQ Pixel Component Organization"},
08928     {DCM_ACQPIXELCOMPMASK, DCM_UL, "ACQ Pixel Component Mask"},
08929     {DCM_ACQPIXELCOMPRANGESTART, DCM_UL, "ACQ Pixel Component Range Start"},
08930     {DCM_ACQPIXELCOMPRANGESTOP, DCM_UL, "ACQ Pixel Component Range Stop"},
08931     {DCM_ACQPIXELCOMPPHYSUNITS, DCM_US, "ACQ Pixel Component Physical Units"},
08932     {DCM_ACQPIXELCOMPDATATYPE, DCM_US, "ACQ Pixel Component Data Type"},
08933     {DCM_ACQNUMBERTABLEBREAKPOINTS, DCM_UL, "ACQ Number of Table Break Points"},
08934     {DCM_ACQTABLEXBREAKPOINTS, DCM_UL, "ACQ Table of X Break Points"},
08935     {DCM_ACQTABLEYBREAKPOINTS, DCM_FD, "ACQ Table of Y Break Points"},
08936     {DCM_ACQNUMBEROFTABLEENTRIES, DCM_UL, "ACQ Number of Table Entries"},
08937     {DCM_ACQTABLEOFPIXELVALUES, DCM_UL, "ACQ Table of Pixel Values"},
08938     {DCM_ACQTABLEOFPARAMETERVALUES, DCM_FL, "ACQ Table of Parameter Values"},
08939 
08940     {0x00187000, DCM_CS, "ACQ Detector Conditions Nominal Flag"}, /* 2002.04.26 */
08941     {0x00187001, DCM_DS, "ACQ Detector Temperature"},           /* 2002.04.26 */
08942     {0x00187004, DCM_CS, "ACQ Detector Type"},                  /* 2002.04.26 */
08943     {0x00187005, DCM_CS, "ACQ Detector Configuration"},         /* 2002.04.26 */
08944     {0x00187006, DCM_LT, "ACQ Detector Description"},           /* 2002.04.26 */
08945     {0x00187008, DCM_LT, "ACQ Detector Mode"},                  /* 2002.04.26 */
08946     {0x0018700A, DCM_SH, "ACQ Detector ID"},                    /* 2002.04.26 */
08947 
08948     {0x00187028, DCM_DS, "ACQ Detector Active Origin"}          /* 2002.04.26 */
08949 };
08950 
08951 /* Define the entries for the RELATIONSHIP group (0020)
08952 */
08953 static DCMDICT REL_dictionary[] = {
08954     {DCM_RELGROUPLENGTH, DCM_UL, "REL Group Length"},
08955     {DCM_RELSTUDYINSTANCEUID, DCM_UI, "REL Study Instance UID"},
08956     {DCM_RELSERIESINSTANCEUID, DCM_UI, "REL Series Instance UID"},
08957     {DCM_RELSTUDYID, DCM_SH, "REL Study ID"},
08958     {DCM_RELSERIESNUMBER, DCM_IS, "REL Series Number"},
08959     {DCM_RELACQUISITIONNUMBER, DCM_IS, "REL Acquisition Number"},
08960     {DCM_RELIMAGENUMBER, DCM_IS, "REL Instance Number"},
08961 
08962     {DCM_RELISOTOPENUMBER, DCM_IS, "REL Isotope Number (RET)"},
08963     {DCM_RELPHASENUMBER, DCM_IS, "REL Phase Number (RET)"},
08964     {DCM_RELINTERVALNUMBER, DCM_IS, "REL Interval Number (RET)"},
08965     {DCM_RELTIMESLOTNUMBER, DCM_IS, "REL Time Slot Number (RET)"},
08966     {DCM_RELANGLENUMBER, DCM_IS, "REL Angle Number (RET)"},
08967 
08968     {DCM_RELPATIENTORIENTATION, DCM_CS, "REL Patient Orientation"},
08969     {DCM_RELOVERLAYNUMBER, DCM_IS, "REL Overlay Number"},
08970     {DCM_RELCURVENUMBER, DCM_IS, "REL Curve Number"},
08971     {DCM_RELLOOKUPTABLENUMBER, DCM_IS, "REL Looup Table Number"},
08972     {DCM_RELIMAGEPOSITION, DCM_RET, "REL Image Position (RET)"},
08973     {DCM_RELIMAGEPOSITIONPATIENT, DCM_DS, "REL Image Position Patient"},
08974     {DCM_RELIMAGEORIENTATION, DCM_RET, "REL Image Orientation"},
08975     {DCM_RELIMAGEORIENTATIONPATIENT, DCM_DS, "REL Image Orientation (Patient)"},
08976     {DCM_RELLOCATION, DCM_RET, "REL Location (RET)"},
08977     {DCM_RELFRAMEOFREFERENCEUID, DCM_UI, "REL Frame of Reference UID"},
08978     {DCM_RELLATERALITY, DCM_CS, "REL Laterality"},
08979     { DCM_MAKETAG(0x0020, 0x0062), DCM_CS, "REL Image Laterality"},
08980     {DCM_RELIMAGEGEOMETRYTYPE, DCM_RET, "REL Image Geometry Type (RET)"},
08981     {DCM_RELMASKINGIMAGE, DCM_RET, "REL Masking Image (RET)"},
08982     {DCM_RELTEMPORALPOSITIONID, DCM_IS, "REL Temporal Position Identifier"},
08983     {DCM_RELNUMBERTEMPORALPOSITIONS, DCM_IS, "REL Number of Temporal Positions"},
08984     {DCM_RELTEMPORALRESOLUTION, DCM_DS, "REL Temporal Resolution"},
08985     {DCM_RELSERIESINSTUDY, DCM_IS, "REL Series in Study"},
08986     {DCM_RELACQUISITIONSINSERIES, DCM_RET, "REL Acquisitions in Series"},
08987     {DCM_RELIMAGESINACQUISITION, DCM_IS, "REL Images in Acquisition"},
08988     {DCM_RELACQUISITIONSINSTUDY, DCM_IS, "REL Acquisitions in Study"},
08989     {DCM_RELREFERENCE, DCM_RET, "REL Reference (RET)"},
08990     {DCM_RELPOSITIONREFINDICATOR, DCM_LO, "REL Position Reference Indicator"},
08991     {DCM_RELSLICELOCATION, DCM_DS, "REL Slice Location"},
08992     {DCM_RELOTHERSTUDYNUMBERS, DCM_IS, "REL Other Study Numbers"},
08993     {DCM_RELNUMBERPATRELATEDSTUDIES, DCM_IS,
08994     "REL Number of Patient Related Studies"},
08995     {DCM_RELNUMBERPATRELATEDSERIES, DCM_IS, "REL Number of Patient Related Series"},
08996     {DCM_RELNUMBERPATRELATEDIMAGES, DCM_IS, "REL Number of Patient Related Instances"},
08997     {DCM_RELNUMBERSTUDYRELATEDSERIES, DCM_IS, "REL Number of Study Related Series"},
08998     {DCM_RELNUMBERSTUDYRELATEDIMAGES, DCM_IS, "REL Number of Study Related Instances"},
08999     {DCM_RELNUMBERSERIESRELATEDINST, DCM_IS, "REL Number of Series Related Instances"},
09000     {DCM_RELSOURCEIMAGEID, DCM_RET, "REL Source Image IDs (RET)"},
09001     {DCM_RELMODIFYINGDEVICEID, DCM_RET, "REL Modifying Device ID (RET)"},
09002     {DCM_RELMODIFIEDIMAGEID, DCM_RET, "REL Modified Image ID (RET)"},
09003     {DCM_RELMODIFIEDIMAGEDATE, DCM_RET, "REL Modified Image Date (RET)"},
09004     {DCM_RELMODIFYINGDEVICEMFR, DCM_RET, "REL Modifying Device Mfr (RET)"},
09005     {DCM_RELMODIFIEDIMAGETIME, DCM_RET, "REL Modified Image Time"},
09006     {DCM_RELMODIFIEDIMAGEDESCRIPTION, DCM_RET,
09007     "REL Modified Image Description (RET)"},
09008     {DCM_RELIMAGECOMMENTS, DCM_LT, "REL Image Comments"},
09009     {DCM_RELORIGINALIMAGEID, DCM_RET, "REL Original Image ID (RET)"},
09010     {DCM_RELORIGINALIMAGEIDNOMENCLATURE, DCM_RET,
09011     "REL Orig Image ID Nomenclature (RET)"}
09012 };
09013 
09014 /* Define the entries for the IMAGE group (0028)
09015 */
09016 static DCMDICT IMG_dictionary[] = {
09017     {DCM_IMGGROUPLENGTH, DCM_UL, "IMG Group Length"},
09018     {DCM_IMGSAMPLESPERPIXEL, DCM_US, "IMG Samples Per Pixel"},
09019     {DCM_IMGPHOTOMETRICINTERP, DCM_CS, "IMG Photometric Interpretation"},
09020     {DCM_IMGIMAGEDIMENSIONS, DCM_RET, "IMG Image Dimensions (RET)"},
09021     {DCM_IMGPLANARCONFIGURATION, DCM_US, "IMG Planar Configuration"},
09022     {DCM_IMGNUMBEROFFRAMES, DCM_IS, "IMG Number of Frames"},
09023     {DCM_IMGFRAMEINCREMENTPOINTER, DCM_AT, "IMG Frame Increment Pointer"},
09024     {DCM_IMGROWS, DCM_US, "IMG Rows"},
09025     {DCM_IMGCOLUMNS, DCM_US, "IMG Columns"},
09026     {DCM_IMGPLANES, DCM_US, "IMG Planes"},
09027     {DCM_IMGUSOUNDCOLORDATAPRESENT, DCM_US, "IMG Ultrasound Color Data Present"},
09028     {DCM_IMGPIXELSPACING, DCM_DS, "IMG Pixel Spacing"},
09029     {DCM_IMGZOOMFACTOR, DCM_DS, "IMG Zoom Factor"},
09030     {DCM_IMGZOOMCENTER, DCM_DS, "IMG Zoom Center"},
09031     {DCM_IMGPIXELASPECTRATIO, DCM_IS, "IMG Pixel Aspect Ratio"},
09032     {DCM_IMGIMAGEFORMAT, DCM_RET, "IMG Image Format (RET)"},
09033     {DCM_IMGMANIPULATEDIMAGE, DCM_RET, "IMG Manipulated Image (RET)"},
09034     {DCM_IMGCORRECTEDIMAGE, DCM_CS, "IMG Corrected Image"},
09035     {DCM_IMGCOMPRESSIONCODE, DCM_RET, "IMG Compression Code"},
09036     {DCM_IMGBITSALLOCATED, DCM_US, "IMG Bits Allocated"},
09037     {DCM_IMGBITSSTORED, DCM_US, "IMG Bits Stored"},
09038     {DCM_IMGHIGHBIT, DCM_US, "IMG High Bit"},
09039     {DCM_IMGPIXELREPRESENTATION, DCM_US, "IMG Pixel Representation"},
09040     {DCM_IMGSMALLESTPIXELVALUE, DCM_RET, "IMG Smallest Pixel Value (RET)"},
09041     {DCM_IMGLARGESTPIXELVALUE, DCM_RET, "IMG Largest Pixel Vaue (RET)"},
09042     {DCM_IMGSMALLESTIMAGEPIXELVALUE, DCM_CTX, "IMG Smallest Image Pixel Value"},
09043     {DCM_IMGLARGESTIMAGEPIXELVALUE, DCM_CTX, "IMG Largest Image Pixel Value"},
09044     {DCM_IMGSMALLESTPIXELVALUESERIES, DCM_CTX, "IMG Smallest Pixel Value in Series"},
09045     {DCM_IMGLARGESTPIXELVALUESERIES, DCM_CTX, "IMG Largest Pixel Value in Series"},
09046     {DCM_IMGSMALLESTIMAGEPIXELVALUEPLANE, DCM_CTX, "IMG Smallest Pixel Value in Plane"},
09047     {DCM_IMGLARGESTIMAGEPIXELVALUEPLANE, DCM_CTX, "IMG Largest Pixel Value in Plane"},
09048     {DCM_IMGPIXELPADDINGVALUE, DCM_CTX, "IMG Pixel Padding Value"},
09049     {DCM_IMGWAVEFORMPADDINGVALUE, DCM_CTX, "IMG Waveform Padding Value"},       /* Sup 30 0.6 */
09050     {DCM_IMGIMAGELOCATION, DCM_RET, "IMG Image Location"},
09051     {DCM_MAKETAG(0x0028, 0x0300), DCM_CS, "IMG Quality Control Image"},
09052     {DCM_MAKETAG(0x0028, 0x0301), DCM_CS, "IMG Burned In Annotation"},
09053     {DCM_IMGPIXELINTENSITYRELATIONSHIP, DCM_CS, "IMG Pixel Intensity Relationship"},
09054     {DCM_MAKETAG(0x0028, 0x1041), DCM_SS, "IMG Pixel Intensity Relationship Sign"},
09055     {DCM_IMGWINDOWCENTER, DCM_DS, "IMG Window Center"},
09056     {DCM_IMGWINDOWWIDTH, DCM_DS, "IMG Window Width"},
09057     {DCM_IMGRESCALEINTERCEPT, DCM_DS, "IMG Rescale Intercept"},
09058     {DCM_IMGRESCALESLOPE, DCM_DS, "IMG Rescale Slope"},
09059     {DCM_IMGRESCALETYPE, DCM_LO, "IMG Rescale Type"},
09060     {DCM_IMGWINDOWCWEXPLANATION, DCM_LO, "IMG Window Center & Width Explanation"},
09061     {DCM_IMGGRAYSCALE, DCM_RET, "IMG Gray Scale (RET)"},
09062     {DCM_IMGRECOMMENDEDVIEWINGMODE, DCM_CS, "IMG Recommended Viewing Mode"},
09063     {DCM_IMGLUTDESCRIPTGRAY, DCM_RET, "IMG Lookup Table Desc-Gray (RET)"},
09064     {DCM_IMGLUTDESCRIPTRED, DCM_US, "IMG Lookup Table Desc-Red"},
09065     {DCM_IMGLUTDESCRIPTGREEN, DCM_US, "IMG Lookup Table Desc-Green"},
09066     {DCM_IMGLUTDESCRIPTBLUE, DCM_US, "IMG Lookup Table Desc-Blue"},
09067     {DCM_IMGPALETTECOLORLUTUID, DCM_UI, "IMG Palette Color Lookup Table UID"},
09068     {DCM_IMGLOOKUPDATAGRAY, DCM_RET, "IMG Lookup Data-Gray"},
09069 
09070 #if 0
09071     /* As originally defined in 1993 */
09072     {DCM_IMGLOOKUPDATARED, DCM_US, "IMG Lookup Data-Red"},
09073     {DCM_IMGLOOKUPDATAGREEN, DCM_US, "IMG Lookup Data-Green"},
09074     {DCM_IMGLOOKUPDATABLUE, DCM_US, "IMG Lookup Data-Blue"},
09075 #endif
09076 
09077     {DCM_IMGLOOKUPDATARED, DCM_CTX, "IMG Lookup Data-Red"},
09078     {DCM_IMGLOOKUPDATAGREEN, DCM_CTX, "IMG Lookup Data-Green"},
09079     {DCM_IMGLOOKUPDATABLUE, DCM_CTX, "IMG Lookup Data-Blue"},
09080 
09081     {DCM_IMGSEGMENTEDREDLUTDATA, DCM_OW, "IMG Segmented Red Palette Color LUT Data"},
09082     {DCM_IMGSEGMENTEDGREENLUTDATA, DCM_OW, "IMG Segmented Green Palette Color LUT Data"},
09083     {DCM_IMGSEGMENTEDBLUELUTDATA, DCM_OW, "IMG Segmented Blue Palette Color LUT Data"},
09084 
09085     {DCM_IMGLOSSYIMAGECOMPRESSION, DCM_CS, "IMG Lossy Image Compression"},
09086     {DCM_IMGMODALITYLUTSEQUENCE, DCM_SQ, "IMG Modality LUT Sequence"},
09087     {DCM_IMGLUTDESCRIPTOR, DCM_CTX, "IMG LUT Descriptor"},
09088     {DCM_IMGLUTEXPLANATION, DCM_LO, "IMG LUT Explanation"},
09089     {DCM_IMGMODALITYLUTTYPE, DCM_LO, "IMG Modality LUT Type"},
09090     {DCM_IMGLUTDATA, DCM_CTX, "IMG LUT Data"},
09091     {DCM_IMGVOILUTSEQUENCE, DCM_SQ, "IMG VOI LUT Sequence"},
09092     {DCM_IMGCOMMENTS, DCM_RET, "IMG Comments (RET)"},
09093     {DCM_IMGBIPLANEACQSEQUENCE, DCM_SQ, "IMG Bi-Plane Acquisition Sequence"},
09094     {DCM_IMGREPRESENTATIVEFRAMENUMBER, DCM_US, "IMG Representative Frame Number"},
09095     {DCM_IMGFRAMENUMBERSOFINTEREST, DCM_US, "IMG Frame Numbers of Interest"},
09096     {DCM_IMGFRAMEOFINTERESTDESCRIPTION, DCM_LO, "IMG Frame of Interest Description"},
09097     {DCM_IMGMASKPOINTER, DCM_US, "IMG Mask Pointer(s)"},
09098     {DCM_IMGRWAVEPOINTER, DCM_US, "IMG R Wave Pointer"},
09099     {DCM_IMGMASKSUBTRACTIONSEQ, DCM_SQ, "IMG Mask Subtraction Sequence"},
09100     {DCM_IMGMASKOPERATION, DCM_CS, "IMG Mask Operation"},
09101     {DCM_IMGAPPLICABLEFRAMERANGE, DCM_US, "IMG Applicable Frame Range"},
09102     {DCM_IMGMASKFRAMENUMBERS, DCM_US, "IMG Mask Frame Numbers"},
09103     {DCM_IMGCONTRASTFRAMEAVERAGING, DCM_US, "IMG Contrast Frame Averaging"},
09104     {DCM_IMGMASKSUBPIXELSHIFT, DCM_FL, "IMG Mask Sub-pixel shift"},
09105     {DCM_IMGTIDOFFSET, DCM_SS, "IMG TID Offset"},
09106     {DCM_MASKOPERATIONEXPLANATION, DCM_ST, "IMG Mask Operation Explanation"}
09107 };
09108 
09109 /* Define the entries for the STUDY group (0032)
09110 */
09111 static DCMDICT SDY_dictionary[] = {
09112     {DCM_SDYGROUPLENGTH, DCM_UL, "SDY Study Group length"},
09113     {DCM_SDYSTATUSID, DCM_CS, "SDY Study Status ID"},
09114     {DCM_SDYPRIORITYID, DCM_CS, "SDY Study Priority ID"},
09115     {DCM_SDYIDISSUER, DCM_LO, "SDY Study ID Issuer"},
09116     {DCM_SDYVERIFIEDDATE, DCM_DA, "SDY Study Verified Date"},
09117     {DCM_SDYVERIFIEDTIME, DCM_TM, "SDY Study Verified Time"},
09118     {DCM_SDYREADDATE, DCM_DA, "SDY Study Read Date"},
09119     {DCM_SDYREADTIME, DCM_TM, "SDY Study Read Time"},
09120     {DCM_SDYSCHEDULEDSTARTDATE, DCM_DA, "SDY Scheduled Study Start Date"},
09121     {DCM_SDYSCHEDULEDSTARTTIME, DCM_TM, "SDY Scheduled Study Start Time"},
09122     {DCM_SDYSCHEDULEDSTOPDATE, DCM_DA, "SDY Scheduled Study Stop Date"},
09123     {DCM_SDYSCHEDULEDSTOPTIME, DCM_TM, "SDY Scheduled Study Stop Time"},
09124     {DCM_SDYSCHEDULEDLOCATION, DCM_LO, "SDY Scheduled Study Location"},
09125     {DCM_SDYSCHEDULEDLOCATIONAETITLE, DCM_AE,
09126     "SDY Scheduled Study Location AE Title(s)"},
09127     {DCM_SDYREASON, DCM_LO, "SDY Study Reason"},
09128     {DCM_SDYREQUESTINGPHYSICIAN, DCM_PN, "SDY Requesting Physician "},
09129     {DCM_SDYREQUESTINGSERVICE, DCM_LO, "SDY Requesting Service"},
09130     {DCM_SDYARRIVALDATE, DCM_DA, "SDY Study Arrival Date"},
09131     {DCM_SDYARRIVALTIME, DCM_TM, "SDY Study Arrival Time"},
09132     {DCM_SDYCOMPLETIONDATE, DCM_DA, "SDY Study Completion Date"},
09133     {DCM_SDYCOMPLETIONTIME, DCM_TM, "SDY Study Completion Time"},
09134     {DCM_SDYSTUDYCOMPONENTSTATUSID, DCM_CS, "SDY Study Component Status ID"},
09135     {DCM_SDYREQUESTEDPRODESCRIPTION, DCM_LO, "SDY Requested Procedure Description"},
09136     {DCM_SDYREQUESTEDPROCODESEQ, DCM_SQ, "SDY Requested Procedure Code Seq"},
09137     {DCM_SDYREQUESTEDCONTRASTAGENT, DCM_LO, "SDY Requested Contrast Agent"},
09138     {DCM_SDYCOMMENTS, DCM_LT, "SDY Comments"}
09139 };
09140 
09141 /* Define the entries for the VISIT group, 0038
09142 */
09143 static DCMDICT VIS_dictionary[] = {
09144     {DCM_VISGROUPLENGTH, DCM_UL, "VIS Group Length"},
09145     {DCM_VISREFERENCEDPATALIASSEQ, DCM_SQ, "VIS Referenced Patient Alias Sequence"},
09146     {DCM_VISSTATUSID, DCM_CS, "VIS Visit Status ID"},
09147     {DCM_VISADMISSIONID, DCM_LO, "VIS Admission ID"},
09148     {DCM_VISISSUEROFADMISSIONID, DCM_LO, "VIS Issuer of Admission ID"},
09149     {DCM_VISROUTEOFADMISSION, DCM_LO, "VIS Route of Admission"},
09150     {DCM_VISSCHEDULEDADMISSIONDATE, DCM_DA, "VIS Scheduled Admission Date"},
09151     {DCM_VISSCHEDULEDADMISSIONTIME, DCM_TM, "VIS Scheduled Admission Time"},
09152     {DCM_VISSCHEDULEDDISCHARGEDATE, DCM_DA, "VIS Scheduled Discharge Date"},
09153     {DCM_VISSCHEDULEDDISCHARGETIME, DCM_TM, "VIS Scheduled Discharge Time"},
09154     {DCM_VISSCHEDULEDPATINSTRESIDENCE, DCM_LO, "VIS Scheduled Patient Institution Residence"},
09155     {DCM_VISADMITTINGDATE, DCM_DA, "VIS Admitting Date"},
09156     {DCM_VISADMITTINGTIME, DCM_TM, "VIS Admitting Time"},
09157     {DCM_VISDISCHARGEDATE, DCM_DA, "VIS Discharge Date"},
09158     {DCM_VISDISCHARGETIME, DCM_TM, "VIS Discharge Time"},
09159     {DCM_VISDISCHARGEDIAGDESCRIPTION, DCM_LO, "VIS Discharge Diagnosis Description"},
09160     {DCM_VISDISCHARGEDIAGNOSISCODESEQ, DCM_SQ, "VIS Discharge Diagnosis Code Sequence"},
09161     {DCM_VISSPECIALNEEDS, DCM_LO, "VIS Special Needs"},
09162     {DCM_VISCURRENTPATIENTLOCATION, DCM_LO, "VIS Current Patient Location"},
09163     {DCM_VISPATIENTSINSTRESIDENCE, DCM_LO, "VIS Patient's Institution Residence"},
09164     {DCM_VISPATIENTSTATE, DCM_LO, "VIS Patient State"},
09165     {DCM_VISCOMMENTS, DCM_LT, "VIS Comments"}
09166 };
09167 
09168 /* Define the entries for the Waveform group, 003a
09169 */
09170 static DCMDICT WAV_dictionary[] = {
09171     {DCM_MAKETAG(0x003a, 0x0000), DCM_UL, "WAV Group Length"},
09172     {DCM_MAKETAG(0x003a, 0x0002), DCM_SQ, "WAV Waveform Sequence"},     /* Sup 30 0.6 */
09173     {DCM_MAKETAG(0x003a, 0x0005), DCM_US, "WAV Number of Channels"},    /* Sup 30 0.6 */
09174     {DCM_MAKETAG(0x003a, 0x0010), DCM_UL, "WAV Number of Samples"},     /* Sup 30 0.6 */
09175     {DCM_MAKETAG(0x003a, 0x001a), DCM_DS, "WAV Sampling Frequency"},    /* Sup 30 0.6 */
09176     {DCM_MAKETAG(0x003a, 0x0020), DCM_SH, "WAV Group Label"},   /* Sup 30 0.6 */
09177     {DCM_MAKETAG(0x003a, 0x0103), DCM_CS, "WAV Data Value Representation"},     /* Sup 30 0.6 */
09178     {DCM_MAKETAG(0x003a, 0x0200), DCM_SQ, "WAV Channel Definition"},    /* Sup 30 0.6 */
09179     {DCM_MAKETAG(0x003a, 0x0202), DCM_IS, "WAV Channel Number"},        /* Sup 30 0.6 */
09180     {DCM_MAKETAG(0x003a, 0x0203), DCM_SH, "WAV Channel Label"}, /* Sup 30 0.6 */
09181     {DCM_MAKETAG(0x003a, 0x0205), DCM_CS, "WAV Channel Status"},        /* Sup 30 0.6 */
09182     {DCM_MAKETAG(0x003a, 0x0208), DCM_SQ, "WAV Waveform Source"},       /* Sup 30 0.6 */
09183     {DCM_MAKETAG(0x003a, 0x0209), DCM_SQ, "WAV Waveform Source Modifiers"},     /* Sup 30 0.6 */
09184     {DCM_MAKETAG(0x003a, 0x020a), DCM_SQ, "WAV Differential Waveform Source"},  /* Sup 30 0.6 */
09185     {DCM_MAKETAG(0x003a, 0x020b), DCM_SQ, "WAV Differential Waveform Source Modifiers"},        /* Sup 30 0.6 */
09186     {DCM_MAKETAG(0x003a, 0x0210), DCM_DS, "WAV Channel Sensitivity"},   /* Sup 30 0.6 */
09187     {DCM_MAKETAG(0x003a, 0x0211), DCM_SQ, "WAV Channel Sensitivity Units"},     /* Sup 30 0.6 */
09188     {DCM_MAKETAG(0x003a, 0x0212), DCM_DS, "WAV Channel Sensitivity Correction Factor"}, /* Sup 30 0.6 */
09189     {DCM_MAKETAG(0x003a, 0x0213), DCM_DS, "WAV Channel Baseline"},      /* Sup 30 0.6 */
09190     {DCM_MAKETAG(0x003a, 0x0214), DCM_DS, "WAV Channel Time Skew"},     /* Sup 30 0.6 */
09191     {DCM_MAKETAG(0x003a, 0x0215), DCM_DS, "WAV Channel Sample Skew"},   /* Sup 30 0.6 */
09192     {DCM_MAKETAG(0x003a, 0x0218), DCM_DS, "WAV Channel Offset"},        /* Sup 30 0.6 */
09193     {DCM_MAKETAG(0x003a, 0x021a), DCM_US, "WAV Bits Per Sample"},       /* Sup 30 0.6 */
09194     {DCM_MAKETAG(0x003a, 0x0216), DCM_CTX, "WAV Channel Minimum Value"},        /* Sup 30 0.6 */
09195     {DCM_MAKETAG(0x003a, 0x0217), DCM_CTX, "WAV Channel Maximum Value"},        /* Sup 30 0.6 */
09196     {DCM_MAKETAG(0x003a, 0x0220), DCM_DS, "WAV Filter Low Frequency"},  /* Sup 30 0.6 */
09197     {DCM_MAKETAG(0x003a, 0x0221), DCM_DS, "WAV Filter High Frequency"}, /* Sup 30 0.6 */
09198     {DCM_MAKETAG(0x003a, 0x0222), DCM_DS, "WAV Notch Filter Frequency"},        /* Sup 30 0.6 */
09199     {DCM_MAKETAG(0x003a, 0x0223), DCM_DS, "WAV Notch Filter Bandwidth"},        /* Sup 30 0.6 */
09200     {DCM_MAKETAG(0x003a, 0x1000), DCM_CTX, "WAV Waveform Data"} /* Sup 30 0.6 */
09201 };
09202 
09203 /* Define the entries for the Procedure Step group, 0040
09204 */
09205 
09206 static DCMDICT PRC_dictionary[] = {
09207     {DCM_PRCGROUPLENGTH, DCM_UL, "PRC Group Length"},
09208     {DCM_PRCSCHEDULEDSTATIONAETITLE, DCM_AE, "PRC Scheduled Station AE Title"},
09209     {DCM_PRCSCHEDULEDPROCSTEPSTARTDATE, DCM_DA, "PRC Scheduled Procedure Step Start Date"},
09210     {DCM_PRCSCHEDULEDPROCSTEPSTARTTIME, DCM_TM, "PRC Scheduled Procedure Step Start Time"},
09211     {DCM_PRCSCHEDULEDPROCSTEPENDDATE, DCM_DA, "PRC Scheduled Procedure Step End Date"},
09212     {DCM_PRCSCHEDULEDPROCSTEPENDTIME, DCM_TM, "PRC Scheduled Procedure Step End Time"},
09213     {DCM_PRCSCHEDULEDPERFORMINGPHYSNAME, DCM_PN, "PRC Scheduled Performing Physician's Name"},
09214     {DCM_PRCSCHEDULEDPROCSTEPDESCRIPTION, DCM_LO, "PRC Scheduled Step Description"},
09215     {DCM_PRCSCHEDULEDACTIONITEMCODESEQ, DCM_SQ, "PRC Scheduled Action Item Code Sequence"},
09216     {DCM_PRCSCHEDULEDPROCSTEPID, DCM_SH, "PRC Scheduled Procedure Step ID"},
09217     {DCM_PRCSCHEDULEDSTATIONNAME, DCM_SH, "PRC Scheduled Station Name"},
09218     {DCM_PRCSCHEDULEDPROCSTEPLOCATION, DCM_SH, "PRC Scheduled Procedure Step Location"},
09219     {DCM_PRCPREMEDICATION, DCM_LO, "PRC Pre-Medication"},
09220     {DCM_PRCSTATUS, DCM_CS, "PRC SPStep Status"},
09221     {DCM_PRCREFSTANDALONESOPSEQ, DCM_SQ, "PRC Ref Standalone SOP Inst Seq"},
09222     {DCM_PRCPERFORMEDSTATIONAET, DCM_AE, "PRC Performed Station AE Title"},
09223     {DCM_PRCPERFORMEDSTATIONNAME, DCM_SH, "PRC Performed Station Name"},
09224     {DCM_PRCPERFORMEDLOCATION, DCM_SH, "PRC Performed Location"},
09225     {DCM_PRCPPSSTARTDATE, DCM_DA, "PRC PPS Start Date"},
09226     {DCM_PRCPPSSTARTTIME, DCM_TM, "PRC PPS Start Time"},
09227     {DCM_PRCPPSENDDATE, DCM_DA, "PRC PPS End Date"},
09228     {DCM_PRCPPSENDTIME, DCM_TM, "PRC PPS End Time"},
09229     {DCM_PRCPPSSTATUS, DCM_CS, "PRC PPS Status"},
09230 #if 0
09231     {DCM_PRCPPSID, DCM_CS, "PRC PPS ID"},
09232 #else
09233     {DCM_PRCPPSID, DCM_SH, "PRC PPS ID"},    /* RWC correction */
09234 #endif
09235     {DCM_PRCPPSDESCRIPTION, DCM_LO, "PRC PPS Description"},
09236     {DCM_PRCPPTYPEDESCRIPTION, DCM_LO, "PRC Perf Procedure Type Description"},
09237     {DCM_PRCPERFORMEDAISEQUENCE, DCM_SQ, "PRC Perf AI Sequence"},
09238     {DCM_PRCSCHEDSTEPATTRSEQ, DCM_SQ, "PRC Scheduled Step Attr Seq"},
09239     {DCM_PRCREQUESTATTRIBUTESSEQ, DCM_SQ, "PRC Request Attributes Seq"},
09240     {DCM_PRCCOMMENTSPPS, DCM_ST, "PRC Comments on PPS"},
09241     {DCM_PRCQUANTITYSEQ, DCM_SQ, "PRC Quantity Sequence"},
09242     {DCM_PRCQUANTITY, DCM_DS, "PRC Quantity"},
09243     {DCM_PRCMEASURINGUNITSSEQ, DCM_SQ, "PRC Measuring Units Sequence"},
09244     {DCM_PRCBILLINGITEMSEQ, DCM_SQ, "PRC Billing Item Seq"},
09245     {DCM_PRCTOTALTIMEFLUOROSCOPY, DCM_US, "PRC Total Time Fluoroscopy"},
09246     {DCM_PRCTOTALNUMBEREXPOSURES, DCM_US, "PRC Total Number Exposures"},
09247     {DCM_PRCENTRANCEDOSE, DCM_US, "PRC Entrance Dose"},
09248     {DCM_PRCEXPOSEDAREA, DCM_US, "PRC Exposed Area"},
09249     {DCM_PRCDISTANCESOURCEENTRANCE, DCM_DS, "PRC Distance Source to Entrance"},
09250     {DCM_PRCCOMMENTSRADIATIONDOSE, DCM_ST, "PRC Comments on Radiation Dose"},
09251 
09252     {0x00400312, DCM_DS, "PRC X-Ray Output"},           /* 2002.04.26 */
09253     {0x00400314, DCM_DS, "PRC Half Value Layer"},       /* 2002.04.26 */
09254     {0x00400316, DCM_DS, "PRC Organ Dose"},             /* 2002.04.26 */
09255     {0x00400318, DCM_CS, "PRC Organ Exposed"},          /* 2002.04.26 */
09256 
09257     {DCM_PRCBILLINGPROCEDURESTEPSEQ, DCM_SQ, "PRC Billing Proc Step Seq"},
09258     {DCM_PRCFILMCONSUMPTIONSEQ, DCM_SQ, "PRC Film Consumption Seq"},
09259     {DCM_PRCBILLINGSUPPLIESDEVICESEQ, DCM_SQ, "PRC Billing Supplies/Devices Seq"},
09260     {DCM_PRCREFERENCEDPPS, DCM_SQ, "PRC Ref Procedure Step Seq"},
09261     {DCM_PRCPERFORMEDSERIESSEQ, DCM_SQ, "PRC Performed Series Seq"},
09262     {DCM_PRCSCHEDULEDPROCSTEPSEQ, DCM_SQ, "PRC Scheduled Procedure Step Sequence"},
09263     {DCM_PRCCOMMENTSONSCHEDULEDPROCSTEP, DCM_LT, "PRC Comments on the Scheduled Procedure Step"},
09264     {DCM_MAKETAG(0x0040, 0x050a), DCM_LO, "PRC Specimen Accession Number"},     /* Sup 15 */
09265     {DCM_MAKETAG(0x0040, 0x0550), DCM_SQ, "PRC Specimen Sequence"},     /* Sup 15 */
09266     {DCM_MAKETAG(0x0040, 0x0551), DCM_LO, "PRC Specimen Identifier"},   /* Sup 15 */
09267     {DCM_MAKETAG(0x0040, 0x0552), DCM_SQ, "PRC Specimen Description Sequence"}, /* Sup 15 */
09268     {DCM_MAKETAG(0x0040, 0x0553), DCM_ST, "PRC Specimen Description"},  /* Sup 15 */
09269     {DCM_MAKETAG(0x0040, 0x0555), DCM_SQ, "PRC Acquisition Context Sequence"},  /* Sup 15 */
09270     {DCM_MAKETAG(0x0040, 0x0556), DCM_ST, "PRC Acquisition Context Description"},       /* Sup 15 */
09271     {DCM_MAKETAG(0x0040, 0x059a), DCM_SQ, "PRC Specimen Type Code Sequence"},   /* Sup 15 */
09272     {DCM_MAKETAG(0x0040, 0x06fa), DCM_LO, "PRC Slide Identifier"},      /* Sup 15 */
09273     {DCM_MAKETAG(0x0040, 0x071a), DCM_SQ, "PRC Image Center Point Coordinates Sequence"},       /* Sup 15 */
09274     {DCM_MAKETAG(0x0040, 0x072a), DCM_DS, "PRC X offset in Slide Coordinate System"},   /* Sup 15 */
09275     {DCM_MAKETAG(0x0040, 0x073a), DCM_DS, "PRC Y offset in Slide Coordinate System"},   /* Sup 15 */
09276     {DCM_MAKETAG(0x0040, 0x074a), DCM_DS, "PRC Z offset in Slide Coordinate System"},   /* Sup 15 */
09277     {DCM_MAKETAG(0x0040, 0x08d8), DCM_SQ, "PRC Pixel Spacing Sequence"},        /* Sup 15 */
09278     {DCM_MAKETAG(0x0040, 0x08da), DCM_SQ, "PRC Coordinate System Axis Code Sequence"},  /* Sup 15 */
09279     {DCM_MAKETAG(0x0040, 0x08ea), DCM_SQ, "PRC Measurement Units Code Sequence"},       /* Sup 15 */
09280     {DCM_MAKETAG(0x0040, 0x09f8), DCM_SQ, "PRC Vital Stain Code Sequence"},     /* Sup 15 */
09281     {DCM_PRCREQUESTEDPROCEDUREID, DCM_SH, "PRC Requested Procedure ID"},
09282     {DCM_PRCREASONFORREQUESTEDPROC, DCM_LO, "PRC Reason for the Requested Procedure"},
09283     {DCM_PRCREQUESTEDPROCPRIORITY, DCM_SH, "PRC Patient Transport Arrangements"},
09284     {DCM_PRCPATIENTTRANSPORTARRANGEMENTS, DCM_LO, "PRC Patient Transport Arrangements"},
09285     {DCM_PRCREQUESTEDPROCLOCATION, DCM_LO, "PRC Requested Procedure Location"},
09286     {DCM_PRCPLACERORDERNUMBERPROC, DCM_SH, "PRC Placer Order Number / Procedure"},
09287 
09288     {DCM_PRCFILLERORDERNUMBERPROC, DCM_SH, "PRC Filler Order Number / Procedure"},
09289     {DCM_PRCCONFIDENTIALITYCODE, DCM_LO, "PRC Confidentiality Code"},
09290     {DCM_PRCREPORTINGPRIORITY, DCM_SH, "PRC  Reporting Priority"},
09291     {DCM_PRCNAMESINTENDEDRECIPIENTSRESULTS, DCM_PN, "PRC Names of Intended Recipients of Results"},
09292     {DCM_PRCREQUESTEDPROCCOMMENTS, DCM_LT, "PRC Requested Procedure Comments"},
09293     {DCM_PRCREASONFORIMAGINGSERVICEREQ, DCM_LO, "PRC Reason for the Imaging Service Request"},
09294     {DCM_PRCISSUEDATEIMAGINGSERVICEREQ, DCM_DA, "PRC Issue Date of Imaging Service Request"},
09295     {DCM_PRCISSUETIMEIMAGINGSERVICEREQ, DCM_TM, "PRC Issue Time of Imaging Service Request"},
09296     {DCM_PRCPLACERORDERNUMBERIMAGINGSRVREQ, DCM_SH, "PRC Placer Order Number/Imaging Service Request"},
09297     {DCM_PRCFILLERORDERNUMBERIMAGINGSRVREQ, DCM_SH, "PRC Filler Order Number/Imaging Service Request"},
09298     {DCM_PRCORDERENTEREDBY, DCM_PN, "PRC Order Entered By"},
09299     {DCM_PRCORDERENTERERSLOCATION, DCM_SH, "PRC Order Enterer's Location"},
09300     {DCM_PRCORDERCALLBACKPHONENUMBER, DCM_SH, "PRC Order Callback Phone Number"},
09301     {DCM_MAKETAG(0x0040, 0x2016), DCM_LO, "PRC Placer Order Number/ISR"},
09302     {DCM_MAKETAG(0x0040, 0x2017), DCM_LO, "PRC Filler Order Number/ISR"},
09303 
09304     {DCM_PRCIMAGINGSERVICEREQCOMMENTS, DCM_LT, "PRC Imaging Service Request Comments"},
09305     {DCM_PRCCONFIDIENTIALITYCONSTRAINTPATIENTDATADES, DCM_LO, "PRC Confidientiality Constraint Patient Data..."},
09306 
09307     {DCM_PRCGPSPSSTATUS, DCM_CS, "PRC General Purpose Sched Procedure Step Status"},
09308     {DCM_PRCGPPPSSTATUS, DCM_CS, "PRC Gen. Purpose Perf Procedure Step Status"},
09309     {DCM_PRCGPSPSPRIORITY, DCM_CS, "PRC Gen. Purpose Sched Procedure Step Priority"},
09310     {DCM_PRCSCHEDULEDPROCAPPCODESEQ, DCM_SQ, "PRC Scheduled Proccessing Application Code Seq"},
09311     {DCM_PRCGPSPSSTARTDATETIME, DCM_DT, "PRC Sched Procedure Step Start Date and Time"},
09312     {DCM_PRCGPSPSMULTIPLECOPIESFLAG, DCM_CS, "PRC Multiple Copies Flag"},
09313     {DCM_PRCPERFORMEDPROCAPPCODESEQ, DCM_SQ, "PRC Performed Proccessing Applications Code Seq"},
09314     {DCM_PRCHUMANPERFORMERCODESEQ, DCM_SQ, "PRC Human Performer Code Sequence"},
09315     {DCM_PRCGPSPSEXPECTEDCOMPLETEDATETIME, DCM_DT, "PRC Expected Completion Date and Time"},
09316     {DCM_PRCRESULTINGGPPERFPROCSTEPSEQ, DCM_SQ, "PRC Resulting Gen Purpose Perf Proc Steps Seq"},
09317     {DCM_PRCREFERENCEDGPSCHEDPROCSTEPSEQ, DCM_SQ, "PRC Referenced Gen Purp Sched Proc Steps Seq"},
09318     {DCM_PRCSCHEDWORKITEMCODESEQ, DCM_SQ, "PRC Scheduled Workitem Code Sequence"},
09319     {DCM_PRCPERFORMEDWORKITEMCODESEQ, DCM_SQ, "PRC Performed Workitem Code Sequence"},
09320     {DCM_PRCINPUTAVAILFLAG, DCM_CS, "PRC Input Availability Flag"},
09321     {DCM_PRCINPUTINFOSEQ, DCM_SQ, "PRC Input Information Sequence"},
09322     {DCM_PRCRELEVANTINFOSEQ, DCM_SQ, "PRC Relevant Information Sequence"},
09323     {DCM_PRCREFERENCEDGPSPSTRANSACTIONUID, DCM_UI, "PRC Referenced Gen Purp SPS Transaction UID"},
09324     {DCM_PRCSCHEDSTATIONNAMECODESEQ, DCM_SQ, "PRC Scheduled Station Name Code Sequence"},
09325     {DCM_PRCSCHEDSTATIONCLASSCODESEQ, DCM_SQ, "PRC Scheduled Station Class Code Sequence"},
09326     {DCM_PRCSCHEDSTATIONLOCCODESEQ, DCM_SQ, "PRC Sched Station Geographic Location Code Seq"},
09327     {DCM_PRCPERFORMEDSTATIONNAMECODESEQ, DCM_SQ, "PRC Performed Station Name Code Seq"},
09328     {DCM_PRCPERFORMEDSTATIONCLASSCODESEQ, DCM_SQ, "PRC Performed Station Class Code Sequence"},
09329     {DCM_PRCPERFORMEDSTATIONLOCCODESEQ, DCM_SQ, "PRC Perf Station Geographic Location Code Seq"},
09330     {DCM_PRCREQSUBSWORKITEMCODESEQ, DCM_SQ, "PRC Requested Subsequent Workitem Code Sequence"},
09331     {DCM_PRCNONDICOMOUTPUTCODESEQ, DCM_SQ, "PRC Non-DICOM Output Code Sequence"},
09332     {DCM_PRCOUTPUTINFOSEQ, DCM_SQ, "PRC Output Information Sequence"},
09333     {DCM_PRCSCHEDHUMANPERFORMERSSEQ, DCM_SQ, "PRC Scheduled Human Performers Sequence"},
09334     {DCM_PRCHUMANPERFORMERSORG, DCM_LO, "PRC Human Performer's Organization"},
09335     {DCM_PRCHUMANPERFORMERSNAME, DCM_PN, "PRC Human Performer's Name"},
09336 
09337 
09338     {DCM_MAKETAG(0x0040, 0xa010), DCM_CS, "PRC Relationship Type"}, /* Sup 23*/
09339     {DCM_MAKETAG(0x0040, 0xa027), DCM_LO, "PRC Verifying Organization"}, /* Sup 23*/
09340     {DCM_MAKETAG(0x0040, 0xa030), DCM_DT, "PRC Verification DateTime"}, /* Sup 23*/
09341     {DCM_MAKETAG(0x0040, 0xa032), DCM_DT, "PRC Observation DateTime"}, /* Sup 23*/
09342     {DCM_MAKETAG(0x0040, 0xa040), DCM_CS, "PRC Value Type"}, /* Sup 23*/
09343 
09344     {DCM_MAKETAG(0x0040, 0xa043), DCM_SQ, "PRC Concept-name Code Sequence"},    /* Sup 23 */
09345     {DCM_MAKETAG(0x0040, 0xa050), DCM_CS, "PRC Continuity of Content"}, /* Sup 23*/
09346     {DCM_MAKETAG(0x0040, 0xa073), DCM_SQ, "PRC Verifying Observer Sequence"}, /* Sup 23*/
09347     {DCM_MAKETAG(0x0040, 0xa075), DCM_PN, "PRC Verifying Observer Name"}, /* Sup 23*/
09348     {DCM_MAKETAG(0x0040, 0xa088), DCM_SQ, "PRC Verifying Observer Identification Code Seq"}, /* Sup 23*/
09349     {DCM_MAKETAG(0x0040, 0xa0a0), DCM_CS, "PRC Referenced Type of Data"},       /* Sup 30 0.6 */
09350     {DCM_MAKETAG(0x0040, 0xa0b0), DCM_US, "PRC Referenced Waveform Channels"},  /* Sup 30 0.6 */
09351     {DCM_MAKETAG(0x0040, 0xa120), DCM_DT, "PRC Date Time"}, /* Sup 23*/
09352     {DCM_MAKETAG(0x0040, 0xa121), DCM_DA, "PRC Date"},  /* Sup 15 */
09353     {DCM_MAKETAG(0x0040, 0xa122), DCM_TM, "PRC Time"},  /* Sup 15 */
09354     {DCM_MAKETAG(0x0040, 0xa123), DCM_PN, "PRC Person Name"},   /* Sup 15 */
09355     {DCM_MAKETAG(0x0040, 0xa124), DCM_UI, "PRC UID"}, /* Sup 23*/
09356     {DCM_MAKETAG(0x0040, 0xa130), DCM_CS, "PRC Temporal Range Type"},   /* Sup 30 0.6 */
09357     {DCM_MAKETAG(0x0040, 0xa132), DCM_UL, "PRC Referenced Sample Offsets"},     /* Sup 30 0.6 */
09358     {DCM_MAKETAG(0x0040, 0xa138), DCM_DS, "PRC Referenced Time Offsets"},       /* Sup 30 0.6 */
09359     {DCM_MAKETAG(0x0040, 0xa13a), DCM_DT, "PRC Referenced Datetime"},   /* Sup 30 0.6 */
09360     {DCM_MAKETAG(0x0040, 0xa160), DCM_UT, "PRC Text Value"},    /* */
09361     {DCM_MAKETAG(0x0040, 0xa168), DCM_SQ, "PRC Concept Code Sequence"}, /* Sup 15 */
09362     {DCM_MAKETAG(0x0040, 0xa16a), DCM_ST, "PRC Bibliographics Citation"},       /* Sup 15 */
09363     {DCM_MAKETAG(0x0040, 0xa180), DCM_US, "PRC Annotation Group Number"},       /* Sup 30 0.6 */
09364     {DCM_MAKETAG(0x0040, 0xa195), DCM_SQ, "PRC Concept-name Code Sequence Modifier"},   /* Sup 15 */
09365 
09366     {DCM_MAKETAG(0x0040, 0xa300), DCM_SQ, "PRC Measured Value Sequence"}, /* Sup 23 */
09367     {DCM_MAKETAG(0x0040, 0xa30a), DCM_DS, "PRC Numeric Value"}, /* Sup 15 */
09368     {DCM_MAKETAG(0x0040, 0xa353), DCM_ST, "PRC Address"},       /* Sup 15 */
09369     {DCM_MAKETAG(0x0040, 0xa354), DCM_LO, "PRC Telephone Number"},      /* Sup 15 */
09370     {DCM_MAKETAG(0x0040, 0xa360), DCM_SQ, "PRC Predecessor Documents Sequence"}, /* Sup 23 */
09371     {DCM_MAKETAG(0x0040, 0xa370), DCM_SQ, "PRC Referenced Request Sequence"}, /* Sup 23 */
09372     {DCM_MAKETAG(0x0040, 0xa372), DCM_SQ, "PRC Performed Procedure Code Sequence"}, /* Sup 23 */
09373     {DCM_MAKETAG(0x0040, 0xa375), DCM_SQ, "PRC Current Reqeusted Procedure Evidence Seq"}, /* Sup 23 */
09374     {DCM_MAKETAG(0x0040, 0xa385), DCM_SQ, "PRC Pertinent Other Evidence Sequence"}, /* Sup 23 */
09375     {DCM_MAKETAG(0x0040, 0xa491), DCM_CS, "PRC Completion Flag"}, /* Sup 23 */
09376     {DCM_MAKETAG(0x0040, 0xa492), DCM_LO, "PRC Completion Flag Description"}, /* Sup 23 */
09377     {DCM_MAKETAG(0x0040, 0xa493), DCM_CS, "PRC Verification Flag"}, /* Sup 23 */
09378     {DCM_MAKETAG(0x0040, 0xa504), DCM_SQ, "PRC Content Template Sequence"}, /* Sup 23 */
09379     {DCM_MAKETAG(0x0040, 0xa525), DCM_SQ, "PRC Identical Documents Sequence"}, /* Sup 23 */
09380     {DCM_MAKETAG(0x0040, 0xa730), DCM_SQ, "PRC Content Sequence"}, /* Sup 23 */
09381     {DCM_MAKETAG(0x0040, 0xa992), DCM_ST, "PRC Uniform Resource Locator"},      /* Sup 15 */
09382     {DCM_MAKETAG(0x0040, 0xb020), DCM_SQ, "PRC Annotation Sequence"},   /* Sup 30 0.6 */
09383     {DCM_MAKETAG(0x0040, 0xadb00), DCM_CS, "PRC Template Identifier"}, /* Sup 23 */
09384     {DCM_MAKETAG(0x0040, 0xadb06), DCM_DT, "PRC Template Version"}, /* Sup 23 */
09385     {DCM_MAKETAG(0x0040, 0xadb07), DCM_DT, "PRC Template Local Version"}, /* Sup 23 */
09386     {DCM_MAKETAG(0x0040, 0xadb0b), DCM_CS, "PRC Template Extension Flag"}, /* Sup 23 */
09387     {DCM_MAKETAG(0x0040, 0xadb0c), DCM_UI, "PRC Template Extension Organization UID"}, /* Sup 23 */
09388     {DCM_MAKETAG(0x0040, 0xadb0d), DCM_UI, "PRC Template Extension Creator UID"}, /* Sup 23 */
09389     {DCM_MAKETAG(0x0040, 0xadb73), DCM_UL, "PRC Referenced Content Item Identifier"} /* Sup 23 */
09390 };
09391 
09392 /* Define the entries for the DEVICE group, 0050
09393 */
09394 static DCMDICT DEV_dictionary[] = {
09395     {DCM_DEVCALIBRATIONOBJECT, DCM_CS, "DEV Calibration Object"},
09396     {DCM_DEVDEVICESEQUENCE, DCM_SQ, "DEV Device Sequence"},
09397     {DCM_DEVDEVICELENGTH, DCM_DS, "DEV Device Length"},
09398     {DCM_DEVDEVICEDIAMETER, DCM_DS, "DEV Device Diameter"},
09399     {DCM_DEVDEVICEDIAMETERUNITS, DCM_CS, "DEV Device Diameter Units"},
09400     {DCM_DEVDEVICEVOLUME, DCM_DS, "DEV Device Volume"},
09401     {DCM_DEVINTERMARKERDISTANCE, DCM_DS, "DEV Inter-Marker Distance"},
09402     {DCM_DEVDEVICEDESCRIPTION, DCM_LO, "DEV Device Description"},
09403 };
09404 
09405 /* Define the entries for the RESULTS group, 4008
09406 */
09407 static DCMDICT RES_dictionary[] = {
09408     {DCM_RESGROUPLENGTH, DCM_UL, "RES Group Length"},
09409     {DCM_RESID, DCM_SH, "RES Results ID"},
09410     {DCM_RESIDISSUER, DCM_LO, "RES Results ID Issuer"},
09411     {DCM_RESREFERENCEDINTERPSEQ, DCM_SQ, "RES Referenced Interpretation Sequence"},
09412     {DCM_RESINTERPRECORDEDDATE, DCM_DA, "RES Interpretation Recorded Date"},
09413     {DCM_RESINTERPRECORDEDTIME, DCM_TM, "RES Interpretation Recorded Time"},
09414     {DCM_RESINTERPRECORDER, DCM_PN, "RES Interpretation Recorder"},
09415     {DCM_RESREFERENCETORECORDEDSOUND, DCM_LO, "RES Reference to Recorded Sound"},
09416     {DCM_RESINTERPTRANSCRIPTIONDATE, DCM_DA, "RES Interpretation Transcription Date"},
09417     {DCM_RESINTERPTRANSCRIPTIONTIME, DCM_TM, "RES Interpretation Transcription Time"},
09418     {DCM_RESINTERPTRANSCRIBER, DCM_PN, "RES Interpretation Transcriber"},
09419     {DCM_RESINTERPTEXT, DCM_ST, "RES Interpretation Text"},
09420     {DCM_RESINTERPAUTHOR, DCM_PN, "RES Interpretation Author"},
09421     {DCM_RESINTERPAPPROVERSEQUENCE, DCM_SQ, "RES Interpretation Approver Sequence"},
09422     {DCM_RESINTERPAPPROVALDATE, DCM_DA, "RES Interpretation Approval Date"},
09423     {DCM_RESINTERPAPPROVALTIME, DCM_TM, "RES Interpretation Approval Time"},
09424     {DCM_RESPHYSICIANAPPROVINGINTERP, DCM_PN, "RES Physician Approving Interpretation"},
09425     {DCM_RESDIAGNOSIS, DCM_LT, "RES Diagnosis"},
09426     {DCM_RESDIAGNOSISCODESEQ, DCM_SQ, "RES Diagnosis Code Sequence"},
09427     {DCM_RESDISTRIBUTIIONLISTSEQUENCE, DCM_SQ, "RES Results Distribution List Sequence"},
09428     {DCM_RESDISTRIBUTIONNAME, DCM_PN, "RES Distribution Name"},
09429     {DCM_RESDISTRIBUTIONADDRESS, DCM_LO, "RES Distribution Address"},
09430     {DCM_RESINTERPID, DCM_SH, "RES Interpretation ID"},
09431     {DCM_RESINTERPIDISSUER, DCM_LO, "RES Interpretation ID Issuer"},
09432     {DCM_RESINTERPTYPEID, DCM_CS, "RES Interpretation Type ID"},
09433     {DCM_RESINTERPSTATUSID, DCM_CS, "RES Interpretation Status ID"},
09434     {DCM_RESIMPRESSIONS, DCM_ST, "RES Impressions"},
09435     {DCM_RESCOMMENTS, DCM_ST, "RES Comments"}
09436 };
09437 
09438 /* Define entries for the CURVE group */
09439 static DCMDICT CRV_dictionary[] = {
09440     {DCM_CURVEGROUPLENGTH, DCM_UL, "CRV Group Length"},
09441     {DCM_CURVEDIMENSIONS, DCM_US, "CRV Curve Dimensions"},
09442     {DCM_CURVENUMBEROFPOINTS, DCM_US, "CRV Number of points"},
09443     {DCM_CURVETYPEOFDATA, DCM_CS, "CRV Type of Data"},
09444     {DCM_CURVEDESCRIPTION, DCM_LO, "CRV Curve Description"},
09445     {DCM_CURVEAXISUNITS, DCM_SH, "CRV Axis Units"},
09446     {DCM_CURVEAXISLABELS, DCM_SH, "CRV Axis Labels"},
09447     {DCM_CURVEDATAVALUEREPRESENTATION, DCM_US, "CRV Data Value Representation"},
09448     {DCM_CURVEMINCOORDINATEVALUE, DCM_US, "CRV Minimum Coordinate Value"},
09449     {DCM_CURVEMAXCOORDINATEVALUE, DCM_US, "CRV Maximum Coordinate Value"},
09450     {DCM_CURVERANGE, DCM_SH, "CRV Curve Range"},
09451     {DCM_CURVEDATADESCRIPTOR, DCM_US, "CRV Data Descriptor"},
09452     {DCM_CURVECOORDINATESTARTVALUE, DCM_US, "CRV Coordinate Start Value"},
09453     {DCM_CURVECOORDINATESTEPVALUE, DCM_US, "CRV Coordinate Step Value"},
09454     {DCM_CURVEAUDIOTYPE, DCM_US, "CRV Audio Type"},
09455     {DCM_CURVEAUDIOSAMPLEFORMAT, DCM_US, "CRV Audio Sample Format"},
09456     {DCM_CURVENUMBEROFCHANNELS, DCM_US, "CRV Number of Channels"},
09457     {DCM_CURVENUMBEROFSAMPLES, DCM_UL, "CRV Number of Samples"},
09458     {DCM_CURVESAMPLERATE, DCM_UL, "CRV Sample Rate"},
09459     {DCM_CURVETOTALTIME, DCM_UL, "CRV Total Time"},
09460     {DCM_CURVEAUDIOSAMPLEDATA, DCM_OW, "CRV Audio Sample Data"},
09461     {DCM_CURVEAUDIOCOMMENTS, DCM_LT, "CRV Audio Comments"},
09462     {DCM_CURVELABEL, DCM_LO, "CRV Curve Label"},
09463     {DCM_CURVEREFOVERLAYSEQUENCE, DCM_SQ, "CRV Referenced Overlay Sequence"},
09464     {DCM_CURVEREFOVERLAYGROUP, DCM_US, "CRV Referenced Overlay Group"},
09465     {DCM_CURVEDATA, DCM_OW, "CRV Curve Data"}
09466 };
09467 
09468 /* Define the entries for the NMI (nuclear medicine image) group, 0054 */
09469 static DCMDICT NMI_dictionary[] = {
09470     {DCM_NMIGROUPLENGTH, DCM_UL, "NMI Group Length"},
09471     {DCM_NMIENERGYWINDOWVECTOR, DCM_US, "NMI Energy Window Vector"},
09472     {DCM_NMINUMBEROFENERGYWINDOWS, DCM_US, "NMI Number of Energy Windows"},
09473     {DCM_NMIENERGYWINDOWINFOSEQ, DCM_SQ, "NMI Energy Window Information Sequence"},
09474     {DCM_NMIENERGYWINDOWRANGESEQ, DCM_SQ, "NMI Energy Window Range Sequence"},
09475     {DCM_NMIENERGYWINDOWLOWERLIMIT, DCM_DS, "NMI Energy Window Lower Limit"},
09476     {DCM_NMIENERGYWINDOWUPPERLIMIT, DCM_DS, "NMI Energy Window Upper Limit"},
09477     {DCM_NMIRADIOPHARMINFOSEQ, DCM_SQ, "NMI Radiopharmaceutical Information Sequence"},
09478     {DCM_NMIRESIDUALSYRINGECOUNTS, DCM_IS, "NMI Residual Syringe Counts"},
09479     {DCM_NMIENERGYWINDOWNAME, DCM_SH, "NMI Energy Window Name"},
09480     {DCM_NMIDETECTORVECTOR, DCM_US, "NMI Detector Vector"},
09481     {DCM_NMINUMBEROFDETECTORS, DCM_US, "NMI Number of Detectors"},
09482     {DCM_NMIDETECTORINFOSEQUENCE, DCM_SQ, "NMI Detector Information Sequence"},
09483     {DCM_NMIPHASEVECTOR, DCM_US, "NMI Phase Vector"},
09484     {DCM_NMINUMBEROFPHASES, DCM_US, "NMI Number of Phases"},
09485     {DCM_NMIPHASEINFOSEQUENCE, DCM_SQ, "NMI Phase Information Sequence"},
09486     {DCM_NMINUMBEROFFRAMESINPHASE, DCM_US, "NMI Number of Frames in Phase"},
09487     {DCM_NMIPHASEDELAY, DCM_IS, "NMI Phase Delay"},
09488     {DCM_NMIPAUSEBETWEENFRAMES, DCM_IS, "NMI Pause between Frames"},
09489     {DCM_NMIROTATIONVECTOR, DCM_US, "NMI Rotation Vector"},
09490     {DCM_NMINUMBEROFROTATIONS, DCM_US, "NMI Number of rotations"},
09491     {DCM_NMIROTATIONINFOSEQUENCE, DCM_SQ, "NMI Rotation Information Sequence"},
09492     {DCM_NMINUMBEROFFRAMESINROTATION, DCM_US, "NMI Number of frames in rotation"},
09493     {DCM_NMIRRINTERVALVECTOR, DCM_US, "NMI R-R Interval Vector"},
09494     {DCM_NMINUMBEROFRRINTERVALS, DCM_US, "NMI Number of R-R Intervals"},
09495     {DCM_NMIGATEDINFOSEQUENCE, DCM_SQ, "NMI Gated Information Sequence"},
09496     {DCM_NMIDATAINFORMATIONSEQUENCE, DCM_SQ, "NMI Data Information Sequence"},
09497     {DCM_NMITIMESLOTVECTOR, DCM_US, "NMI Time Slot Vector"},
09498     {DCM_NMINUMBEROFTIMESLOTS, DCM_US, "NMI Number of Time Slots"},
09499     {DCM_NMITIMESLOTINFOSEQUENCE, DCM_SQ, "NMI Time Slot Information Sequence"},
09500     {DCM_NMITIMESLOTTIME, DCM_DS, "NMI Time Slot Time"},
09501     {DCM_NMISLICEVECTOR, DCM_US, "NMI Slice Vector"},
09502     {DCM_NMINUMBEROFSLICES, DCM_US, "NMI Number of Slices"},
09503     {DCM_NMIANGULARVIEWVECTOR, DCM_US, "NMI Angular View Vector"},
09504     {DCM_NMITIMESLICEVECTOR, DCM_US, "NMI Time Slice Vector"},
09505     {DCM_NMINUMBEROFTIMESLICES, DCM_US, "NMI Number of Time Slices"},
09506     {DCM_NMISTARTANGLE, DCM_DS, "NMI Start Angle"},
09507     {DCM_NMITYPEOFDETECTORMOTION, DCM_CS, "NMI Type of Detector Motion"},
09508     {DCM_NMITRIGGERVECTOR, DCM_IS, "NMI Trigger Vector"},
09509     {DCM_NMINUMBEROFTRIGGERSINPHASE, DCM_US, "NMI Number of Triggers in Phase"},
09510     {DCM_NMIVIEWCODESEQUENCE, DCM_SQ, "NMI View Code Sequence"},
09511     {DCM_NMIVIEWANGULATIONMODIFIERCODESEQ, DCM_SQ, "NMI View Angulation Modifer Code Sequence"},
09512     {DCM_NMIRADIONUCLIDECODESEQUENCE, DCM_SQ, "NMI Radionuclide Code Sequence"},
09513     {DCM_NMIRADIOPHARMROUTECODESEQUENCE, DCM_SQ, "NMI Radiopharmaceutical Route Code Sequence"},
09514     {DCM_NMIRADIOPHARMCODESEQUENCE, DCM_SQ, "NMI Radiopahrmaceutical Code Sequence"},
09515     {DCM_NMICALIBRATIONDATASEQUENCE, DCM_SQ, "NMI Calibration Data Sequence"},
09516     {DCM_NMIENERGYWINDOWNUMBER, DCM_US, "NMI Energy Window Number"},
09517     {DCM_NMIIMAGEID, DCM_SH, "NMI Image ID"},
09518     {DCM_NMIPATIENTORIENTATIONCODESEQ, DCM_SQ, "NMI Patient Orientation Code Sequence"},
09519     {DCM_NMIPATIENTORIENTATIONMODIFIERCODESEQ, DCM_SQ, "NMI Patient Orientation Modifier Code Sequence"},
09520     {DCM_NMIPATIENTGANTRYRELATIONSHIPCODESEQ, DCM_SQ, "NMI Patient Gantry Relationship Code Sequence"},
09521     {DCM_NMISERIESTYPE, DCM_CS, "NMI Series Type"},
09522     {DCM_NMIUNITS, DCM_CS, "NMI Units"},
09523     {DCM_NMICOUNTSSOURCE, DCM_CS, "NMI Counts Source"}, /* 1002 */
09524     {DCM_NMIREPROJECTIONMETHOD, DCM_CS, "NMI Reprojection Method"},     /* 1004 */
09525     {DCM_NMIRANDOMSCORRECTIONMETHOD, DCM_CS,
09526     "NMI Randoms Correction Method"},   /* 1100 */
09527     {DCM_NMIATTENUATIONCORRECTIONMETHOD, DCM_LO,
09528     "NMI Attenuation Correction Method"},       /* 1101 */
09529     {DCM_NMIDECAYCORRECTION, DCM_CS, "NMI Decay Correction"},   /* 1102 */
09530     {DCM_NMIRECONSTRUCTIONMETHOD, DCM_LO, "NMI Reconstruction Method"}, /* 1103 */
09531     {DCM_NMIDETECTORLINESRESPONSEUSED, DCM_LO,
09532     "NMI Detector Lines of Response Used"},     /* 1104 */
09533     {DCM_NMISCATTERCORRECTIONMETHOD, DCM_LO, "NMI Scatter Correction Method"},  /* 1105 */
09534     {DCM_NMIAXIALACCEPTANCE, DCM_DS, "NMI Axial Acceptance"},   /* 1200 */
09535     {DCM_NMIAXIALMASH, DCM_IS, "NMI Axial Mash"},       /* 1201 */
09536     {DCM_NMITRANSVERSEMASH, DCM_IS, "NMI Transverse Mash"},     /* 1202 */
09537     {DCM_NMIDETECTORELEMENTSIZE, DCM_DS, "NMI Detector Element Size"},  /* 1203 */
09538     {DCM_NMICOINCIDENCEWINDOWWIDTH, DCM_DS, "NMI Coincidence Window Width"},    /* 1210 */
09539     {DCM_NMISECONDARYCOUNTSTYPE, DCM_CS, "NMI Secondary Counts Type"},  /* 1220 */
09540     {DCM_NMIFRAMEREFERENCETIME, DCM_DS, "NMI Frame Reference Time"},    /* 1300 */
09541     {DCM_NMIPRIMARYCOUNTSACCUMULATED, DCM_IS,
09542     "NMI Primary (Prompts) Counts Accumulated"},        /* 1310 */
09543     {DCM_NMISECONDARYCOUNTSACCUMULATED, DCM_IS,
09544     "NMI Secondary Counts Accumulated"},        /* 1311 */
09545     {DCM_NMISLICESENSITIVITYFACTOR, DCM_DS, "NMI Slice Sensitivity Factor"},    /* 1320 */
09546     {DCM_NMIDECAYFACTOR, DCM_DS, "NMI Decay Factor"},   /* 1321 */
09547     {DCM_NMIDOSECALIBRATIONFACTOR, DCM_DS, "NMI Dose Calibration Factor"},      /* 1322 */
09548     {DCM_NMISCATTERFRACTIONFACTOR, DCM_DS, "NMI Scatter Fraction Factor"},      /* 1323 */
09549     {DCM_NMIDEADTIMEFACTOR, DCM_DS, "NMI Dead Time Factor"},    /* 1324 */
09550     {DCM_NMIIMAGEINDEX, DCM_US, "NMI Image Index"},     /* 1330 */
09551     {DCM_NMICOUNTSINCLUDED, DCM_CS, "NMI Counts Included"},     /* 1400 */
09552     {DCM_NMIDEADTIMECORRECTIONFLAG, DCM_CS,
09553     "NMI Dead Time Correction Flag"},   /* 1401 */
09554 };
09555 
09556 /* Define the entries for the Graphics group, 0070 */
09557 static DCMDICT GRP_dictionary[] = {
09558     {DCM_MAKETAG(0x0070, 0x0000), DCM_UL, "GRP Group Length"},
09559     {DCM_MAKETAG(0x0070, 0x0022), DCM_FL, "GRP Graphic Data"}, /* Sup 33 */
09560     {DCM_MAKETAG(0x0070, 0x0023), DCM_CS, "GRP Graphic Type"}, /* Sup 33 */
09561     {DCM_MAKETAG(0x0070, 0x0024), DCM_CS, "GRP Graphic Filled"}, /* Sup 33 */
09562     {DCM_MAKETAG(0x0070, 0x0041), DCM_CS, "GRP Image Horizontal Flip"}, /* Sup 33*/
09563     {DCM_MAKETAG(0x0070, 0x0042), DCM_US, "GRP Image Rotation"}, /* Sup 33 */
09564     {DCM_MAKETAG(0x0070, 0x0052), DCM_SL, "GRP Displayed Area Top LH Corner"},
09565     {DCM_MAKETAG(0x0070, 0x0053), DCM_SL, "GRP Displayed Area Bottom RH Corner"},
09566     {DCM_MAKETAG(0x0070, 0x005a), DCM_SQ, "GRP Display Area Selection Seq"},
09567     {DCM_MAKETAG(0x0070, 0x0060), DCM_SQ, "GRP Graphic Layer Sequence"},
09568     {DCM_MAKETAG(0x0070, 0x0062), DCM_IS, "GRP Graphic Layer Order"},
09569     {DCM_MAKETAG(0x0070, 0x0066), DCM_US, "GRP Graphic Layer Rec Disp GS Val"},
09570     {DCM_MAKETAG(0x0070, 0x0067), DCM_US, "GRP Graphic Layer Rec Disp RGB Val"},
09571     {DCM_MAKETAG(0x0070, 0x0068), DCM_LO, "GRP Graphic Layer Description"},
09572 
09573     {DCM_MAKETAG(0x0070, 0x0080), DCM_CS, "GRP Presentation Label"}, /* Sup 33 */
09574     {DCM_MAKETAG(0x0070, 0x0081), DCM_LO, "GRP Presentation Description"}, /* Sup 33 */
09575     {DCM_MAKETAG(0x0070, 0x0082), DCM_DA, "GRP Presentation Creation Date"}, /* Sup 33 */
09576     {DCM_MAKETAG(0x0070, 0x0083), DCM_TM, "GRP Presentation Creation Time"}, /* Sup 33 */
09577     {DCM_MAKETAG(0x0070, 0x0084), DCM_PN, "GRP Presentation Creators Name"}, /* Sup 33 */
09578     {DCM_MAKETAG(0x0070, 0x0100), DCM_CS, "GRP Presentation Size Mode"}, /* Sup 33 */
09579     {DCM_MAKETAG(0x0070, 0x0101), DCM_DS, "GRP Presentation Pixel Spacing"}, /* Sup 33 */
09580     {DCM_MAKETAG(0x0070, 0x0102), DCM_IS, "GRP Presentation Pixel Aspect Ratio"}, /* Sup 33 */
09581     {DCM_MAKETAG(0x0070, 0x0103), DCM_FL, "GRP Presentation Pixel Magnification Ratio"}, /* Sup 33 */
09582 };
09583 
09584 /* Define the entries for the OLY (Overlay) group */
09585 static DCMDICT OLY_dictionary[] = {
09586     {DCM_OLYGROUPLENGTH, DCM_UL, "OLY Group Length"},
09587     {DCM_OLYROWS, DCM_US, "OLY Rows"},
09588     {DCM_OLYCOLUMNS, DCM_US, "OLY Columns"},
09589     {DCM_OLYPLANES, DCM_US, "OLY Planes"},
09590     {DCM_OLYNUMBEROFFRAMESINOVERLAY, DCM_IS, "OLY Number of frames in Overlay"},
09591     {DCM_OLYOVERLAYDESCRIPTION, DCM_LO, "OLY Overlay Description"},
09592     {DCM_OLYTYPE, DCM_CS, "OLY Type"},
09593     {DCM_OLYSUBTYPE, DCM_LO, "OLY Subtype"},
09594     {DCM_OLYORIGIN, DCM_SS, "OLY Origin"},
09595     {DCM_OLYIMAGEFRAMEORIGIN, DCM_US, "OLY Image Frame Origin"},
09596     {DCM_OLYOVERLAYPLANEORIGIN, DCM_US, "OLY Overlay Plane Origin"},
09597     {DCM_OLYCOMPRESSIONCODE, DCM_LO, "OLY Compression Code (RET)"},
09598     {DCM_OLYBITSALLOCATED, DCM_US, "OLY Overlay Bits Allocated"},
09599     {DCM_OLYBITPOSITION, DCM_US, "OLY Overlay Bit Position"},
09600     {DCM_OLYOVERLAYFORMAT, DCM_LO, "OLY Overlay Format (RET)"},
09601     {DCM_OLYOVERLAYLOCATION, DCM_US, "OLY Overlay Location (RET)"},
09602     {DCM_OLYDESCRIPTORGRAY, DCM_US, "OLY Overlay Descriptor - Gray"},
09603     {DCM_OLYDESCRIPTORRED, DCM_US, "OLY Overlay Descriptor - Red"},
09604     {DCM_OLYDESCRIPTORGREEN, DCM_US, "OLY Overlay Descriptor - Green"},
09605     {DCM_OLYDESCRIPTORBLUE, DCM_US, "OLY Overlay Descriptor - Blue"},
09606     {DCM_OLYGRAY, DCM_US, "OLY Overlays - Gray"},
09607     {DCM_OLYRED, DCM_US, "OLY Overlays - Red"},
09608     {DCM_OLYGREEN, DCM_US, "OLY Overlays - Green"},
09609     {DCM_OLYBLUE, DCM_US, "OLY Overlays - Blue"},
09610     {DCM_OLYROIAREA, DCM_IS, "OLY ROI Area"},
09611     {DCM_OLYROIMEAN, DCM_DS, "OLY ROI Mean"},
09612     {DCM_OLYROISTANDARDDEVIATION, DCM_DS, "OLY ROI Standard Deviation"},
09613     {DCM_OLYOVERLAYLABEL, DCM_LO, "OLY Overlay Label"},
09614     {DCM_OLYDATA, DCM_OW, "OLY Data"},
09615     {DCM_OLYCOMMENTS, DCM_LO, "OLY Comments (RET)"}
09616 };
09617 
09618 /* Define the entries for the PIXEL group (7FE0)
09619 */
09620 static DCMDICT PXL_dictionary[] = {
09621     {DCM_PXLGROUPLENGTH, DCM_UL, "PXL Group Length"},
09622     {DCM_PXLPIXELDATA, DCM_OT, "PXL Pixel Data"}
09623 };
09624 
09625 /* Define the elements for the MEDIA group (0088) */
09626 static DCMDICT MED_dictionary[] = {
09627     {DCM_MEDIAGROUPLENGTH, DCM_UL, "MED Media Group Length "},
09628     {DCM_MEDIASTORAGEFILESETID, DCM_SH, "MED Storage Media File-set ID"},
09629     {DCM_MEDIASTORAGEFILESETUID, DCM_UI, "MED Storage Media File-setUID"},
09630     {DCM_MEDIAICONIMAGE, DCM_SQ, "MED Icon Image Sequence"},
09631     {DCM_MEDIATOPICTITLE, DCM_LO, "MED Topic Title"},
09632     {DCM_MEDIATOPICSUBJECT, DCM_ST, "MED Topic Subject"},
09633     {DCM_MEDIATOPICAUTHOR, DCM_LO, "MED Topic Author"},
09634     {DCM_MEDIATOPICKEYWORD, DCM_LO, "MED Topic Keywords"}
09635 };
09636 
09637 /* Define the entries in the BASICFILMSESSION group (2000)
09638 */
09639 static DCMDICT BFS_dictionary[] = {
09640     {DCM_BFSGROUPLENGTH, DCM_UL, "BFS Group Length"},
09641     {DCM_BFSCOPIES, DCM_IS, "BFS Number of copies printed for each film"},
09642     {DCM_BFSPRINTPRIORITY, DCM_CS, "BFS Specifies priority of print job"},
09643     {DCM_BFSMEDIUMTYPE, DCM_CS, "BFS Medium on which page will be printed"},
09644     {DCM_BFSFILMDESTINATION, DCM_CS, "BFS Film destination"},
09645     {DCM_BFSFILMSESSIONLABEL, DCM_LO, "BFS Human readable label to identify film"},
09646     {DCM_BFSMEMORYALLOCATION, DCM_IS, "BFS Amount of mem allocated for film session"},
09647     {DCM_BFSREFERENCEDFILMBOXSEQ, DCM_SQ, "BFS seq of UIDs of diff FILMBOX instances"}
09648 };
09649 
09650 /* Define the entries in the BASICFILMBOX group (2010)
09651 */
09652 static DCMDICT BFB_dictionary[] = {
09653     {DCM_BFBGROUPLENGTH, DCM_UL, "BFB Group Length"},
09654     {DCM_BFBIMAGEDISPLAYFORMAT, DCM_ST, "BFB Type of image display format"},
09655     {DCM_BFBANNOTATIONDISPLAYFORMAT, DCM_CS, "BFB Id of annotation display format"},
09656     {DCM_BFBFILMORIENTATION, DCM_CS, "BFB Film orientation"},
09657     {DCM_BFBFILMSIZEID, DCM_CS, "BFB Film size identification"},
09658     {DCM_BFBMAGNIFICATIONTYPE, DCM_CS, "BFB Interpol. type by which printer mag image"},
09659     {DCM_BFBSMOOTHINGTYPE, DCM_CS, "BFB Specifies type of interpolation function"},
09660     {DCM_BFBBORDERDENSITY, DCM_CS, "BFB density of film areas around/between images"},
09661     {DCM_BFBEMPTYIMAGEDENSITY, DCM_CS, "BFB density of image box area having no image"},
09662     {DCM_BFBMINDENSITY, DCM_US, "BFB Minimum density of images on the film"},
09663     {DCM_BFBMAXDENSITY, DCM_US, "BFB Maximum density of images on the film"},
09664     {DCM_BFBTRIM, DCM_CS, "BFB specifies whether to trim or not"},
09665     {DCM_BFBCONFIGURATIONINFO, DCM_ST, "BFB ID of configuration table"},
09666     {DCM_BFBREFBASICFILMSESSIONSEQ, DCM_SQ, "BFB seq. of film session instance"},
09667     {DCM_BFBREFBASICIMAGEBOXSEQ, DCM_SQ, "BFB seq. of basic image box SOP instance"},
09668     {DCM_BFBREFBASICANNOTBOXSEQ, DCM_SQ, "BFB seq. of basic annotation box SOP instance"},
09669 };
09670 
09671 /* Defines the entries in the BASICIMAGEBOX (2020)
09672 */
09673 static DCMDICT BIB_dictionary[] = {
09674     {DCM_BIBGROUPLENGTH, DCM_UL, "BIB Group Length"},
09675     {DCM_BIBIMAGEPOSITION, DCM_US, "BIB Specifies position of the image in the film"},
09676     {DCM_BIBPOLARITY, DCM_CS, "BIB Specifies image polarity"},
09677     {DCM_BIBREQUESTEDIMAGESIZE, DCM_DS, "BIB Requested image size"},
09678     {DCM_BIBPREFORMATGREYSCALEIMAGESEQ, DCM_SQ, "BIB Preformatted Greyscale image"},
09679     {DCM_BIBPREFORMATCOLORIMAGESEQ, DCM_SQ, "BIB Preformatted Color image"},
09680     {DCM_BIBREFIMAGEOVERLAYBOXSEQ, DCM_SQ, "BIB Referenced Image Overlay Box seq"},
09681     {DCM_BIBREFVOILUTSEQ, DCM_SQ, "BIB Referenced VOI LUT seq."}
09682 };
09683 
09684 /* Defines the entries in the BASICANNOTATIONBOX group (2030)
09685 */
09686 static DCMDICT BAB_dictionary[] = {
09687     {DCM_BABGROUPLENGTH, DCM_UL, "BAB Group Length"},
09688     {DCM_BABANNOTATIONPOSITION, DCM_US, "BAB posn of the annot. box in parent film box"},
09689     {DCM_BABTEXTSTRING, DCM_LO, "BAB text string"}
09690 };
09691 
09692 /* Defines entries for BASICIMAGEOVERLAYBOX group (2040)
09693 */
09694 static DCMDICT IOB_dictionary[] = {
09695     {DCM_IOBGROUPLENGTH, DCM_UL, "IOB Group Length"},
09696     {DCM_IOBREFOVERLAYPLANESEQ, DCM_SQ, "IOB Ref Overlay Plane Sequence"},
09697     {DCM_IOBREFOVERLAYPLANEGROUPS, DCM_US, "IOB Ref Overlay Plane Groups"},
09698     {DCM_IOBOVERLAYMAGNIFICATIONTYPE, DCM_CS, "IOB Overlay Magnification Type"},
09699     {DCM_IOBOVERLAYSMOOTHINGTYPE, DCM_CS, "IOB Overlay Smoothing Type"},
09700     {DCM_IOBOVERLAYFOREGROUNDDENSITY, DCM_CS, "IOB Overlay Foreground Density"},
09701     {DCM_IOBOVERLAYMODE, DCM_CS, "IOB Overlay Mode"},
09702     {DCM_IOBTHRESHOLDDENSITY, DCM_CS, "IOB Threshold Density"},
09703     {DCM_IOBREFIMAGEBOXSEQUENCE, DCM_SQ, "IOB Ref Image Box Sequence (RET)"}
09704 };
09705 
09706 /* Defines entries for Presentation LUT Group (2050)
09707 */
09708 static DCMDICT PLUT_dictionary[] = {
09709     {DCM_MAKETAG(0x2050, 0x0000), DCM_UL, "PLUT Group Length"},
09710     {DCM_MAKETAG(0x2050, 0x0010), DCM_SQ, "PLUT Presentation LUT Sequence"},
09711     {DCM_MAKETAG(0x2050, 0x0020), DCM_CS, "PLUT Presentation LUT Shape"},
09712     {DCM_MAKETAG(0x2050, 0x0500), DCM_SQ, "PLUT Referenced Presentation LUT Sequence"}
09713 };
09714 
09715 /* Defines the entries in the PRINTJOB group (2100)
09716 */
09717 static DCMDICT PJ_dictionary[] = {
09718     {DCM_PJGROUPLENGTH, DCM_UL, "PJ Group Length"},
09719     {DCM_PJEXECUTIONSTATUS, DCM_CS, "PJ execution status of print job"},
09720     {DCM_PJEXECUTIONSTATUSINFO, DCM_CS, "PJ additional information"},
09721     {DCM_PJCREATIONDATE, DCM_DA, "PJ date of print job creation"},
09722     {DCM_PJCREATIONTIME, DCM_TM, "PJ time of print job creation"},
09723     {DCM_PJORIGINATOR, DCM_AE, "PJ Appln entity title that issued the print opn"},
09724     {DCM_PJREFPRINTJOBSEQ, DCM_SQ, "PJ Referenced print job seq."}
09725 };
09726 
09727 /* Defines the entries in the PRINTER group (2110)
09728 */
09729 static DCMDICT PRN_dictionary[] = {
09730     {DCM_PRINTERGROUPLENGTH, DCM_UL, "PRINTER Group Length"},
09731     {DCM_PRINTERSTATUS, DCM_CS, "PRINTER printer device status"},
09732     {DCM_PRINTERSTATUSINFO, DCM_CS, "PRINTER additional information"},
09733     {DCM_PRINTERNAME, DCM_LO, "PRINTER printer name"},
09734     {DCM_PRINTERQUEUEID, DCM_SH, "Printer Queue ID"}
09735 };
09736 
09737 /* Define the entries in the 0x3002 group, used for RT planning
09738 */
09739 static DCMDICT G3002_dictionary[] = {
09740     {DCM_MAKETAG(0x3002, 0x0000), DCM_UL, "RT Group Length"},
09741     {DCM_MAKETAG(0x3002, 0x0002), DCM_SH, "RT Image Label"},
09742     {DCM_MAKETAG(0x3002, 0x0003), DCM_LO, "RT Image Name"},
09743     {DCM_MAKETAG(0x3002, 0x0004), DCM_ST, "RT Image Description"},
09744     {DCM_MAKETAG(0x3002, 0x000a), DCM_CS, "RT Reported Values Origin"},
09745     {DCM_MAKETAG(0x3002, 0x000c), DCM_CS, "RT Image Plane"},
09746     {DCM_MAKETAG(0x3002, 0x000e), DCM_DS, "RT X-Ray Image Receptor Angle"},
09747     {DCM_MAKETAG(0x3002, 0x0010), DCM_DS, "RT Image Orientation"},
09748     {DCM_MAKETAG(0x3002, 0x0011), DCM_DS, "RT Image Plane Pixel Spacing"},
09749     {DCM_MAKETAG(0x3002, 0x0012), DCM_DS, "RT Image Position"},
09750     {DCM_MAKETAG(0x3002, 0x0020), DCM_SH, "RT Radiation Machine Name"},
09751     {DCM_MAKETAG(0x3002, 0x0022), DCM_DS, "RT Radiation Machine SAD"},
09752     {DCM_MAKETAG(0x3002, 0x0024), DCM_DS, "RT Radiation Machine SSD"},
09753     {DCM_MAKETAG(0x3002, 0x0026), DCM_DS, "RT Image SID"},
09754     {DCM_MAKETAG(0x3002, 0x0028), DCM_DS, "RT Source to Reference Object Distance"},
09755     {DCM_MAKETAG(0x3002, 0x0029), DCM_IS, "RT Fraction Number"},
09756     {DCM_MAKETAG(0x3002, 0x0030), DCM_SQ, "RT Exposure Sequence"},
09757     {DCM_MAKETAG(0x3002, 0x0032), DCM_DS, "RT Meterset Exposure"}
09758 };
09759 
09760 /* Define the entries in the 0x3004 group, Dose Volume Histogram (DVH),
09761 ** used in RT planning.
09762 */
09763 static DCMDICT DVH_dictionary[] = {
09764     {DCM_MAKETAG(0x3004, 0x0000), DCM_UL, "DVH Group Length"},
09765     {DCM_MAKETAG(0x3004, 0x0001), DCM_CS, "DVH Type"},
09766     {DCM_MAKETAG(0x3004, 0x0002), DCM_CS, "DVH Dose Units"},
09767     {DCM_MAKETAG(0x3004, 0x0004), DCM_CS, "DVH Dose Type"},
09768     {DCM_MAKETAG(0x3004, 0x0006), DCM_LO, "DVH Dose Comment"},
09769     {DCM_MAKETAG(0x3004, 0x0008), DCM_DS, "DVH Normalization Point"},
09770     {DCM_MAKETAG(0x3004, 0x000a), DCM_CS, "DVH Dose Summation Type"},
09771     {DCM_MAKETAG(0x3004, 0x000c), DCM_DS, "DVH Grid Frame Offset Vector"},
09772     {DCM_MAKETAG(0x3004, 0x000e), DCM_DS, "DVH Dose Grid Scaling"},
09773     {DCM_MAKETAG(0x3004, 0x0010), DCM_SQ, "DVH RT Dose ROI Sequence"},
09774     {DCM_MAKETAG(0x3004, 0x0012), DCM_DS, "DVH Dose Value"},
09775     {DCM_MAKETAG(0x3004, 0x0040), DCM_DS, "DVH Normalization Point"},
09776     {DCM_MAKETAG(0x3004, 0x0042), DCM_DS, "DVH Normalization Dose Value"},
09777     {DCM_MAKETAG(0x3004, 0x0050), DCM_SQ, "DVH Sequence"},
09778     {DCM_MAKETAG(0x3004, 0x0052), DCM_DS, "DVH Dose Scaling"},
09779     {DCM_MAKETAG(0x3004, 0x0054), DCM_CS, "DVH Volume Units"},
09780     {DCM_MAKETAG(0x3004, 0x0056), DCM_IS, "DVH Number of Bins"},
09781     {DCM_MAKETAG(0x3004, 0x0058), DCM_DS, "DVH Data"},
09782     {DCM_MAKETAG(0x3004, 0x0060), DCM_SQ, "DVH Referenced ROI Sequence"},
09783     {DCM_MAKETAG(0x3004, 0x0062), DCM_CS, "DVH ROI Contribution Type"},
09784     {DCM_MAKETAG(0x3004, 0x0070), DCM_DS, "DVH Minimum Dose"},
09785     {DCM_MAKETAG(0x3004, 0x0072), DCM_DS, "DVH Maximum Dose"},
09786     {DCM_MAKETAG(0x3004, 0x0074), DCM_DS, "DVH Mean Dose"}
09787 };
09788 
09789 /* Define the entries in the 0x3006 group, Structure Set,
09790 ** used in RT planning.
09791 */
09792 static DCMDICT SSET_dictionary[] = {
09793     {DCM_MAKETAG(0x3006, 0x0000), DCM_UL, "SSET Group Length"},
09794     {DCM_MAKETAG(0x3006, 0x0002), DCM_SH, "SSET Structure Set Label"},
09795     {DCM_MAKETAG(0x3006, 0x0004), DCM_LO, "SSET Structure Set Name"},
09796     {DCM_MAKETAG(0x3006, 0x0006), DCM_ST, "SSET Structure Set Description"},
09797     {DCM_MAKETAG(0x3006, 0x0008), DCM_DA, "SSET Structure Set Date"},
09798     {DCM_MAKETAG(0x3006, 0x0009), DCM_TM, "SSET Structure Set Time"},
09799     {DCM_MAKETAG(0x3006, 0x0010), DCM_SQ, "SSET Referenced Frame of Reference Sequence"},
09800     {DCM_MAKETAG(0x3006, 0x0012), DCM_SQ, "SSET RT Referenced Study Sequence"},
09801     {DCM_MAKETAG(0x3006, 0x0014), DCM_SQ, "SSET RT Referenced Series Sequence"},
09802     {DCM_MAKETAG(0x3006, 0x0016), DCM_SQ, "SSET Contour Image Sequence"},
09803     {DCM_MAKETAG(0x3006, 0x0020), DCM_SQ, "SSET Structure Set ROI Sequence"},
09804     {DCM_MAKETAG(0x3006, 0x0022), DCM_IS, "SSET ROI Number"},
09805     {DCM_MAKETAG(0x3006, 0x0024), DCM_UI, "SSET Referenced Frame of Reference UID"},
09806     {DCM_MAKETAG(0x3006, 0x0026), DCM_LO, "SSET ROI Name"},
09807     {DCM_MAKETAG(0x3006, 0x0028), DCM_ST, "SSET ROI Description"},
09808     {DCM_MAKETAG(0x3006, 0x002a), DCM_IS, "SSET ROI Display Color"},
09809     {DCM_MAKETAG(0x3006, 0x002c), DCM_DS, "SSET ROI Volume"},
09810     {DCM_MAKETAG(0x3006, 0x0030), DCM_SQ, "SSET RT Related ROI Sequence"},
09811     {DCM_MAKETAG(0x3006, 0x0033), DCM_CS, "SSET RT ROI Relationship"},
09812     {DCM_MAKETAG(0x3006, 0x0036), DCM_CS, "SSET ROI Generation Algorithm"},
09813     {DCM_MAKETAG(0x3006, 0x0038), DCM_LO, "SSET ROI Generation Description"},
09814     {DCM_MAKETAG(0x3006, 0x0039), DCM_SQ, "SSET ROI Contour Sequence"},
09815     {DCM_MAKETAG(0x3006, 0x0040), DCM_SQ, "SSET Contour Sequence"},
09816     {DCM_MAKETAG(0x3006, 0x0042), DCM_CS, "SSET Contour Geometric Type"},
09817     {DCM_MAKETAG(0x3006, 0x0044), DCM_DS, "SSET Contour Slab Thickness"},
09818     {DCM_MAKETAG(0x3006, 0x0045), DCM_DS, "SSET Contour Offset Vector"},
09819     {DCM_MAKETAG(0x3006, 0x0046), DCM_IS, "SSET Number of Contour Points"},
09820     {DCM_MAKETAG(0x3006, 0x0050), DCM_DS, "SSET Contour Data"},
09821     {DCM_MAKETAG(0x3006, 0x0080), DCM_SQ, "SSET RT ROI Observations Sequence"},
09822     {DCM_MAKETAG(0x3006, 0x0082), DCM_IS, "SSET Observation Number"},
09823     {DCM_MAKETAG(0x3006, 0x0084), DCM_IS, "SSET Referenced ROI Number"},
09824     {DCM_MAKETAG(0x3006, 0x0085), DCM_SH, "SSET ROI Observation Label"},
09825     {DCM_MAKETAG(0x3006, 0x0086), DCM_SQ, "SSET RT ROI Identification Code Sequence"},
09826     {DCM_MAKETAG(0x3006, 0x0088), DCM_ST, "SSET ROI Observation Description"},
09827     {DCM_MAKETAG(0x3006, 0x00a0), DCM_SQ, "SSET Relation RT ROI Observations Sequence"},
09828     {DCM_MAKETAG(0x3006, 0x00a4), DCM_CS, "SSET RT ROI Interpreted Type"},
09829     {DCM_MAKETAG(0x3006, 0x00a6), DCM_PN, "SSET ROI Interpreter"},
09830     {DCM_MAKETAG(0x3006, 0x00b0), DCM_SQ, "SSET ROI Physical Properties Sequence"},
09831     {DCM_MAKETAG(0x3006, 0x00b2), DCM_CS, "SSET ROI Physical Property"},
09832     {DCM_MAKETAG(0x3006, 0x00b4), DCM_DS, "SSET ROI Physical Property Value"},
09833     {DCM_MAKETAG(0x3006, 0x00c0), DCM_SQ, "SSET Frame of Referenced Relationship Sequence"},
09834     {DCM_MAKETAG(0x3006, 0x00c2), DCM_UI, "SSET Related Frame of Reference UID"},
09835     {DCM_MAKETAG(0x3006, 0x00c4), DCM_CS, "SSET Frame of Reference Transformation Type"},
09836     {DCM_MAKETAG(0x3006, 0x00c6), DCM_DS, "SSET Frame of Reference Transformation Matrix"},
09837     {DCM_MAKETAG(0x3006, 0x00c8), DCM_LO, "SSET Frame of Reference Transformation Comment"}
09838 };
09839 
09840 /* Define the entries in the 0x300A group, used in RT planning.
09841 */
09842 static DCMDICT G300A_dictionary[] = {
09843     {DCM_MAKETAG(0x300a, 0x0000), DCM_UL, "     Group Length"},
09844     {DCM_MAKETAG(0x300a, 0x0002), DCM_SH, "     RT Plan Label"},
09845     {DCM_MAKETAG(0x300a, 0x0003), DCM_LO, "     RT Plan Name"},
09846     {DCM_MAKETAG(0x300a, 0x0004), DCM_ST, "     RT Plan Description"},
09847     {DCM_MAKETAG(0x300a, 0x0006), DCM_DA, "     RT Plan Date"},
09848     {DCM_MAKETAG(0x300a, 0x0007), DCM_TM, "     RT Plan Time"},
09849     {DCM_MAKETAG(0x300a, 0x0009), DCM_LO, "     RT Treatment Protocols"},
09850     {DCM_MAKETAG(0x300a, 0x000a), DCM_CS, "     Treatment Intent"},
09851     {DCM_MAKETAG(0x300a, 0x000b), DCM_LO, "     Treatment Sites"},
09852     {DCM_MAKETAG(0x300a, 0x000c), DCM_CS, "     RT Plan Geometry"},
09853     {DCM_MAKETAG(0x300a, 0x000e), DCM_ST, "     Prescription Description"},
09854     {DCM_MAKETAG(0x300a, 0x0010), DCM_SQ, "     Dose Reference Sequence"},
09855     {DCM_MAKETAG(0x300a, 0x0012), DCM_IS, "     Dose Reference Number"},
09856     {DCM_MAKETAG(0x300a, 0x0014), DCM_CS, "     Dose Reference Structure Type"},
09857     {DCM_MAKETAG(0x300a, 0x0016), DCM_LO, "     Dose Reference Description"},
09858     {DCM_MAKETAG(0x300a, 0x0018), DCM_DS, "     Dose Reference Point Coordinates"},
09859     {DCM_MAKETAG(0x300a, 0x001a), DCM_DS, "     Nominal Prior Dose"},
09860     {DCM_MAKETAG(0x300a, 0x0020), DCM_CS, "     Dose Reference Type"},
09861     {DCM_MAKETAG(0x300a, 0x0021), DCM_DS, "     Constraint Weight"},
09862     {DCM_MAKETAG(0x300a, 0x0022), DCM_DS, "     Delivery Warning Dose"},
09863     {DCM_MAKETAG(0x300a, 0x0023), DCM_DS, "     Delivery Maximum Dose"},
09864     {DCM_MAKETAG(0x300a, 0x0025), DCM_DS, "     Target Minimum Dose"},
09865     {DCM_MAKETAG(0x300a, 0x0026), DCM_DS, "     Target Prescription Dose"},
09866     {DCM_MAKETAG(0x300a, 0x0027), DCM_DS, "     Target Maximum Dose"},
09867     {DCM_MAKETAG(0x300a, 0x0028), DCM_DS, "     Target Underdose Volume Fraction"},
09868     {DCM_MAKETAG(0x300a, 0x002a), DCM_DS, "     Organ at Risk Full-volume Dose"},
09869     {DCM_MAKETAG(0x300a, 0x002b), DCM_DS, "     Organ at Risk Limit Dose"},
09870     {DCM_MAKETAG(0x300a, 0x002c), DCM_DS, "     Organ at Risk Maximum Dose"},
09871     {DCM_MAKETAG(0x300a, 0x002d), DCM_DS, "     Organ at Risk Overdose Volume Fraction"},
09872     {DCM_MAKETAG(0x300a, 0x0040), DCM_SQ, "     Tolerance Table Sequence"},
09873     {DCM_MAKETAG(0x300a, 0x0042), DCM_IS, "     Tolerance Table Number"},
09874     {DCM_MAKETAG(0x300a, 0x0043), DCM_SH, "     Tolerance Table Label"},
09875     {DCM_MAKETAG(0x300a, 0x0044), DCM_DS, "     Gantry Angle Tolerance"},
09876     {DCM_MAKETAG(0x300a, 0x0046), DCM_DS, "     Beam Limiting Device Angle Tolerance"},
09877     {DCM_MAKETAG(0x300a, 0x0048), DCM_SQ, "     Beam Limiting Device Tolerance Sequence"},
09878     {DCM_MAKETAG(0x300a, 0x004a), DCM_DS, "     Beam Limiting Device Position Tolerance"},
09879     {DCM_MAKETAG(0x300a, 0x004c), DCM_DS, "     Patient Support Angle Tolerance"},
09880     {DCM_MAKETAG(0x300a, 0x004e), DCM_DS, "     Table Top Eccentric Angle Tolerance"},
09881     {DCM_MAKETAG(0x300a, 0x0051), DCM_DS, "     Table Top Vertical Position Tolerance"},
09882     {DCM_MAKETAG(0x300a, 0x0052), DCM_DS, "     Table Top Longitudinal Position Tolerance"},
09883     {DCM_MAKETAG(0x300a, 0x0053), DCM_DS, "     Table Top Lateral Position Tolerance"},
09884     {DCM_MAKETAG(0x300a, 0x0055), DCM_CS, "     RT Plan Relationship"},
09885     {DCM_MAKETAG(0x300a, 0x0070), DCM_SQ, "     Fraction Group Sequence"},
09886     {DCM_MAKETAG(0x300a, 0x0071), DCM_IS, "     Fraction Group Number"},
09887     {DCM_MAKETAG(0x300a, 0x0078), DCM_IS, "     Number of Fractions Planned"},
09888     {DCM_MAKETAG(0x300a, 0x0079), DCM_IS, "     Number of Fractions Per Day"},
09889     {DCM_MAKETAG(0x300a, 0x007a), DCM_IS, "     Repeat Fraction Cycle Length"},
09890     {DCM_MAKETAG(0x300a, 0x007b), DCM_LT, "     Fraction Pattern"},
09891     {DCM_MAKETAG(0x300a, 0x0080), DCM_IS, "     Number of Beams"},
09892     {DCM_MAKETAG(0x300a, 0x0082), DCM_DS, "     Beam Dose Specification Point"},
09893     {DCM_MAKETAG(0x300a, 0x0084), DCM_DS, "     Beam Dose"},
09894     {DCM_MAKETAG(0x300a, 0x0086), DCM_DS, "     Beam Meterset"},
09895     {DCM_MAKETAG(0x300a, 0x00a0), DCM_IS, "     Number of Brachy Application Setups"},
09896     {DCM_MAKETAG(0x300a, 0x00a2), DCM_DS, "     Brachy App Setup Dose Specification Point"},
09897     {DCM_MAKETAG(0x300a, 0x00a4), DCM_DS, "     Brachy Application Setup Dose"},
09898     {DCM_MAKETAG(0x300a, 0x00b0), DCM_SQ, "     Beam Sequence"},
09899     {DCM_MAKETAG(0x300a, 0x00b2), DCM_SH, "     Treatment Machine Name"},
09900     {DCM_MAKETAG(0x300a, 0x00b3), DCM_CS, "     Primary Dosimeter Unit"},
09901     {DCM_MAKETAG(0x300a, 0x00b4), DCM_DS, "     Source-Axis Distance"},
09902     {DCM_MAKETAG(0x300a, 0x00b6), DCM_SQ, "     Beam Limiting Device Sequence"},
09903     {DCM_MAKETAG(0x300a, 0x00b8), DCM_CS, "     RT Beam Limiting Device Type"},
09904     {DCM_MAKETAG(0x300a, 0x00ba), DCM_DS, "     Source to Beam Limiting Device Distance"},
09905     {DCM_MAKETAG(0x300a, 0x00bc), DCM_IS, "     Number of Leaf/Jaw Pairs"},
09906     {DCM_MAKETAG(0x300a, 0x00be), DCM_DS, "     Leaf Position Boundaries"},
09907     {DCM_MAKETAG(0x300a, 0x00c0), DCM_IS, "     Beam Number"},
09908     {DCM_MAKETAG(0x300a, 0x00c2), DCM_LO, "     Beam Name"},
09909     {DCM_MAKETAG(0x300a, 0x00c3), DCM_ST, "     Beam Description"},
09910     {DCM_MAKETAG(0x300a, 0x00c4), DCM_CS, "     Beam Type"},
09911     {DCM_MAKETAG(0x300a, 0x00c6), DCM_CS, "     Radiation Type"},
09912     {DCM_MAKETAG(0x300a, 0x00c8), DCM_IS, "     Reference Image Number"},
09913     {DCM_MAKETAG(0x300a, 0x00ca), DCM_SQ, "     Planned Verification Image Sequence"},
09914     {DCM_MAKETAG(0x300a, 0x00cc), DCM_LO, "     Imaging Device-Specific Acq Parameters"},
09915     {DCM_MAKETAG(0x300a, 0x00ce), DCM_CS, "     Treatment Delivery Type"},
09916     {DCM_MAKETAG(0x300a, 0x00d0), DCM_IS, "     Number of Wedges"},
09917     {DCM_MAKETAG(0x300a, 0x00d1), DCM_SQ, "     Wedge Sequence"},
09918     {DCM_MAKETAG(0x300a, 0x00d2), DCM_IS, "     Wedge Number"},
09919     {DCM_MAKETAG(0x300a, 0x00d3), DCM_CS, "     Wedge Type"},
09920     {DCM_MAKETAG(0x300a, 0x00d4), DCM_SH, "     Wedge ID"},
09921     {DCM_MAKETAG(0x300a, 0x00d5), DCM_IS, "     Wedge Angle"},
09922     {DCM_MAKETAG(0x300a, 0x00d6), DCM_DS, "     Wedge Factor"},
09923     {DCM_MAKETAG(0x300a, 0x00d8), DCM_DS, "     Wedge Orientation"},
09924     {DCM_MAKETAG(0x300a, 0x00da), DCM_DS, "     Source to Wedge Tray Distance"},
09925     {DCM_MAKETAG(0x300a, 0x00e0), DCM_IS, "     Number of Compensators"},
09926     {DCM_MAKETAG(0x300a, 0x00e1), DCM_SH, "     Material ID"},
09927     {DCM_MAKETAG(0x300a, 0x00e2), DCM_DS, "     Total Compensator Tray Factor"},
09928     {DCM_MAKETAG(0x300a, 0x00e3), DCM_SQ, "     Compensator Sequence"},
09929     {DCM_MAKETAG(0x300a, 0x00e4), DCM_IS, "     Compensator Number"},
09930     {DCM_MAKETAG(0x300a, 0x00e5), DCM_SH, "     Compensator ID"},
09931     {DCM_MAKETAG(0x300a, 0x00e6), DCM_DS, "     Source to Compensator Tray Distance"},
09932     {DCM_MAKETAG(0x300a, 0x00e7), DCM_IS, "     Compensator Rows"},
09933     {DCM_MAKETAG(0x300a, 0x00e8), DCM_IS, "     Compensator Columns"},
09934     {DCM_MAKETAG(0x300a, 0x00e9), DCM_DS, "     Compensator Pixel Spacing"},
09935     {DCM_MAKETAG(0x300a, 0x00ea), DCM_DS, "     Compensator Position"},
09936     {DCM_MAKETAG(0x300a, 0x00eb), DCM_DS, "     Compensator Transmission Data"},
09937     {DCM_MAKETAG(0x300a, 0x00ec), DCM_DS, "     Compensator Thickness Data"},
09938     {DCM_MAKETAG(0x300a, 0x00ed), DCM_IS, "     Number of Boli"},
09939     {DCM_MAKETAG(0x300a, 0x00f0), DCM_IS, "     Number of Blocks"},
09940     {DCM_MAKETAG(0x300a, 0x00f2), DCM_DS, "     Total Block Tray Factor"},
09941     {DCM_MAKETAG(0x300a, 0x00f4), DCM_SQ, "     Block Sequence"},
09942     {DCM_MAKETAG(0x300a, 0x00f5), DCM_SH, "     Block Tray ID"},
09943     {DCM_MAKETAG(0x300a, 0x00f6), DCM_DS, "     Source to Block Tray Distance"},
09944     {DCM_MAKETAG(0x300a, 0x00f8), DCM_CS, "     Block Type"},
09945     {DCM_MAKETAG(0x300a, 0x00fa), DCM_CS, "     Block Divergence"},
09946     {DCM_MAKETAG(0x300a, 0x00fc), DCM_IS, "     Block Number"},
09947     {DCM_MAKETAG(0x300a, 0x00fe), DCM_LO, "     Block Name"},
09948     {DCM_MAKETAG(0x300a, 0x0100), DCM_DS, "     Block Thickness"},
09949     {DCM_MAKETAG(0x300a, 0x0102), DCM_DS, "     Block Transmission"},
09950     {DCM_MAKETAG(0x300a, 0x0104), DCM_IS, "     Block Number of Points"},
09951     {DCM_MAKETAG(0x300a, 0x0106), DCM_DS, "     Block Data"},
09952     {DCM_MAKETAG(0x300a, 0x0107), DCM_SQ, "     Applicator Sequence"},
09953     {DCM_MAKETAG(0x300a, 0x0108), DCM_SH, "     Applicator ID"},
09954     {DCM_MAKETAG(0x300a, 0x0109), DCM_CS, "     Applicator Type"},
09955     {DCM_MAKETAG(0x300a, 0x010a), DCM_LO, "     Applicator Description"},
09956     {DCM_MAKETAG(0x300a, 0x010c), DCM_DS, "     Cumulative Dose Reference COefficient"},
09957     {DCM_MAKETAG(0x300a, 0x010e), DCM_DS, "     Final Cumulative Meterset Weight"},
09958     {DCM_MAKETAG(0x300a, 0x0110), DCM_IS, "     Number of Control Points"},
09959     {DCM_MAKETAG(0x300a, 0x0111), DCM_SQ, "     Control Point Sequence"},
09960     {DCM_MAKETAG(0x300a, 0x0112), DCM_IS, "     Control Point Index"},
09961     {DCM_MAKETAG(0x300a, 0x0114), DCM_DS, "     Nominal Beam Energy"},
09962     {DCM_MAKETAG(0x300a, 0x0115), DCM_DS, "     Dose Rate Set"},
09963     {DCM_MAKETAG(0x300a, 0x0116), DCM_SQ, "     Wedge Position Sequence"},
09964     {DCM_MAKETAG(0x300a, 0x0118), DCM_CS, "     Wedge Position"},
09965     {DCM_MAKETAG(0x300a, 0x011a), DCM_SQ, "     Beam Limiting Device Position Sequence"},
09966     {DCM_MAKETAG(0x300a, 0x011c), DCM_DS, "     Leaf/Jaw Positions"},
09967     {DCM_MAKETAG(0x300a, 0x011e), DCM_DS, "     Gantry Angle"},
09968     {DCM_MAKETAG(0x300a, 0x011f), DCM_CS, "     Gantry Rotation Direction"},
09969     {DCM_MAKETAG(0x300a, 0x0120), DCM_DS, "     Beam Limiting Device Angle"},
09970     {DCM_MAKETAG(0x300a, 0x0121), DCM_CS, "     Beam Limiting Device Rotation Direction"},
09971     {DCM_MAKETAG(0x300a, 0x0122), DCM_DS, "     Patient Support Angle"},
09972     {DCM_MAKETAG(0x300a, 0x0123), DCM_CS, "     Patient Support Rotation Direction"},
09973     {DCM_MAKETAG(0x300a, 0x0124), DCM_DS, "     Table Top Eccentric Axis Distance"},
09974     {DCM_MAKETAG(0x300a, 0x0125), DCM_DS, "     Table Top Eccentric Angle"},
09975     {DCM_MAKETAG(0x300a, 0x0126), DCM_CS, "     Table Top Eccentric Rotation Direction"},
09976     {DCM_MAKETAG(0x300a, 0x0128), DCM_DS, "     Table Top Vertical Position"},
09977     {DCM_MAKETAG(0x300a, 0x0129), DCM_DS, "     Table Top Longitudinal Position"},
09978     {DCM_MAKETAG(0x300a, 0x012a), DCM_DS, "     Table Top Lateral Position"},
09979     {DCM_MAKETAG(0x300a, 0x012c), DCM_DS, "     Isocenter Position"},
09980     {DCM_MAKETAG(0x300a, 0x012e), DCM_DS, "     Surface Entry Point"},
09981     {DCM_MAKETAG(0x300a, 0x0130), DCM_DS, "     Source to Surface Distance"},
09982     {DCM_MAKETAG(0x300a, 0x0134), DCM_DS, "     Cumulative Meterset Weight"},
09983     {DCM_MAKETAG(0x300a, 0x0180), DCM_SQ, "     Patient Setup Sequence"},
09984     {DCM_MAKETAG(0x300a, 0x0182), DCM_IS, "     Patient Setup Number"},
09985     {DCM_MAKETAG(0x300a, 0x0184), DCM_LO, "     Patient Additional Position"},
09986     {DCM_MAKETAG(0x300a, 0x0190), DCM_SQ, "     Fixation Device Sequence"},
09987     {DCM_MAKETAG(0x300a, 0x0192), DCM_CS, "     Fixation Device Type"},
09988     {DCM_MAKETAG(0x300a, 0x0194), DCM_SH, "     Fixation Device Label"},
09989     {DCM_MAKETAG(0x300a, 0x0196), DCM_ST, "     Fixation Device Description"},
09990     {DCM_MAKETAG(0x300a, 0x0198), DCM_SH, "     Fixation Device Position"},
09991     {DCM_MAKETAG(0x300a, 0x01a0), DCM_SQ, "     Shielding Device Sequence"},
09992     {DCM_MAKETAG(0x300a, 0x01a2), DCM_CS, "     Shielding Device Type"},
09993     {DCM_MAKETAG(0x300a, 0x01a4), DCM_SH, "     Shielding Device Label"},
09994     {DCM_MAKETAG(0x300a, 0x01a6), DCM_ST, "     Shielding Device Description"},
09995     {DCM_MAKETAG(0x300a, 0x01a8), DCM_SH, "     Shielding Device Position"},
09996     {DCM_MAKETAG(0x300a, 0x01b0), DCM_CS, "     Setup Technique"},
09997     {DCM_MAKETAG(0x300a, 0x01b2), DCM_ST, "     Setup Technique Description"},
09998     {DCM_MAKETAG(0x300a, 0x01b4), DCM_SQ, "     Setup Device Sequence"},
09999     {DCM_MAKETAG(0x300a, 0x01b6), DCM_CS, "     Setup Device Type"},
10000     {DCM_MAKETAG(0x300a, 0x01b8), DCM_SH, "     Setup Device Label"},
10001     {DCM_MAKETAG(0x300a, 0x01ba), DCM_ST, "     Setup Device Description"},
10002     {DCM_MAKETAG(0x300a, 0x01bc), DCM_DS, "     Setup Device Parameter"},
10003     {DCM_MAKETAG(0x300a, 0x01d0), DCM_ST, "     Setup Reference Description"},
10004     {DCM_MAKETAG(0x300a, 0x01d2), DCM_DS, "     Table Top Vertical Setup Displacement"},
10005     {DCM_MAKETAG(0x300a, 0x01d4), DCM_DS, "     Table Top Longitudinal Setup Displacement"},
10006     {DCM_MAKETAG(0x300a, 0x01d6), DCM_DS, "     Table Top Lateral Setup Displacement"},
10007     {DCM_MAKETAG(0x300a, 0x0200), DCM_CS, "     Brachy Treatment Technique"},
10008     {DCM_MAKETAG(0x300a, 0x0202), DCM_CS, "     Brachy Treatment Type"},
10009     {DCM_MAKETAG(0x300a, 0x0206), DCM_SQ, "     Treatment Machine Sequence"},
10010     {DCM_MAKETAG(0x300a, 0x0210), DCM_SQ, "     Source Sequence"},
10011     {DCM_MAKETAG(0x300a, 0x0212), DCM_IS, "     Source Number"},
10012     {DCM_MAKETAG(0x300a, 0x0214), DCM_CS, "     Source Type"},
10013     {DCM_MAKETAG(0x300a, 0x0216), DCM_LO, "     Source Manufacturer"},
10014     {DCM_MAKETAG(0x300a, 0x0218), DCM_DS, "     Active Source Diameter"},
10015     {DCM_MAKETAG(0x300a, 0x021a), DCM_DS, "     Active Source Length"},
10016     {DCM_MAKETAG(0x300a, 0x0222), DCM_DS, "     Source Encapsulation Nominal Thickness"},
10017     {DCM_MAKETAG(0x300a, 0x0224), DCM_DS, "     Source Encapsulation Nominal Transmission"},
10018     {DCM_MAKETAG(0x300a, 0x0226), DCM_LO, "     Source Isotope Name"},
10019     {DCM_MAKETAG(0x300a, 0x0228), DCM_DS, "     Source Isotope Half Life"},
10020     {DCM_MAKETAG(0x300a, 0x022a), DCM_DS, "     Reference Air Kerma Rate"},
10021     {DCM_MAKETAG(0x300a, 0x022c), DCM_DA, "     Air Kerma Rate Reference Date"},
10022     {DCM_MAKETAG(0x300a, 0x022e), DCM_TM, "     Air Kerma Rate Reference Time"},
10023     {DCM_MAKETAG(0x300a, 0x0230), DCM_SQ, "     Application Setup Sequence"},
10024     {DCM_MAKETAG(0x300a, 0x0232), DCM_CS, "     Application Setup Type"},
10025     {DCM_MAKETAG(0x300a, 0x0234), DCM_IS, "     Application Setup Number"},
10026     {DCM_MAKETAG(0x300a, 0x0236), DCM_LO, "     Application Setup Name"},
10027     {DCM_MAKETAG(0x300a, 0x0238), DCM_LO, "     Application Setup Manufacturer"},
10028     {DCM_MAKETAG(0x300a, 0x0240), DCM_IS, "     Template Number"},
10029     {DCM_MAKETAG(0x300a, 0x0242), DCM_SH, "     Template Type"},
10030     {DCM_MAKETAG(0x300a, 0x0244), DCM_LO, "     Template Name"},
10031     {DCM_MAKETAG(0x300a, 0x0250), DCM_DS, "     Total Reference Air Kerma"},
10032     {DCM_MAKETAG(0x300a, 0x0260), DCM_SQ, "     Brachy Acessory Device Sequence"},
10033     {DCM_MAKETAG(0x300a, 0x0262), DCM_IS, "     Brachy Accessory Device Number"},
10034     {DCM_MAKETAG(0x300a, 0x0263), DCM_SH, "     Brachy Accessory Device ID"},
10035     {DCM_MAKETAG(0x300a, 0x0264), DCM_CS, "     Brachy Accessory Device Type"},
10036     {DCM_MAKETAG(0x300a, 0x0266), DCM_LO, "     Brachy Accessory Device Name"},
10037     {DCM_MAKETAG(0x300a, 0x026a), DCM_DS, "     Brachy Accessory Device Nominal Thickness"},
10038     {DCM_MAKETAG(0x300a, 0x026c), DCM_DS, "     Brachy Acc'ry Device Nominal Transmission"},
10039     {DCM_MAKETAG(0x300a, 0x0280), DCM_SQ, "     Channel Sequence"},
10040     {DCM_MAKETAG(0x300a, 0x0282), DCM_IS, "     Channel Number"},
10041     {DCM_MAKETAG(0x300a, 0x0284), DCM_DS, "     Channel Length"},
10042     {DCM_MAKETAG(0x300a, 0x0286), DCM_DS, "     Channel Total Time"},
10043     {DCM_MAKETAG(0x300a, 0x0288), DCM_CS, "     Source Movement Type"},
10044     {DCM_MAKETAG(0x300a, 0x028a), DCM_IS, "     Number of Pulses"},
10045     {DCM_MAKETAG(0x300a, 0x028c), DCM_DS, "     Pulse Repetition Interval"},
10046     {DCM_MAKETAG(0x300a, 0x0290), DCM_IS, "     Source Applicator Number"},
10047     {DCM_MAKETAG(0x300a, 0x0291), DCM_SH, "     Source Applicator ID"},
10048     {DCM_MAKETAG(0x300a, 0x0292), DCM_CS, "     Source Applicator Type"},
10049     {DCM_MAKETAG(0x300a, 0x0294), DCM_LO, "     Source Applicator Name"},
10050     {DCM_MAKETAG(0x300a, 0x0296), DCM_DS, "     Source Applicator Length"},
10051     {DCM_MAKETAG(0x300a, 0x0298), DCM_LO, "     Source Applicator Manufacturer"},
10052     {DCM_MAKETAG(0x300a, 0x029c), DCM_DS, "     Source Applicator Wall Nominal Thickness"},
10053     {DCM_MAKETAG(0x300a, 0x029e), DCM_DS, "     Src Applicator Wall Nominal Transmission"},
10054     {DCM_MAKETAG(0x300a, 0x02a0), DCM_DS, "     Source Applicator Step Size"},
10055     {DCM_MAKETAG(0x300a, 0x02a2), DCM_IS, "     Transfer Tube Number"},
10056     {DCM_MAKETAG(0x300a, 0x02a4), DCM_DS, "     Transfer Tube Length"},
10057     {DCM_MAKETAG(0x300a, 0x02b0), DCM_SQ, "     Channel Shield Sequence"},
10058     {DCM_MAKETAG(0x300a, 0x02b2), DCM_IS, "     Channel Shield Number"},
10059     {DCM_MAKETAG(0x300a, 0x02b3), DCM_SH, "     Channel Shield ID"},
10060     {DCM_MAKETAG(0x300a, 0x02b4), DCM_LO, "     Channel Shield Name"},
10061     {DCM_MAKETAG(0x300a, 0x02b8), DCM_DS, "     Channel Shield Nominal Thickness"},
10062     {DCM_MAKETAG(0x300a, 0x02ba), DCM_DS, "     Channel Shield Nominal Transmission"},
10063     {DCM_MAKETAG(0x300a, 0x02c8), DCM_DS, "     Final Cumulative Time Weight"},
10064     {DCM_MAKETAG(0x300a, 0x02d0), DCM_SQ, "     Brachy Control Point Sequence"},
10065     {DCM_MAKETAG(0x300a, 0x02d2), DCM_DS, "   Control Point Relative Position"},
10066     {DCM_MAKETAG(0x300a, 0x02d4), DCM_DS, "     Control Point 3D Position"},
10067     {DCM_MAKETAG(0x300a, 0x02d6), DCM_DS, "     Cumulative Time Weight"}
10068 };
10069 
10070 /* Define the entries in the 0x300C group, used in RT planning.
10071 */
10072 static DCMDICT G300C_dictionary[] = {
10073     {DCM_MAKETAG(0x300c, 0x0000), DCM_UL, "     Group Length"},
10074     {DCM_MAKETAG(0x300c, 0x0002), DCM_SQ, "     Referenced RT Plan Sequence"},
10075     {DCM_MAKETAG(0x300c, 0x0004), DCM_SQ, "     Referenced Beam Sequence"},
10076     {DCM_MAKETAG(0x300c, 0x0006), DCM_IS, "     Referenced Beam Number"},
10077     {DCM_MAKETAG(0x300c, 0x0007), DCM_IS, "     Referenced Reference Image Number"},
10078     {DCM_MAKETAG(0x300c, 0x0008), DCM_DS, "     Start Cumulative Meterset Weight"},
10079     {DCM_MAKETAG(0x300c, 0x0009), DCM_DS, "     End Cumulative Meterset Weight"},
10080     {DCM_MAKETAG(0x300c, 0x000a), DCM_SQ, "     Referenced Brachy Application Setup Seq"},
10081     {DCM_MAKETAG(0x300c, 0x000c), DCM_IS, "     Referenced Brachy Application Setup Number"},
10082     {DCM_MAKETAG(0x300c, 0x000e), DCM_IS, "     Referenced Source Number"},
10083     {DCM_MAKETAG(0x300c, 0x0020), DCM_SQ, "     Referenced Fraction Group Sequence"},
10084     {DCM_MAKETAG(0x300c, 0x0022), DCM_IS, "     Referenced Fraction Group Number"},
10085     {DCM_MAKETAG(0x300c, 0x0040), DCM_SQ, "     Referenced Verification Image Sequence"},
10086     {DCM_MAKETAG(0x300c, 0x0042), DCM_SQ, "     Referenced Reference Image Sequence"},
10087     {DCM_MAKETAG(0x300c, 0x0050), DCM_SQ, "     Referenced Dose Reference Sequence"},
10088     {DCM_MAKETAG(0x300c, 0x0051), DCM_IS, "     Referenced Dose Reference Numer"},
10089     {DCM_MAKETAG(0x300c, 0x0055), DCM_SQ, "     Brachy Referenced Dose Reference Sequence"},
10090     {DCM_MAKETAG(0x300c, 0x0060), DCM_SQ, "     Referenced Structure Set Sequence"},
10091     {DCM_MAKETAG(0x300c, 0x006a), DCM_IS, "     Referenced Patient Setup Number"},
10092     {DCM_MAKETAG(0x300c, 0x0080), DCM_SQ, "     Referenced Dose Sequence"},
10093     {DCM_MAKETAG(0x300c, 0x00a0), DCM_IS, "     Referenced Tolerance Table Number"},
10094     {DCM_MAKETAG(0x300c, 0x00b0), DCM_SQ, "     Referenced Bolus Sequence"},
10095     {DCM_MAKETAG(0x300c, 0x00c0), DCM_IS, "     Referenced Wedge Number"},
10096     {DCM_MAKETAG(0x300c, 0x00d0), DCM_IS, "     Referenced Compensator Number"},
10097     {DCM_MAKETAG(0x300c, 0x00e0), DCM_IS, "     Referenced Block Number"},
10098     {DCM_MAKETAG(0x300c, 0x00f0), DCM_IS, "     Referenced Control Point Index"}
10099 };
10100 
10101 
10102 /* Define the entries in the 0x300E group, used in RT planning.
10103 */
10104 static DCMDICT G300E_dictionary[] = {
10105     {DCM_MAKETAG(0x300e, 0x0000), DCM_UL, "     Group Length"},
10106     {DCM_MAKETAG(0x300e, 0x0002), DCM_CS, "     Approval Status"},
10107     {DCM_MAKETAG(0x300e, 0x0004), DCM_DA, "     Review Date"},
10108     {DCM_MAKETAG(0x300e, 0x0005), DCM_TM, "     Review Time"},
10109     {DCM_MAKETAG(0x300e, 0x0008), DCM_PN, "     Reviewer Name"}
10110 };
10111 
10112 /* Defines the entries in the Text group (4000)
10113 */
10114 #if 0
10115 static DCMDICT TXT_dictionary[] = {
10116 };
10117 #endif
10118 
10119 /* Define the entries in the PAD group, 0xfffc
10120 */
10121 
10122 static DCMDICT PAD_dictionary[] = {
10123     {DCM_PADITEM, DCM_OB, "Pad item"}
10124 };
10125 
10126 /* Define the entries in the DELIMITER group, 0xfffe
10127 */
10128 
10129 static DCMDICT DLM_dictionary[] = {
10130     {DCM_DLMITEM, DCM_DLM, "DELIMITER Item"},
10131     {DCM_DLMITEMDELIMITATIONITEM, DCM_DLM, "DELIMITER Item Delimitation Item"},
10132     {DCM_DLMSEQUENCEDELIMITATIONITEM, DCM_DLM, "DELIMITER Sequence Delimitation Item"}
10133 };
10134 
10135 /* Define the outer layer dictionary which contains group numbers and
10136 ** pointers to each of the individual group lists.
10137 */
10138 
10139 static GROUPPTR group_dictionary[] = {
10140     {DCM_GROUPCOMMAND, sizeof(CMD_dictionary) / sizeof(DCMDICT), CMD_dictionary},
10141     {DCM_GROUPFILEMETA, sizeof(META_dictionary) / sizeof(DCMDICT), META_dictionary},
10142     {DCM_GROUPBASICDIRINFO, sizeof(BASICDIR_dictionary) / sizeof(DCMDICT), BASICDIR_dictionary},
10143     {DCM_GROUPIDENTIFYING,
10144     sizeof(ID_dictionary) / sizeof(DCMDICT), ID_dictionary},
10145     {DCM_GROUPPATIENTINFO,
10146     sizeof(PAT_dictionary) / sizeof(DCMDICT), PAT_dictionary},
10147     {DCM_GROUPACQUISITION,
10148     sizeof(ACQ_dictionary) / sizeof(DCMDICT), ACQ_dictionary},
10149     {DCM_GROUPRELATIONSHIP,
10150     sizeof(REL_dictionary) / sizeof(DCMDICT), REL_dictionary},
10151     {DCM_GROUPIMAGE,
10152     sizeof(IMG_dictionary) / sizeof(DCMDICT), IMG_dictionary},
10153     {DCM_GROUPSTUDY,
10154     sizeof(SDY_dictionary) / sizeof(DCMDICT), SDY_dictionary},
10155     {DCM_GROUPVISIT,
10156     sizeof(VIS_dictionary) / sizeof(DCMDICT), VIS_dictionary},
10157     {DCM_GROUPWAVEFORM,
10158     sizeof(WAV_dictionary) / sizeof(DCMDICT), WAV_dictionary},
10159     {DCM_GRPPROCEDURE,
10160     sizeof(PRC_dictionary) / sizeof(DCMDICT), PRC_dictionary},
10161     {DCM_GROUPDEVICE,
10162     sizeof(DEV_dictionary) / sizeof(DCMDICT), DEV_dictionary},
10163     {DCM_GROUPNMIMAGE,
10164     sizeof(NMI_dictionary) / sizeof(DCMDICT), NMI_dictionary},
10165     {DCM_GROUPGRAPHICS,
10166     sizeof(GRP_dictionary) / sizeof(DCMDICT), GRP_dictionary},
10167     {DCM_GROUPMEDIA,
10168     sizeof(MED_dictionary) / sizeof(DCMDICT), MED_dictionary},
10169     {DCM_GROUPBASICFILMSESSION,
10170     sizeof(BFS_dictionary) / sizeof(DCMDICT), BFS_dictionary},
10171     {DCM_GROUPBASICFILMBOX,
10172     sizeof(BFB_dictionary) / sizeof(DCMDICT), BFB_dictionary},
10173     {DCM_GROUPBASICIMAGEBOX,
10174     sizeof(BIB_dictionary) / sizeof(DCMDICT), BIB_dictionary},
10175     {DCM_GROUPBASICANNOTATIONBOX,
10176     sizeof(BAB_dictionary) / sizeof(DCMDICT), BAB_dictionary},
10177 
10178     {DCM_GROUPBASICIMAGEOVERLAYBOX,
10179     sizeof(IOB_dictionary) / sizeof(DCMDICT), IOB_dictionary},
10180 
10181     {0x2050,
10182     sizeof(PLUT_dictionary) / sizeof(DCMDICT), PLUT_dictionary},
10183 
10184     {DCM_GROUPPRINTJOB,
10185     sizeof(PJ_dictionary) / sizeof(DCMDICT), PJ_dictionary},
10186 
10187     {DCM_GROUPPRINTER,
10188     sizeof(PRN_dictionary) / sizeof(DCMDICT), PRN_dictionary},
10189     {0x3002,
10190     sizeof(G3002_dictionary) / sizeof(DCMDICT), G3002_dictionary},
10191     {0x3004,
10192     sizeof(DVH_dictionary) / sizeof(DCMDICT), DVH_dictionary},
10193     {0x3006,
10194     sizeof(SSET_dictionary) / sizeof(DCMDICT), SSET_dictionary},
10195     {0x300a,
10196     sizeof(G300A_dictionary) / sizeof(DCMDICT), G300A_dictionary},
10197     {0x300c,
10198     sizeof(G300C_dictionary) / sizeof(DCMDICT), G300C_dictionary},
10199     {0x300e,
10200     sizeof(G300E_dictionary) / sizeof(DCMDICT), G300E_dictionary},
10201 
10202 /*  Add this entry in when we define retired attributes
10203 **  in text group.
10204 */
10205 #if 0
10206     {DCM_GROUPTEXT,
10207     sizeof(TXT_dictionary) / sizeof(DCMDICT), TXT_dictionary},
10208 #endif
10209     {DCM_GROUPRESULTS,
10210     sizeof(RES_dictionary) / sizeof(DCMDICT), RES_dictionary},
10211     {DCM_GROUPCURVE,
10212     sizeof(CRV_dictionary) / sizeof(DCMDICT), CRV_dictionary},
10213     {DCM_GROUPOVERLAY,
10214     sizeof(OLY_dictionary) / sizeof(DCMDICT), OLY_dictionary},
10215     {DCM_GROUPPIXEL,
10216     sizeof(PXL_dictionary) / sizeof(DCMDICT), PXL_dictionary},
10217     {DCM_GROUPPAD,
10218     sizeof(PAD_dictionary) / sizeof(DCMDICT), PAD_dictionary},
10219     {DCM_GROUPDELIMITER,
10220     sizeof(DLM_dictionary) / sizeof(DCMDICT), DLM_dictionary}
10221 };
10222 
10223 
10224 /* DCM_LookupElement
10225 **
10226 ** Purpose:
10227 **      Lookup an element in the DICOM dictionary and return information
10228 **      about the element, including representation, type and english
10229 **      description.
10230 **
10231 ** Parameter Dictionary:
10232 **      element         Pointer to an DCM element (group, element) to
10233 **                      be found in the dictionary.
10234 **
10235 ** Return Values:
10236 **      DCM_NORMAL
10237 **      DCM_UNRECOGNIZEDGROUP
10238 **      DCM_UNRECOGNIZEDELEMENT
10239 **
10240 ** Algorithm:
10241 **      Set representation, type, englishDescription fields of caller's
10242 **      element to NULL values
10243 **      Search group_dictionary to find caller's group.
10244 **      If group not found,
10245 **          return DCM_UNRECOGNIZEDGROUP
10246 **      Search particular group list to find caller's element.
10247 **      If element not found,
10248 **          return DCM_UNRECOGNIZEDELEMENT
10249 **      Else
10250 **          Copy representation, type, englishDescription from dictionary
10251 **          to caller's element
10252 **          return DCM_NORMAL
10253 **      EndIf
10254 */
10255 
10256 CONDITION
10257 DCM_LookupElement(DCM_ELEMENT * element)
10258 {
10259     int
10260         found;
10261     unsigned long
10262         index,
10263         entries;
10264     GROUPPTR
10265         * p;
10266     DCMDICT
10267         * dictionaryPtr;
10268 
10269     element->representation = DCM_UN;
10270     (void) strcpy(element->description, "");
10271 
10272     for (index = 0, p = NULL;
10273          index < sizeof(group_dictionary) / sizeof(group_dictionary[0]) && p == NULL;
10274          index++)
10275         if (DCM_TAG_GROUP(element->tag) == group_dictionary[index].group)
10276             p = &group_dictionary[index];
10277 
10278     if (p == NULL) {
10279         if (DCM_TAG_ELEMENT(element->tag) == 0x0000) {
10280             element->representation = DCM_UL;
10281             (void) strcpy(element->description, "Unknown group length");
10282             return DCM_NORMAL;
10283         }
10284         return COND_PushCondition(DCM_UNRECOGNIZEDGROUP,
10285                                   DCM_Message(DCM_UNRECOGNIZEDGROUP),
10286                                   DCM_TAG_GROUP(element->tag),
10287                                   "DCM_LookupElement");
10288     }
10289     entries = p->entries;
10290     dictionaryPtr = p->dict;
10291 
10292     for (found = 0; !found && entries > 0; entries--)
10293         if (element->tag == dictionaryPtr->tag)
10294             found++;
10295         else
10296             dictionaryPtr++;
10297 
10298     if (!found)
10299         return COND_PushCondition(DCM_UNRECOGNIZEDELEMENT,
10300                                   DCM_Message(DCM_UNRECOGNIZEDELEMENT),
10301                                   DCM_TAG_GROUP(element->tag),
10302                                   DCM_TAG_ELEMENT(element->tag),
10303                                   "DCM_LookupElement");
10304 
10305 
10306     element->representation = dictionaryPtr->representation;
10307     (void) strcpy(element->description, dictionaryPtr->englishDescription);
10308     return DCM_NORMAL;
10309 }
10310 
10311 typedef struct {
10312     unsigned short group;
10313     char *description;
10314 }   GROUP_DESCRIPTION;
10315 
10316 static GROUP_DESCRIPTION groupTable[] = {
10317     {0x0000, "Command"},
10318     {0x0002, "File Meta"},
10319     {0x0004, "Basic Directory Information"},
10320     {0x0008, "Identifying"},
10321     {0x0010, "Patient Information"},
10322     {0x0018, "Acquisition"},
10323     {0x0020, "Relationship"},
10324     {0x0028, "Image"},
10325     {0x0032, "Study"},
10326     {0x0038, "Visit"},
10327     {0x003a, "Waveform"},
10328     {0x0040, "Procedure Step"},
10329     {0x0050, "Device"},
10330     {0x0054, "NM Image"},
10331     {0x0070, "Graphics"},
10332     {0x0088, "Media"},
10333     {0x2000, "Basic Film Session"},
10334     {0x2010, "Basic Film Box"},
10335     {0x2020, "Basic Image Box"},
10336     {0x2030, "Basic Annotation Box"},
10337     {0x2040, "Basic Image Overlay Box"},
10338     {0x2050, "Presentation LUT"},
10339     {0x2100, "Print Job"},
10340     {0x2110, "Printer"},
10341     {0x3002, "RT"},
10342     {0x3004, "Dose Volume Histogram"},
10343     {0x3006, "Structure Set"},
10344     {0x300a, "300a"},
10345     {0x300c, "300c"},
10346     {0x300e, "300e"},
10347 #if 0
10348     {0x4000, "Text"},
10349 #endif
10350     {0x4008, "Results"},
10351     {0x5000, "Curve"},
10352     {0x6000, "Overlay"},
10353     {0x7fe0, "Pixel"}
10354 };
10355 
10356 
10357 /* DCM_GroupDictionary
10358 **
10359 ** Purpose:
10360 **      DCM_GroupDictionary is used to lookup descriptions of groups in
10361 **      the internal DCM group dictionary.  Caller specifies one group
10362 **      with a group number or all groups by passing 0xffff.  For each
10363 **      group that matches (the one group or wildcard), this function
10364 **      invokes the caller's callback function.
10365 **      When the callback function is invoked, the arguments are the
10366 **      group number, an ASCII description of the group and user context
10367 **      information that was passed by the caller originally.
10368 **
10369 ** Parameter Dictionary:
10370 **      group           The number of the group to be found in the dictionary.
10371 **      ctx             User context information to be passed to callback
10372 **                      function.
10373 **      callback        The user's callback function, invoked once for each
10374 **                      group that is found during the dictionary lookup.
10375 **
10376 ** Return Values:
10377 **      DCM_NORMAL
10378 ** Notes:
10379 **
10380 ** Algorithm:
10381 **      Description of the algorithm (optional) and any other notes.
10382 */
10383 
10384 CONDITION
10385 DCM_GroupDictionary(unsigned short group, void *ctx,
10386           void (*callback) (unsigned short g, char *description, void *ctx))
10387 {
10388     int i;
10389 
10390     for (i = 0; i < (int) DIM_OF(groupTable); i++) {
10391         if ((group == 0xffff) || (group == groupTable[i].group)) {
10392             callback(groupTable[i].group, groupTable[i].description, ctx);
10393         }
10394     }
10395     return DCM_NORMAL;
10396 }
10397 
10398 /* DCM_ElementDictionary
10399 **
10400 ** Purpose:
10401 **      DCM_ElementDictionary is used to lookup descriptions of elements in
10402 **      the internal DCM element dictionary.  The caller can specify one
10403 **      element to be found or a number of elements as follows:
10404 **              (Group,  Element)       Description
10405 **              GGGG,    EEEE           Lookup one particular element (GGGGEEEE)
10406 **              GGGG,    0xffff         Lookup all elements in group GGGG
10407 **              0xffff,  EEEE           Lookup all elements in all groups with
10408 **                                      element number EEEE
10409 **              0xffff,  0xffff         Lookup all elements in all groups
10410 **      For each element that matches (the one element or wildcard), this
10411 **      function invokes the caller's callback function.
10412 **      When the callback function is invoked, the arguments are the
10413 **      element tag, an ASCII description of the element, the element value
10414 **      representation and user context information that was passed by
10415 **      the caller originally.
10416 **
10417 ** Parameter Dictionary:
10418 **      tag             The tag of the element to be found in the dictionary.
10419 **      ctx             User context information to be passed to callback
10420 **                      function.
10421 **      callback        The user's callback function, invoked once for each
10422 **                      element that is found during the dictionary lookup.
10423 **
10424 ** Return Values:
10425 **      DCM_NORMAL
10426 ** Notes:
10427 **
10428 ** Algorithm:
10429 **      Description of the algorithm (optional) and any other notes.
10430 */
10431 
10432 CONDITION
10433 DCM_ElementDictionary(DCM_TAG tag, void *ctx,
10434   void (*callback) (DCM_TAG t, char *description, DCM_VALUEREPRESENTATION r,
10435                     void *ctx))
10436 {
10437     int i;
10438     unsigned long j;
10439     GROUPPTR *p;
10440     DCMDICT *dictionaryPtr;
10441 
10442     for (i = 0; i < (int) DIM_OF(group_dictionary); i++) {
10443         if ((DCM_TAG_GROUP(tag) == group_dictionary[i].group) ||
10444             (DCM_TAG_GROUP(tag) == 0xffff)) {
10445             p = &group_dictionary[i];
10446             dictionaryPtr = p->dict;
10447             for (j = 0; j < p->entries; j++, dictionaryPtr++) {
10448                 if ((DCM_TAG_ELEMENT(tag) == 0xffff) ||
10449                     (DCM_TAG_ELEMENT(tag) == DCM_TAG_ELEMENT(dictionaryPtr->tag))) {
10450                     callback(dictionaryPtr->tag,
10451                              dictionaryPtr->englishDescription,
10452                              dictionaryPtr->representation,
10453                              ctx);
10454                 }
10455             }
10456         }
10457     }
10458     return DCM_NORMAL;
10459 }
10460 /*
10461           Copyright (C) 1993, 1994, RSNA and Washington University
10462 
10463           The software and supporting documentation for the Radiological
10464           Society of North America (RSNA) 1993, 1994 Digital Imaging and
10465           Communications in Medicine (DICOM) Demonstration were developed
10466           at the
10467                   Electronic Radiology Laboratory
10468                   Mallinckrodt Institute of Radiology
10469                   Washington University School of Medicine
10470                   510 S. Kingshighway Blvd.
10471                   St. Louis, MO 63110
10472           as part of the 1993, 1994 DICOM Central Test Node project for, and
10473           under contract with, the Radiological Society of North America.
10474 
10475           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
10476           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
10477           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
10478           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
10479           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
10480           THE SOFTWARE IS WITH THE USER.
10481 
10482           Copyright of the software and supporting documentation is
10483           jointly owned by RSNA and Washington University, and free access
10484           is hereby granted as a license to use this software, copy this
10485           software and prepare derivative works based upon this software.
10486           However, any distribution of this software source code or
10487           supporting documentation or derivative works (source code and
10488           supporting documentation) must include the three paragraphs of
10489           the copyright notice.
10490 */
10491 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
10492 
10493 /*
10494 **                              DICOM 93
10495 **                   Electronic Radiology Laboratory
10496 **                 Mallinckrodt Institute of Radiology
10497 **              Washington University School of Medicine
10498 **
10499 ** Module Name(s):
10500 **                      DCM_ListToString
10501 **                      DCM_IsString
10502 ** Author, Date:        Stephen M. Moore, 13-Jun-93
10503 ** Intent:              This file contains more DCM routines which are used
10504 **                      as support for the DCM facility and for applications.
10505 **                      These routines help parse strings and other data
10506 **                      values that are encoded in DICOM objects.
10507 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
10508 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
10509 ** Revision:            $Revision: 1.2 $
10510 ** Status:              $State: Exp $
10511 */
10512 
10513 /* DCM_ListToString
10514 **
10515 ** Purpose:
10516 **      Convert the list of strings into a single string separated by '\'
10517 **
10518 ** Parameter Dictionary:
10519 **      list            Handle to the list of strings
10520 **      offset          The actual string starts at "offset" offset in
10521 **                      each individual structure chained in the list
10522 **      string          The single large string returned to the caller
10523 **
10524 ** Return Values:
10525 **      DCM_NORMAL
10526 **      DCM_LISTFAILURE
10527 **      DCM_MALLOCFAILURE
10528 **
10529 ** Notes:
10530 **
10531 ** Algorithm:
10532 **      Description of the algorithm (optional) and any other notes.
10533 */
10534 typedef struct {
10535     void *reserved[2];
10536     char *s;
10537 }   GENERIC;
10538 
10539 CONDITION
10540 DCM_ListToString(LST_HEAD * list, long offset, char **string)
10541 {
10542     GENERIC
10543         * g;
10544     char
10545        *c,
10546        *p;
10547     long
10548         length;
10549 
10550     *string = NULL;
10551     if (list == NULL)
10552         return DCM_NORMAL;
10553 
10554     g = (void *)LST_Head(&list);
10555     if (g == NULL)
10556         return DCM_NORMAL;
10557 
10558     (void) LST_Position(&list, (void *)g);
10559 
10560     length = 0;
10561     while (g != NULL) {
10562         c = ((char *) g) + offset;
10563         length += strlen(c) + 1;
10564         g = (void *)LST_Next(&list);
10565     }
10566 
10567     p = CTN_MALLOC(length);
10568     if (p == NULL)
10569         return COND_PushCondition(DCM_MALLOCFAILURE,
10570                 DCM_Message(DCM_MALLOCFAILURE), length, "DCM_ListToString");
10571 
10572     *string = p;
10573     g = (void *)LST_Head(&list);
10574     if (g == NULL)
10575         return COND_PushCondition(DCM_LISTFAILURE, DCM_Message(DCM_LISTFAILURE),
10576                                   "DCM_ListToString");
10577     (void) LST_Position(&list, (void *)g);
10578 
10579     length = 0;
10580     while (g != NULL) {
10581         c = ((char *) g) + offset;
10582         length = strlen(c);
10583         (void) memcpy(p, c, length);
10584         p += length;
10585         *p++ = '\\';
10586         g = (void *)LST_Next(&list);
10587     }
10588     *--p = '\0';
10589     return DCM_NORMAL;
10590 }
10591 
10592 
10593 /* DCM_IsString
10594 **
10595 ** Purpose:
10596 **      Verify if the DICOM value representation is that of a string
10597 **
10598 ** Parameter Dictionary:
10599 **      representation          One of the many DICOM value representations
10600 **
10601 ** Return Values:
10602 **      TRUE
10603 **      FALSE
10604 **
10605 ** Notes:
10606 **
10607 ** Algorithm:
10608 **      Description of the algorithm (optional) and any other notes.
10609 */
10610 
10611 CTNBOOLEAN
10612 DCM_IsString(DCM_VALUEREPRESENTATION representation)
10613 {
10614     CTNBOOLEAN
10615         flag = FALSE;
10616 
10617     switch (representation) {
10618     case DCM_AE:                /* Application Entity */
10619     case DCM_AS:                /* Age string */
10620         flag = TRUE;
10621         break;
10622     case DCM_AT:                /* Attribute tag */
10623         break;
10624     case DCM_CS:                /* Control string */
10625     case DCM_DA:                /* Date */
10626         flag = TRUE;
10627         break;
10628     case DCM_DD:                /* Data set */
10629         break;
10630     case DCM_DS:                /* Decimal string */
10631     case DCM_DT:                /* Old date/time */
10632         flag = TRUE;
10633         break;
10634     case DCM_FD:                /* Floating double */
10635     case DCM_FL:                /* Float */
10636         break;
10637     case DCM_IS:                /* Integer string */
10638     case DCM_LO:                /* Long string */
10639     case DCM_LT:                /* Long text */
10640         flag = TRUE;
10641         break;
10642     case DCM_OB:                /* Other binary value (byte) */
10643     case DCM_OT:                /* Other binary value */
10644     case DCM_OW:                /* Other binary value (word) */
10645         break;
10646     case DCM_SH:                /* Short string */
10647         flag = TRUE;
10648         break;
10649     case DCM_SL:                /* Signed long */
10650     case DCM_SQ:                /* Sequence of items */
10651     case DCM_SS:                /* Signed short */
10652         break;
10653     case DCM_ST:                /* Short text */
10654     case DCM_TM:                /* Time */
10655         flag = TRUE;
10656         break;
10657     case DCM_UL:                /* Unsigned long */
10658     case DCM_US:                /* Unsigned short */
10659     /*case DCM_UNKNOWN:*/       /* Unknown/unspecified */
10660     case DCM_RET:               /* Retired */
10661     case DCM_CTX:               /* Context sensitive */
10662         break;
10663     case DCM_PN:                /* Person Name */
10664     case DCM_UI:                /* Unique identifier (UID) */
10665     case DCM_UT:                /* Unlimited Text */
10666         flag = TRUE;
10667         break;
10668     };
10669     return flag;
10670 }
10671 /*
10672           Copyright (C) 1993, RSNA and Washington University
10673 
10674           The software and supporting documentation for the Radiological
10675           Society of North America (RSNA) 1993 Digital Imaging and
10676           Communications in Medicine (DICOM) Demonstration were developed
10677           at the
10678                   Electronic Radiology Laboratory
10679                   Mallinckrodt Institute of Radiology
10680                   Washington University School of Medicine
10681                   510 S. Kingshighway Blvd.
10682                   St. Louis, MO 63110
10683           as part of the 1993 DICOM Central Test Node project for, and
10684           under contract with, the Radiological Society of North America.
10685 
10686           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
10687           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
10688           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
10689           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
10690           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
10691           THE SOFTWARE IS WITH THE USER.
10692 
10693           Copyright of the software and supporting documentation is
10694           jointly owned by RSNA and Washington University, and free access
10695           is hereby granted as a license to use this software, copy this
10696           software and prepare derivative works based upon this software.
10697           However, any distribution of this software source code or
10698           supporting documentation or derivative works (source code and
10699           supporting documentation) must include the three paragraphs of
10700           the copyright notice.
10701 */
10702 /*
10703 ** @$=@$=@$=
10704 */
10705 /*
10706 **                              DICOM 93
10707 **                   Electronic Radiology Laboratory
10708 **                 Mallinckrodt Institute of Radiology
10709 **              Washington University School of Medicine
10710 **
10711 ** Module Name(s):
10712 ** Author, Date:        Thomas R. Leith, 15-Apr-93
10713 ** Intent:              This package implements atomic functions on
10714 **                      linked lists.
10715 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
10716 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
10717 ** Revision:            $Revision: 1.2 $
10718 ** Status:              $State: Exp $
10719 */
10720 
10721 #define CURRENT  (*list)->current
10722 #define OLD_NEXT (*list)->current->next
10723 #define OLD_PREV (*list)->current->previous
10724 
10725 
10726 
10727 LST_HEAD *
10728 LST_Create(void)
10729 /*
10730 **  This module creates a new list head and returns your handle to it.
10731 **
10732 */
10733 {
10734     LST_HEAD
10735     * ptr;
10736 
10737     ptr = CTN_MALLOC(sizeof(LST_HEAD));
10738     if (ptr == NULL)
10739         return NULL;
10740 
10741     ptr->head = NULL;
10742     ptr->tail = NULL;
10743     ptr->current = NULL;
10744     ptr->count = 0;
10745     return ptr;
10746 }
10747 
10748 
10749 
10750 CONDITION
10751 LST_Destroy(LST_HEAD ** list)
10752 /*
10753  *  This routine will destroy a list.  The list must be empty.
10754  *  The list handle is set to NULL as a side-effect.
10755  *
10756  */
10757 {
10758 
10759     if ((*list)->count != 0)
10760         return LST_LISTNOTEMPTY;
10761 
10762     CTN_FREE(*list);
10763     *list = NULL;
10764     return LST_NORMAL;
10765 }
10766 
10767 
10768 
10769 CONDITION
10770 LST_Enqueue(LST_HEAD ** list, LST_NODE * node)
10771 /*
10772  *  Adds a new node to the tail of the list and returns
10773  *  status.
10774  *
10775  */
10776 {
10777     node->next = NULL;          /* no next node              */
10778     node->previous = (*list)->tail;     /* previous is old tail      */
10779     if ((*list)->head == NULL)  /* if list was empty...      */
10780         (*list)->head = node;   /* it has a head now!        */
10781     else
10782         (*list)->tail->next = node;     /* old tail now has a next   */
10783 
10784     (*list)->tail = node;       /* list now has a new tail    */
10785     (*list)->count++;           /* bump the counter           */
10786     return LST_NORMAL;
10787 }
10788 
10789 CONDITION
10790 LST_Push(LST_HEAD ** list, LST_NODE * node)
10791 /*
10792  *  Adds a new node to the head of the list and returns
10793  *  status.
10794  *
10795  */
10796 
10797 {
10798     node->next = (*list)->head; /* set the forward link      */
10799     node->previous = NULL;      /* set rearward link         */
10800     if ((*list)->tail == NULL)  /* if the list was empty     */
10801         (*list)->tail = node;   /* set the tail pointer      */
10802     else                        /* otherwise,                */
10803         (*list)->head->previous = node; /* old head now has a previous                  */
10804 
10805     (*list)->head = node;       /* set new first node        */
10806     (*list)->count++;           /* bump the counter          */
10807     return LST_NORMAL;
10808 
10809 }
10810 
10811 LST_NODE *
10812 LST_Dequeue(LST_HEAD ** list)
10813 /*
10814  *  Removes a node from the head of the list and returns
10815  *  a pointer to it.
10816  *
10817  */
10818 {
10819     LST_NODE
10820     * ptr;
10821 
10822     if ((*list)->head == NULL) {/* list is empty             */
10823         (*list)->count = 0;
10824         return NULL;
10825     }
10826     ptr = (*list)->head;        /* save the head             */
10827     (*list)->head = ptr->next;  /* set new head of list      */
10828     if ((*list)->head == NULL)  /* if the list is now empty  */
10829         (*list)->tail = NULL;   /* there is no tail anymore  */
10830     else
10831         (*list)->head->previous = NULL; /* new head has no previous  */
10832     ptr->next = NULL;           /* hide data from user       */
10833     (*list)->count--;           /* list has one fewer node   */
10834     /* now                       */
10835     return ptr;
10836 }
10837 
10838 
10839 
10840 LST_NODE *
10841 LST_Pop(LST_HEAD ** list)
10842 /*
10843  *  Removes a node from the head of the list and returns
10844  *  a pointer to it.
10845  *
10846  */
10847 {
10848     LST_NODE
10849     * ptr;
10850 
10851     if ((*list)->head == NULL) {/* list is empty             */
10852         (*list)->count = 0;
10853         return NULL;
10854     }
10855     ptr = (*list)->head;        /* save the head             */
10856     (*list)->head = ptr->next;  /* set new head of list      */
10857     if ((*list)->head == NULL)  /* if the list is now empty  */
10858         (*list)->tail = NULL;   /* there is no tail anymore  */
10859     else
10860         (*list)->head->previous = NULL; /* new head has no previous  */
10861     ptr->next = NULL;           /* hide data from user       */
10862     (*list)->count--;           /* list has one fewer node   */
10863     /* now                       */
10864     return ptr;
10865 }
10866 
10867 
10868 
10869 unsigned long
10870 LST_Count(LST_HEAD ** list)
10871 /*
10872  *  Returns the number of nodes in the list.
10873  *
10874  */
10875 {
10876     return (*list)->count;
10877 }
10878 
10879 
10880 
10881 LST_NODE *
10882 LST_Head(LST_HEAD ** list)
10883 /*
10884  *  Returns a pointer to the node at the head of the list.
10885  *  It does NOT remove the node from the list.
10886  *
10887  */
10888 {
10889     return (*list)->head;
10890 }
10891 
10892 
10893 LST_NODE *
10894 LST_Current(LST_HEAD ** list)
10895 /*
10896  *  Returns a pointer to the current node.
10897  *  It does NOT remove the node from the list.
10898  *
10899  */
10900 {
10901     return (*list)->current;
10902 }
10903 
10904 
10905 
10906 LST_NODE *
10907 LST_Tail(LST_HEAD ** list)
10908 /*
10909  *  Returns a pointer to the node at the tail of the list.
10910  *  It does NOT remove the node from the list.
10911  *
10912  */
10913 {
10914     return (*list)->tail;
10915 }
10916 
10917 
10918 CONDITION
10919 LST_Insert(LST_HEAD ** list, LST_NODE * node, LST_END where)
10920 /*
10921 **  Inserts a new node in the list.  User selects whether to insert closer
10922 **  the HEAD end, or the TAIL end.  If the list is empty, the distinction is
10923 **  moot.  In any case, CURRENT is set to the newly-inserted node.  In the
10924 **  case of an error, the list is unchanged.
10925 **/
10926 
10927 {
10928     if ((where != LST_K_BEFORE) && (where != LST_K_AFTER))
10929         goto badend;
10930 
10931     if ((*list)->head == NULL) {/* if the list was empty     */
10932         (*list)->tail = node;   /* set the tail pointer      */
10933         (*list)->head = node;   /* set the head pointer      */
10934         (*list)->count = 0;     /* will get bumped later...  */
10935         (node)->next = NULL;    /* there is no next          */
10936         (node)->previous = NULL;/* and no previous           */
10937 
10938     } else if (CURRENT == NULL) /* is he mixing semantics?       */
10939         goto nocurrent;
10940 
10941     else if ((CURRENT == (*list)->head) &&      /* if at the head           */
10942              (where == LST_K_BEFORE)) { /* and inserting BEFORE   */
10943         node->next = CURRENT;   /* splice new node in       */
10944         CURRENT->previous = node;       /* before the current     */
10945         node->previous = NULL;  /* new one has no previous  */
10946         (*list)->head = node;   /* new one is first now     */
10947 
10948     } else if ((CURRENT == (*list)->tail) &&    /* if at the tail           */
10949                (where == LST_K_AFTER)) {        /* and inserting AFTER    */
10950         node->next = NULL;      /* new node has no next     */
10951         node->previous = (*list)->tail; /* previous is old tail     */
10952         CURRENT->next = node;   /* splice new node in       */
10953         (*list)->tail = node;   /* new node is now the tail */
10954 
10955     } else if (where == LST_K_AFTER) {  /* not a special case       */
10956         OLD_NEXT->previous = node;      /* we preceed a node        */
10957         node->next = OLD_NEXT;  /* the old next follows us  */
10958         node->previous = CURRENT;       /* the current preceeds us  */
10959         CURRENT->next = node;   /* we follow current        */
10960 
10961     } else {                    /* not a special case       */
10962         OLD_PREV->next = node;  /* we follow the previous   */
10963         node->previous = OLD_PREV;      /* of current            */
10964         node->next = CURRENT;   /* current follows us and   */
10965         CURRENT->previous = node;       /* we preceed current     */
10966     };
10967 
10968     (*list)->count++;           /* bump the counter          */
10969     (*list)->current = node;    /* and set current        */
10970     return LST_NORMAL;
10971 
10972 badend:
10973     return LST_BADEND;
10974 
10975 nocurrent:
10976     return LST_NOCURRENT;
10977 }
10978 
10979 
10980 
10981 LST_NODE *
10982 LST_Remove(LST_HEAD ** list, LST_END dir)
10983 /*
10984 **  Removes the current node from the list and returns a pointer to it.
10985 **  How CURRENT gets set depends on which way the DIR argument points.  If
10986 **  DIR is LST_K_BEFORE, CURRENT will move towards the tail-end of the
10987 **  list.  If DIR is LST_K_AFTER, CURRENT will move towards the head-end of
10988 **  the list.  If there is no node in the direction of DIR, CURRENT becomes
10989 **  undefined.
10990 **
10991 **/
10992 {
10993     LST_NODE
10994     * ptr;
10995 
10996     if ((dir != LST_K_BEFORE) && (dir != LST_K_AFTER))
10997         goto baddir;
10998     if (CURRENT == NULL)
10999         goto nocurrent;
11000     if ((*list)->head == NULL)
11001         goto listempty;
11002 
11003     ptr = CURRENT;              /* save node                 */
11004 
11005     if (CURRENT == (*list)->head) {     /* removing the head         */
11006         (*list)->head = OLD_NEXT;       /* set new head of list      */
11007         if ((*list)->head == NULL)      /* if the list is now empty  */
11008             (*list)->tail = NULL;       /* no tail anymore either    */
11009         else
11010             (*list)->head->previous = NULL;     /* new head has no previous  */
11011         if (dir == LST_K_BEFORE)/* there is nothing before   */
11012             (*list)->current = NULL;    /* the head of the list      */
11013         else                    /* otherwise, remain         */
11014             (*list)->current = (*list)->head;   /* at the head...         */
11015 
11016     } else if (CURRENT == (*list)->tail) {      /* removing the tail         */
11017         (*list)->tail = OLD_PREV;       /* set new tail of list      */
11018         (*list)->tail->next = NULL;     /* new tail has no next      */
11019         if (dir == LST_K_AFTER) /* there is nothing after    */
11020             (*list)->current = NULL;    /* the tail of a list        */
11021         else                    /* otherwise, remain         */
11022             (*list)->current = (*list)->tail;   /* at the tail...            */
11023 
11024     } else {                    /* not a special case        */
11025         OLD_PREV->next = CURRENT->next; /* set forward pointer       */
11026         OLD_NEXT->previous = CURRENT->previous; /* set backward pointer      */
11027         if (dir == LST_K_BEFORE)/* depending on direction,   */
11028             (*list)->current = CURRENT->previous;       /* set current             */
11029         else                    /* in the                    */
11030             (*list)->current = CURRENT->next;   /* list head                 */
11031     }
11032 
11033     (*list)->count--;           /* one fewer nodes now       */
11034     ptr->previous = NULL;       /* hide data from user       */
11035     ptr->next = NULL;           /* hide data from user       */
11036     return ptr;
11037 
11038 baddir:
11039     return NULL;
11040 
11041 nocurrent:
11042     return NULL;
11043 
11044 listempty:
11045     (*list)->count = 0;
11046     (*list)->current = NULL;
11047     (*list)->head = (*list)->tail = NULL;
11048     return NULL;
11049 }
11050 
11051 
11052 
11053 LST_NODE *
11054 LST_Next(LST_HEAD ** list)
11055 /*
11056  *  Returns a pointer to the next node in the list and
11057  *  makes it current.
11058  *
11059  */
11060 {
11061     if ((*list)->head == NULL) {/* list is empty            */
11062         (*list)->count = 0;
11063         return NULL;
11064     }
11065     if (CURRENT == NULL) {      /* there is no CURRENT      */
11066         return NULL;
11067     }
11068     CURRENT = CURRENT->next;    /* Set current to next and return it */
11069     return CURRENT;
11070 }
11071 
11072 
11073 
11074 LST_NODE *
11075 LST_Previous(LST_HEAD ** list)
11076 /*
11077  *  Returns a pointer to the previous node in the list and
11078  *  makes it current.
11079  *
11080  */
11081 {
11082     if ((*list)->head == NULL) {/* list is empty     */
11083         (*list)->count = 0;
11084         return NULL;
11085     }
11086     if (CURRENT == NULL) {      /* there is no CURRENT       */
11087         return NULL;
11088     }
11089     if (CURRENT->previous == NULL) {    /* no PREVIOUS               */
11090         return NULL;
11091     }
11092     CURRENT = CURRENT->previous;/* found it                  */
11093     return CURRENT;
11094 }
11095 
11096 
11097 
11098 LST_NODE *
11099 LST_Position(LST_HEAD ** list, LST_NODE * node)
11100 /*
11101  *  Make a node current and return the argument.
11102  *
11103  *
11104  *  Notes:  node = lst_position(list, lst_head(list));
11105  *          makes the node at the head of the list current
11106  *          and returns a pointer to it.
11107  *
11108  *      The routine tries to verify that "node" is in the list
11109  *      by doing a few consistency checks.  It assumes that if
11110  *      any of three "known" pointers are what they should be
11111  *      that all is well.  Its not damnfoolproof, but...
11112  */
11113 {
11114     if ((*list)->head == NULL) {/* list is empty     */
11115         return NULL;
11116     }
11117     if (node == NULL)
11118         return NULL;
11119     if (((node->previous == NULL) && ((*list)->head == node)) ||
11120         ((node->next == NULL) && ((*list)->tail == node)) ||
11121         (node->previous->next == node)) {       /* its probably OK       */
11122 
11123         CURRENT = node;
11124         return CURRENT;
11125     };
11126 
11127     return NULL;
11128 }
11129 
11130 /*
11131  *  Sort a list in order according to a comparison algorithm provided
11132  *  by the caller.
11133  *
11134  */
11135 CONDITION
11136 LST_Sort(LST_HEAD ** list, size_t nodeSize, int (*compare) ())
11137 {
11138     LST_NODE
11139         * n1,
11140         *n2;
11141     LST_HEAD
11142         temp,
11143         *head;
11144     CTNBOOLEAN
11145         inserted;
11146     int ccc ;
11147 
11148     if ((*list)->head == NULL) {/* list is empty     */
11149         return LST_NORMAL;
11150     }
11151     head = &temp;
11152     head->head = NULL;
11153     head->tail = NULL;
11154     head->current = NULL;
11155     head->count = 0;
11156 
11157     while ((n1 = LST_Dequeue(list)) != NULL) {
11158         n2 = LST_Head(&head);
11159         if (n2 != NULL)
11160             (void) LST_Position(&head, n2);
11161         inserted = FALSE;
11162         while (n2 != NULL && !inserted) {
11163 #if 0
11164             if (compare(n1, n2) < 0) {
11165 #else
11166             AFNI_CALL_VALU_2ARG(compare,int,ccc,LST_NODE *,n1,LST_NODE *,n2) ;
11167             if( ccc < 0 ){
11168 #endif
11169                 (void) LST_Insert(&head, n1, LST_K_BEFORE);
11170                 inserted = TRUE;
11171             } else
11172                 n2 = LST_Next(&head);
11173         }
11174         if (n2 == NULL)
11175             (void) LST_Enqueue(&head, n1);
11176     }
11177     **list = *head;
11178     return LST_NORMAL;
11179 }
11180 
11181 /*
11182  *  Return the item at position index.  Can be NULL if list is
11183  *  empty or we go off the end of the list.
11184  *
11185  */
11186 LST_NODE *
11187 LST_Index(LST_HEAD ** l, int index)
11188 {
11189     LST_NODE
11190     * n;
11191 
11192     n = LST_Head(l);
11193     if (n == NULL)
11194         return NULL;
11195 
11196     index--;
11197     LST_Position(l, n);
11198     while (index-- > 0 && n != NULL)
11199         n = LST_Next(l);
11200 
11201     return n;
11202 }
11203 /*
11204           Copyright (C) 1993, 1994, RSNA and Washington University
11205 
11206           The software and supporting documentation for the Radiological
11207           Society of North America (RSNA) 1993, 1994 Digital Imaging and
11208           Communications in Medicine (DICOM) Demonstration were developed
11209           at the
11210                   Electronic Radiology Laboratory
11211                   Mallinckrodt Institute of Radiology
11212                   Washington University School of Medicine
11213                   510 S. Kingshighway Blvd.
11214                   St. Louis, MO 63110
11215           as part of the 1993, 1994 DICOM Central Test Node project for, and
11216           under contract with, the Radiological Society of North America.
11217 
11218           THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND NEITHER RSNA NOR
11219           WASHINGTON UNIVERSITY MAKE ANY WARRANTY ABOUT THE SOFTWARE, ITS
11220           PERFORMANCE, ITS MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
11221           USE, FREEDOM FROM ANY COMPUTER DISEASES OR ITS CONFORMITY TO ANY
11222           SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND PERFORMANCE OF
11223           THE SOFTWARE IS WITH THE USER.
11224 
11225           Copyright of the software and supporting documentation is
11226           jointly owned by RSNA and Washington University, and free access
11227           is hereby granted as a license to use this software, copy this
11228           software and prepare derivative works based upon this software.
11229           However, any distribution of this software source code or
11230           supporting documentation or derivative works (source code and
11231           supporting documentation) must include the three paragraphs of
11232           the copyright notice.
11233 */
11234 /* Copyright marker.  Copyright will be inserted above.  Do not remove */
11235 
11236 /*
11237 **                   Electronic Radiology Laboratory
11238 **                 Mallinckrodt Institute of Radiology
11239 **              Washington University School of Medicine
11240 **
11241 ** Module Name(s):      UTL_RegexMatch, UTL_ConvertRegex,
11242 **                      UTL_ConvertDatetoLong, UTL_ConvertLongtoDate,
11243 **                      UTL_ConvertTimetoFloat, UTL_ConvertFloattoTime,
11244 **                      UTL_SqueezeBlanks, UTL_DateMatch, UTL_TimeMatch
11245 **                      UTL_GetDicomDate, UTL_GetDicomTime
11246 **
11247 ** Author, Date:        David E. Beecher, March 1994
11248 ** Intent:              Miscellaneous functions that may be useful in
11249 **                      a number of different areas.
11250 **
11251 ** Last Update:         $Author: rickr $, $Date: 2005/06/22 14:39:43 $
11252 ** Source File:         $RCSfile: l_mri_dicom_hdr.c,v $
11253 ** Revision:            $Revision: 1.2 $
11254 ** Status:              $State: Exp $
11255 */
11256 
11257 #if 0
11258 /* UTL_RegexMatch
11259 **
11260 ** Purpose:
11261 **      Perform a DICOM regular expression match with the specified string, stm.
11262 **
11263 ** Parameter Dictionary:
11264 **      char *regex:
11265 **              The DICOM regular expression to try and match.
11266 **      char *stm:
11267 **              The input string to match.
11268 **
11269 ** Return Values:
11270 **      UTL_MATCH:      The input string matched the regular expression.
11271 **      UTL_NOMATCH:    The input string did not match the regular expression.
11272 **
11273 ** Algorithm:
11274 **      A simple function to perform a DICOM regular expression match with the
11275 **      specified  string, stm.  The sematics of the DICOM patterns must be altered
11276 **      slightly to work correctly with regex under unix...more information may
11277 **      be found below.
11278 **
11279 */
11280 
11281 #ifdef DARWIN
11282 #define USEREGCOMP
11283 #endif
11284 
11285 #ifdef USEREGCOMP
11286 #include <regex.h>
11287 #endif
11288 
11289 CONDITION
11290 UTL_RegexMatch(char *regex, char *stm)
11291 {
11292 #ifdef USEREGCOMP
11293 
11294     int
11295         ret,
11296         regexReturn;
11297     char
11298        *new_rstring;
11299     regex_t preg;
11300     char errorBuff[256];
11301     regmatch_t pmatch;
11302 
11303     new_rstring = UTL_ConvertRegex(regex);
11304 
11305     regexReturn = regcomp(&preg, new_rstring, 0);
11306     if (regexReturn != 0) {
11307         regerror(regexReturn, &preg, errorBuff, sizeof(errorBuff));
11308         fprintf(stderr, "%d\n", regexReturn);
11309         fprintf(stderr, "%s\n", errorBuff);
11310 
11311         free(new_rstring);
11312         return (UTL_NOMATCH);
11313     } else {
11314         ret = regexec(&preg, stm, 1, &pmatch, 0);
11315 
11316         switch (ret) {
11317         case 0:
11318             free(new_rstring);
11319             return (UTL_MATCH);
11320             break;
11321         default:
11322             free(new_rstring);
11323             return (UTL_NOMATCH);
11324             break;
11325         }
11326     }
11327 #else
11328     int
11329         ret;
11330     char
11331        *new_rstring;
11332 
11333     new_rstring = UTL_ConvertRegex(regex);
11334     if (re_comp(new_rstring) != (char *) 0) {
11335         free(new_rstring);
11336         return (UTL_NOMATCH);
11337     } else {
11338         ret = re_exec(stm);
11339         switch (ret) {
11340         case 0:
11341         case -1:
11342             free(new_rstring);
11343             return (UTL_NOMATCH);
11344             break;
11345         case 1:
11346             free(new_rstring);
11347             return (UTL_MATCH);
11348             break;
11349         }
11350     }
11351 #endif
11352 }
11353 
11354 /* UTL_ConvertRegex
11355 **
11356 ** Purpose:
11357 **      This function converts a DICOM "regular expression" to the proper
11358 **      regex semantics under unix.
11359 **
11360 ** Parameter Dictionary:
11361 **      char *regex:
11362 **              The DICOM regular expression to convert.
11363 **
11364 ** Return Values:
11365 **      char *: The converted regular expression which expresses DICOM pattern
11366 **              matching in regex semantics.
11367 **
11368 ** Notes:
11369 **      This routine needs to return a string of unknown length.  Since we
11370 **      don't want to burden the caller with having to remember to free the
11371 **      string after it has been used, we simply reuse the same piece of storage
11372 **      and realloc it when necessary to increase the size.
11373 **
11374 ** Algorithm:
11375 **      Simple function to convert a DICOM "regular expression" to the proper
11376 **      regex semantics under unix.  DICOM has only 2 meta characters, "*" for 0
11377 **      or more occurrences, and "?" for a single character.  The "*" must be
11378 **      converted to ".*" for regex while the "?" must be converted to ".".
11379 **      Other special characters to regex like "[", "]", and "." must also
11380 **      be escaped with the "\".  The DICOM escape character is assumed to be "\".
11381 */
11382 char *
11383 UTL_ConvertRegex(char *regex)
11384 {
11385 
11386     char
11387        *new_regex = (char *) NULL;
11388     int
11389         malloced_size = 0;
11390     int
11391         i,
11392         j,
11393         escape_on;
11394 
11395     if (new_regex == (char *) NULL) {
11396         malloced_size = REGEX_SIZE;
11397         if ((new_regex = (char *) malloc(malloced_size)) == (char *) NULL) {
11398             return ((char *) NULL);
11399         }
11400     }
11401     i = j = 0;
11402     escape_on = OFF;
11403     new_regex[j++] = '^';
11404     while (regex[i] != '\000') {
11405         switch (regex[i]) {
11406         case '*':               /* Transform the "*" to ".*" or "\*" if
11407                                  * escaped */
11408             switch (escape_on) {
11409             case OFF:
11410                 new_regex[j++] = '.';
11411                 break;
11412             case ON:
11413                 new_regex[j++] = '\\';
11414                 escape_on = OFF;
11415                 break;
11416             }
11417             new_regex[j++] = '*';
11418             i++;
11419             break;
11420         case '?':               /* Transform the "?" to "." or "?" if escaped */
11421             switch (escape_on) {
11422             case OFF:
11423                 new_regex[j++] = '.';
11424                 break;
11425             case ON:
11426                 new_regex[j++] = '?';
11427                 escape_on = OFF;
11428                 break;
11429             }
11430             i++;
11431             break;
11432         case '\\':              /* Note that we have seen the escape
11433                                  * character */
11434             switch (escape_on) {
11435             case OFF:
11436                 escape_on = ON;
11437                 break;
11438             case ON:
11439                 escape_on = OFF;
11440                 new_regex[j++] = '\\';
11441                 new_regex[j++] = '\\';
11442                 break;
11443             }
11444             i++;
11445             break;
11446         case '.':
11447         case '[':               /* These are special to regex and need to be
11448                                  * escaped */
11449         case ']':
11450             new_regex[j++] = '\\';
11451             new_regex[j++] = regex[i++];
11452             escape_on = OFF;
11453             break;
11454         default:                /* Leave the "\" in at this juncture */
11455             switch (escape_on) {
11456             case ON:
11457                 new_regex[j++] = '\\';
11458                 escape_on = OFF;
11459                 break;
11460             case OFF:
11461                 break;
11462             }
11463             new_regex[j++] = regex[i++];
11464             break;
11465         }
11466         if (j >= (malloced_size - 2)) {
11467             malloced_size += REGEX_SIZE;
11468             if ((new_regex = (char *) realloc(new_regex, malloced_size)) ==
11469                 (char *) NULL) {
11470                 return ((char *) NULL);
11471             }
11472         }
11473     }
11474     new_regex[j++] = '$';
11475     new_regex[j] = '\000';
11476     return (new_regex);
11477 }
11478 #endif
11479 /* UTL_ConvertDatetoLong
11480 **      Convert a Dicom date to a long for comparision ease.
11481 */
11482 long
11483 UTL_ConvertDatetoLong(const char *date)
11484 {
11485 
11486     char
11487         year[5],
11488         month[3],
11489         day[3];
11490 
11491     strncpy(year, date, 4);
11492     year[4] = '\000';
11493     strncpy(month, date + 4, 2);
11494     month[2] = '\000';
11495     strncpy(day, date + 6, 2);
11496     day[2] = '\000';
11497 
11498     return ((atol(year) * 10000) + (atol(month) * 100) + atol(day));
11499 }
11500 
11501 /* UTL_ConvertLongtoDate
11502 **      Convert a long to a Dicom date.
11503 */
11504 void
11505 UTL_ConvertLongtoDate(long ld, char *date)
11506 {
11507 
11508     int
11509         year,
11510         month,
11511         day;
11512 
11513     year = ld / 10000;
11514     ld -= (year * 10000);
11515     month = ld / 100;
11516     ld -= (month * 100);
11517     day = ld;
11518 
11519     sprintf(date, "%04d%02d%02d", year, month, day);
11520 
11521     return;
11522 }
11523 
11524 /* UTL_ConvertTimetoFloat
11525 **      Convert a Dicom time to a floating point number for comparision ease.
11526 */
11527 double
11528 UTL_ConvertTimetoFloat(const char *time)
11529 {
11530 
11531     size_t
11532     i;
11533     char
11534         hour[3],
11535         minute[3],
11536         second[3],
11537         fracsec[7];
11538     const char *p;
11539     double
11540         divisor,
11541         hh,
11542         mm,
11543         ss,
11544         fs;
11545 
11546     hh = mm = ss = fs = 0.0;
11547     hour[0] = minute[0] = second[0] = fracsec[0] = '\000';
11548 
11549     p = time;
11550     /*
11551      * Just a brute force way to tear down a Dicom time...not very pretty,
11552      * but it works... We are not guaranteed to have every field present as
11553      * we are in the date...
11554      */
11555     hour[0] = *p++;
11556     hour[1] = *p++;
11557     hour[2] = '\000';
11558     if (isdigit(*p)) {
11559         minute[0] = *p++;
11560         minute[1] = *p++;
11561         minute[2] = '\000';
11562         if (isdigit(*p)) {
11563             second[0] = *p++;
11564             second[1] = *p++;
11565             second[2] = '\000';
11566             if (*p == '.') {
11567                 p++;
11568                 fracsec[0] = *p++;
11569                 if ((*p != '\000') && (isdigit(*p))) {
11570                     fracsec[1] = *p++;
11571                     if ((*p != '\000') && (isdigit(*p))) {
11572                         fracsec[2] = *p++;
11573                         if ((*p != '\000') && (isdigit(*p))) {
11574                             fracsec[3] = *p++;
11575                             if ((*p != '\000') && (isdigit(*p))) {
11576                                 fracsec[4] = *p++;
11577                                 if ((*p != '\000') && (isdigit(*p))) {
11578                                     fracsec[5] = *p++;
11579                                     fracsec[6] = '\000';
11580                                 } else
11581                                     fracsec[5] = '\000';
11582                             } else
11583                                 fracsec[4] = '\000';
11584                         } else
11585                             fracsec[3] = '\000';
11586                     } else
11587                         fracsec[2] = '\000';
11588                 } else
11589                     fracsec[1] = '\000';
11590             }
11591         }
11592     }
11593     hh = atof(hour);
11594     mm = atof(minute);
11595     ss = atof(second);
11596     divisor = 1;
11597     for (i = 0; i < strlen(fracsec); i++)
11598         divisor *= 10;
11599     fs = atof(fracsec) / divisor;
11600 
11601     return ((hh * 3600.0) + (mm * 60.0) + ss + fs);
11602 }
11603 
11604 /* UTL_ConvertFloattoTime
11605 **      Convert a floating point number to a Dicom time.
11606 */
11607 void
11608 UTL_ConvertFloattoTime(double dt, char *time)
11609 {
11610     int
11611         hour,
11612         minute,
11613         second,
11614         fracsec;
11615 
11616     hour = (int) (dt / 3600.0);
11617     dt -= (hour * 3600);
11618 
11619     minute = (int) (dt / 60.);
11620     dt -= (minute * 60);
11621 
11622     second = (int) dt;
11623     dt -= second;
11624 
11625     fracsec = (int) ((dt * 1000000) + 0.5);
11626 
11627     sprintf(time, "%02d%02d%02d.%06d", hour, minute, second, fracsec);
11628 
11629     return;
11630 }
11631 
11632 
11633 /* UTL_SqueezeBlanks
11634 **
11635 */
11636 void
11637 UTL_SqueezeBlanks(char *s)
11638 {
11639 
11640     char
11641        *t1,
11642        *t2;
11643 
11644     t1 = t2 = s;
11645     while (*t2 != '\000') {
11646         if (*t2 != ' ') {
11647             *t1 = *t2;
11648             t1++;
11649         }
11650         t2++;
11651     }
11652     *t1 = '\000';
11653 
11654     return;
11655 }
11656 /* UTL_DateMatch
11657 **      Match a date range as specified in the Dicom standard
11658 */
11659 CONDITION
11660 UTL_DateMatch(char *datestring, char *stm)
11661 {
11662 
11663     int
11664         match;
11665     char
11666        *ndate;
11667     long
11668         start_date,
11669         end_date,
11670         date_in_question;
11671 
11672     if ((ndate = (char *) malloc(strlen(datestring) + 1)) == (char *) NULL)
11673         return (UTL_NOMATCH);
11674 
11675     strcpy(ndate, datestring);
11676     UTL_SqueezeBlanks(ndate);
11677     UTL_SqueezeBlanks(stm);
11678 
11679     match = 0;
11680     if (strchr(ndate, (int) '-') == (char *) NULL) {
11681         if (strcmp(ndate, stm) == 0)
11682             match = 1;
11683     } else {
11684         date_in_question = UTL_ConvertDatetoLong(stm);
11685         if (ndate[0] == '-') {
11686             end_date = UTL_ConvertDatetoLong(ndate + 1);
11687             if (date_in_question <= end_date)
11688                 match = 1;
11689         } else if (ndate[strlen(ndate) - 1] == '-') {
11690             start_date = UTL_ConvertDatetoLong(ndate);
11691             if (date_in_question >= start_date)
11692                 match = 1;
11693         } else {
11694             start_date = UTL_ConvertDatetoLong(ndate);
11695             end_date = UTL_ConvertDatetoLong(strchr(ndate, (int) '-') + 1);
11696             if ((date_in_question >= start_date) &&
11697                 (date_in_question <= end_date))
11698                 match = 1;
11699         }
11700     }
11701     free(ndate);
11702     if (match)
11703         return (UTL_MATCH);
11704     else
11705         return (UTL_NOMATCH);
11706 }
11707 /* UTL_TimeMatch
11708 **      Match a time range as specified in the Dicom standard
11709 */
11710 CONDITION
11711 UTL_TimeMatch(char *timestring, char *stm)
11712 {
11713 
11714     int
11715         match;
11716     char
11717        *ntime;
11718     double
11719         start_time,
11720         end_time,
11721         time_in_question;
11722 
11723     if ((ntime = (char *) malloc(strlen(timestring) + 2)) == (char *) NULL)
11724         return (UTL_NOMATCH);
11725 
11726     strcpy(ntime, timestring);
11727     UTL_SqueezeBlanks(ntime);
11728     UTL_SqueezeBlanks(stm);
11729 
11730     match = 0;
11731     if (strchr(ntime, (int) '-') == (char *) NULL) {
11732         if (strcmp(ntime, stm) == 0)
11733             match = 1;
11734     } else {
11735         time_in_question = UTL_ConvertTimetoFloat(stm);
11736         if (ntime[0] == '-') {
11737             end_time = UTL_ConvertTimetoFloat(ntime + 1);
11738             if (time_in_question <= end_time)
11739                 match = 1;
11740         } else if (ntime[strlen(ntime) - 1] == '-') {
11741             start_time = UTL_ConvertTimetoFloat(ntime);
11742             if (time_in_question >= start_time)
11743                 match = 1;
11744         } else {
11745             start_time = UTL_ConvertTimetoFloat(ntime);
11746             end_time = UTL_ConvertTimetoFloat(strchr(ntime, (int) '-') + 1);
11747             if ((time_in_question >= start_time) &&
11748                 (time_in_question <= end_time))
11749                 match = 1;
11750         }
11751     }
11752     free(ntime);
11753     if (match)
11754         return (UTL_MATCH);
11755     else
11756         return (UTL_NOMATCH);
11757 }
11758 /*
11759 ** UTL_GetDicomDate
11760 **      Get the current date and store as a Dicom date.
11761 */
11762 void
11763 UTL_GetDicomDate(char *datestr)
11764 {
11765 
11766     struct tm
11767        *tf;
11768     time_t
11769         loctime;
11770 
11771     loctime = time((time_t *) NULL);
11772     tf = localtime(&loctime);
11773 
11774     sprintf(datestr, "%04d%02d%02d", (tf->tm_year) + 1900, (tf->tm_mon) + 1, tf->tm_mday);
11775     return;
11776 
11777 }
11778 /*
11779 ** UTL_GetDicomTime
11780 **      Get the current time and store as a Dicom time.
11781 */
11782 void
11783 UTL_GetDicomTime(char *timestr)
11784 {
11785 
11786     struct tm
11787        *tf;
11788     time_t
11789         loctime;
11790 
11791     loctime = time((time_t *) NULL);
11792     tf = localtime(&loctime);
11793 
11794     sprintf(timestr, "%02d%02d%02d.%06d", (tf->tm_hour), (tf->tm_min), (tf->tm_sec), 0);
11795     return;
11796 }
11797 
11798 #ifdef _MSC_VER
11799 typedef struct {
11800     char key[10];
11801     struct _timeb t;
11802 }   UTL_TIMESTRUCTURE;
11803 #else
11804 typedef struct {
11805     char key[10];
11806     struct timeval t;
11807 }   UTL_TIMESTRUCTURE;
11808 #endif
11809 
11810 void *
11811 UTL_GetTimeStamp()
11812 {
11813     UTL_TIMESTRUCTURE *t;
11814 
11815     t = AFMALL( UTL_TIMESTRUCTURE, sizeof(*t));
11816     if (t == NULL)
11817         return NULL;
11818 
11819     strcpy(t->key, "UTL STAMP");
11820 
11821     gettimeofday(&t->t, NULL);
11822 
11823     return t;
11824 }
11825 
11826 double
11827 UTL_DeltaTime(void *timeStamp)
11828 {
11829     struct timeval timeNow;
11830     UTL_TIMESTRUCTURE *t;
11831     double delta = 0.;
11832 
11833     gettimeofday(&timeNow, NULL);
11834 
11835     t = (UTL_TIMESTRUCTURE *) timeStamp;
11836     if (t == NULL)
11837         return -1.0;
11838 
11839     if (strcmp(t->key, "UTL STAMP") != 0)
11840         return -1.0;
11841 
11842     delta = timeNow.tv_sec - t->t.tv_sec;
11843     delta += (timeNow.tv_usec - t->t.tv_usec) / 1000000.;
11844 
11845     return delta;
11846 }
11847 
11848 void
11849 UTL_ReleaseTimeStamp(void *timeStamp)
11850 {
11851     UTL_TIMESTRUCTURE *t;
11852 
11853     t = (UTL_TIMESTRUCTURE *) timeStamp;
11854     if (t == NULL)
11855         return;
11856 
11857     if (strcmp(t->key, "UTL STAMP") != 0)
11858         return;
11859 
11860     free(timeStamp);
11861 }
11862 
11863 CONDITION
11864 UTL_VerifyCreatePath(const char *path)
11865 {
11866     int i;
11867 #ifdef _MSC_VER
11868     struct _stat buf;
11869 #else
11870     struct stat buf;
11871 #endif
11872     char
11873        *p,
11874         temp[1024];
11875     int flag = 0;
11876     static int statCount = 0;
11877 
11878 #ifdef _MSC_VER
11879     statCount++;
11880     i = _stat(path, &buf);
11881 #else
11882     i = stat(path, &buf);
11883 #endif
11884 
11885 
11886     if (i == 0) {
11887 #ifdef _MSC_VER
11888         flag = ((buf.st_mode & _S_IFDIR) != 0);
11889 #else
11890         flag = (S_ISDIR(buf.st_mode));
11891 #endif
11892         if (flag)
11893             return UTL_NORMAL;
11894         else
11895             return UTL_PATHNOTDIR;
11896     }
11897     p = temp;
11898 
11899     while (*path != '\0') {
11900         *p++ = *path++;
11901         while (*path != '/' && *path != '\\' && *path != '\0') {
11902 #ifdef _MSC_VER
11903             if (*path == ':') {
11904                 *p++ = *path++;
11905                 if (*path == '\0')      /* We should not get C:\0, but test
11906                                          * it */
11907                     break;
11908             }
11909 #endif
11910             *p++ = *path++;
11911         }
11912 
11913         *p = '\0';
11914 #ifdef _MSC_VER
11915         statCount++;
11916         i = _stat(temp, &buf);
11917 #else
11918         i = stat(temp, &buf);
11919 #endif
11920 
11921         if (i == 0) {
11922 #ifdef _MSC_VER
11923             flag = ((buf.st_mode & _S_IFDIR) != 0);
11924 #else
11925             flag = (S_ISDIR(buf.st_mode));
11926 #endif
11927             if (!flag)
11928                 return UTL_PATHNOTDIR;
11929         } else {
11930 #ifdef _MSC_VER
11931             int e1;
11932             e1 = errno;
11933             memset(&buf, 0, sizeof(buf));
11934             /*fprintf(stderr, "Stat Count = %d\n", statCount);*/
11935             statCount++;
11936             i = _stat(temp, &buf);
11937             e1 = errno;
11938             i = _mkdir(temp);
11939 #else
11940             i = mkdir(temp, 0777);
11941 #endif
11942             if (i != 0) {
11943                 int e1;
11944                 e1 = errno;
11945                 fprintf(stderr, "Stat Count = %d\n", statCount);
11946                 perror(temp);
11947                 return UTL_FILECREATEFAILED;
11948             }
11949         }
11950     }
11951     return UTL_NORMAL;
11952 }
11953 
11954 CTNBOOLEAN UTL_IsDirectory(const char* path)
11955 {
11956     int i;
11957 #ifdef _MSC_VER
11958     struct _stat buf;
11959 #else
11960     struct stat buf;
11961 #endif
11962 
11963     int flag = 0;
11964 
11965 #ifdef _MSC_VER
11966     i = _stat(path, &buf);
11967 #else
11968     i = stat(path, &buf);
11969 #endif
11970 
11971 
11972     if (i == 0) {
11973 #ifdef _MSC_VER
11974         flag = ((buf.st_mode & _S_IFDIR) != 0);
11975 #else
11976         flag = (S_ISDIR(buf.st_mode));
11977 #endif
11978         if (flag)
11979             return TRUE;
11980     }
11981     return FALSE;
11982 }
11983 
11984 
11985 #if 0
11986 CONDITION UTL_ScanDirectory(const char* path,
11987                             LST_HEAD** lst)
11988 {
11989   UTL_FILEITEM* item = 0;
11990 
11991 #ifdef _WIN32
11992   long hFile = 0;
11993   struct _finddata_t fileInfo;
11994   char directoryText[1024];
11995   *lst = LST_Create();
11996   strcpy(directoryText, path);
11997   strcat(directoryText, "/*");
11998   if( (hFile = _findfirst(directoryText, &fileInfo)) == -1L)
11999     return 0;
12000 
12001   item = malloc(sizeof(*item));
12002   strcpy(item->path, fileInfo.name);
12003   LST_Enqueue(lst, item);
12004 
12005   while(_findnext(hFile, &fileInfo) == 0) {
12006     item = malloc(sizeof(*item));
12007     strcpy(item->path, fileInfo.name);
12008     LST_Enqueue(lst, item);
12009   }
12010   _findclose(hFile);
12011 
12012 #else
12013   DIR* dirp;
12014   struct dirent* dp;
12015 
12016   *lst = LST_Create();
12017   dirp = opendir(path);
12018   if (dirp == 0)
12019     return 0;
12020 
12021   while ((dp = readdir(dirp)) != NULL) {
12022     item = malloc(sizeof(*item));
12023     strcpy(item->path, dp->d_name);
12024     LST_Enqueue(lst, (void *)item);
12025   }
12026   closedir(dirp);
12027 #endif
12028 
12029   return UTL_NORMAL;
12030 }
12031 #endif
12032 
12033 static char* UTL_configFile = 0;
12034 static LST_HEAD* UTL_configList = 0;
12035 typedef struct {
12036   void* reserved[2];
12037   char *pName;
12038   char *pValue;
12039 } CONFIG_ITEM;
12040 
12041 CONDITION UTL_ReadConfigFile( )
12042 {
12043   FILE* f;
12044   char buf[1024];
12045 
12046   if (UTL_configList != 0)
12047     return UTL_NORMAL;
12048 
12049   UTL_configList = LST_Create();
12050   if (UTL_configList == NULL)
12051     return 0;
12052 
12053   if (UTL_configFile == 0)
12054     return UTL_NORMAL;
12055 
12056   if (UTL_configFile[0] == '\0')
12057     return UTL_NORMAL;
12058 
12059   f = fopen(UTL_configFile, "r");
12060   if (f == NULL)
12061     return 0;
12062 
12063   while (fgets(buf, sizeof(buf), f) != NULL) {
12064     char* token1;
12065     char* token2;
12066     CONFIG_ITEM* item;
12067 
12068     if (buf[0] == '#') continue;
12069     if (buf[0] == '\n') continue;
12070     token1 = strtok(buf, " \t\n");
12071     token2 = strtok(0, " \t\n");
12072     if (token2 == NULL) continue;
12073 
12074     item = (CONFIG_ITEM*)malloc(sizeof(*item) + strlen(token1) +
12075                                 strlen(token2) + 2);
12076     item->pName = ((char*)item) + sizeof(*item);
12077     strcpy(item->pName, token1);
12078     item->pValue = item->pName + strlen(token1) + 1;
12079     strcpy(item->pValue, token2);
12080 
12081     LST_Enqueue(&UTL_configList, (void *)item);
12082   }
12083 
12084   fclose(f);
12085 
12086   return UTL_NORMAL;
12087 }
12088 
12089 CONDITION UTL_SetConfigFile(const char* configFile)
12090 {
12091   if (UTL_configFile != 0) {
12092     CTN_FREE(UTL_configFile);
12093   }
12094 
12095   if (configFile == 0 || configFile[0] == '\0') {
12096     char* p = getenv("CTN_TARGET");
12097     if (p == NULL) {
12098       return UTL_NO_CTN_TARGET;
12099     }
12100     UTL_configFile = (char*) malloc(strlen(p) + strlen("/runtime/ctn_cfg.txt") + 1);
12101     strcpy(UTL_configFile, p);
12102     strcat(UTL_configFile, "/runtime/ctn_cfg.txt");
12103   } else {
12104     UTL_configFile = (char*) malloc(strlen(configFile)+1);
12105     strcpy(UTL_configFile, configFile);
12106   }
12107 
12108   return UTL_NORMAL;
12109 }
12110 
12111 CONDITION UTL_TestConfigFile(const char* configFile)
12112 {
12113   return UTL_NORMAL;
12114 }
12115 char* UTL_GetConfigParameter(const char* paramName)
12116 {
12117   CONDITION cond;
12118   char nameCopy[256];
12119   CONFIG_ITEM* item;
12120   int idx;
12121 
12122   cond = UTL_ReadConfigFile( );
12123   if (cond != UTL_NORMAL)
12124     return NULL;
12125 
12126   item = (void *)LST_Head(&UTL_configList);
12127   if (item == NULL)
12128     return NULL;
12129 
12130   (void) LST_Position(&UTL_configList, (void *)item);
12131   while(item != NULL) {
12132     if (strcmp(item->pName, paramName) == 0)
12133       return item->pValue;
12134 
12135     item = (void *)LST_Next(&UTL_configList);
12136   }
12137 
12138   strcpy(nameCopy, paramName);
12139   idx = strlen(nameCopy) - 1;
12140   while (idx > 0) {
12141     if (nameCopy[idx] == '/') {
12142       nameCopy[idx] = '\0';
12143       idx = -1;
12144       break;
12145     } else {
12146       idx--;
12147     }
12148   }
12149 
12150   if (idx < 0) {
12151     return UTL_GetConfigParameter(nameCopy);
12152   } else {
12153     return NULL;
12154   }
12155 }
12156 
12157 char**
12158 UTL_ExpandToPointerArray(const char* inputText,
12159                          const char* delimiters,
12160                          int* numberOfEntries)
12161 {
12162   int idx;
12163   int memorySize = 0;
12164   int arrayIndex = 0;
12165   char** array;
12166   char* outputPtr;
12167   char* token;
12168 
12169   *numberOfEntries = 1;
12170   for (idx = 0; inputText[idx] != '\0'; idx++) {
12171     int j;
12172     for (j = 0; delimiters[j] != '\0'; j++) {
12173       if (inputText[idx] == delimiters[j]) {
12174         (*numberOfEntries)++;
12175         break;
12176       }
12177     }
12178   }
12179 
12180   memorySize = (sizeof(char*)) * (*numberOfEntries);
12181   memorySize += strlen(inputText) + 1;
12182 
12183   array = (char**)CTN_MALLOC(memorySize);
12184   outputPtr = ((char*) array) + ((sizeof(char*)) * (*numberOfEntries));
12185   strcpy(outputPtr, inputText);
12186 
12187   token = strtok(outputPtr, delimiters);
12188   while(token != NULL) {
12189     array[arrayIndex++] = token;
12190     token = strtok(NULL, delimiters);
12191   }
12192 
12193   return array;
12194 }
12195 
12196 CTNBOOLEAN UTL_IsFile(const char* path)
12197 {
12198   int i;
12199   CTNBOOLEAN rtnValue = FALSE;
12200 
12201 #ifdef _WIN32
12202   struct _stat buf;
12203 
12204   i = _stat(path, &buf);
12205   if (i == 0) {
12206     rtnValue = ((buf.st_mode & _S_IFREG) != 0);
12207   }
12208 #else
12209   struct stat buf;
12210   i = stat(path, &buf);
12211   if (i == 0) {
12212     rtnValue = (S_ISREG(buf.st_mode));
12213   }
12214 #endif
12215 
12216   return rtnValue;
12217 }
12218 
12219 CONDITION UTL_DeleteFile(const char* path)
12220 {
12221   int i = 0;
12222 
12223   i = unlink(path);
12224 
12225   if (i == 0)
12226     return UTL_NORMAL;
12227 
12228   return COND_PushCondition(UTL_DELETEFILEFAILED, "");
12229 }
12230 
12231 
12232 CONDITION
12233 UTL_FileSize(const char* path, U32* size)
12234 {
12235   int status;
12236   struct stat im_stat;
12237 
12238   status = stat(path, &im_stat);
12239   if (status < 0) {
12240     *size = 0;
12241     return 0;
12242   } else {
12243     *size = im_stat.st_size;
12244     return UTL_NORMAL;
12245   }
12246 }
12247 
12248 
12249 /* DCM_ExportStream
12250 **
12251 ** Purpose:
12252 **      Export a DICOM object into the stream format suitable
12253 **      for network transmission or disk storage.
12254 **
12255 ** Parameter Dictionary:
12256 **      object          Pointer to caller's DICOM object
12257 **      opt             Bitmask giving options for exporting data.  Legal
12258 **                      options give the byte order of exported data:
12259 **                              DCM_ORDERNATIVE
12260 **                              DCM_ORDERLITTLEENDIAN
12261 **                              DCM_ORDERBIGENDIAN
12262 **      buffer          Pointer to caller's buffer to hold next slug
12263 **                      of DCM stream data.
12264 **      bufferlength    Length of caller's buffer to hold stream data.
12265 **      returnlength    Pointer to caller's variable into which we write
12266 **                      the amount of data exported.
12267 **      ctx             Pointer to context variable we maintain to keep
12268 **                      track of our location in export process.
12269 **
12270 ** Return Values:
12271 **
12272 **      DCM_FILEACCESSERROR
12273 **      DCM_ILLEGALOBJECT
12274 **      DCM_LISTFAILURE
12275 **      DCM_NORMAL
12276 **      DCM_NULLOBJECT
12277 **
12278 ** Algorithm:
12279 **      Description of the algorithm (optional) and any other notes.
12280 */
12281 
12282 CONDITION
12283 DCM_ExportStream(DCM_OBJECT ** callerObject, unsigned long opt,
12284                  void *buffer, unsigned long bufferlength,
12285                  DCM_EXPORT_STREAM_CALLBACK* callback,
12286                  void *ctx)
12287 {
12288 
12289 
12290     PRIVATE_OBJECT
12291         ** object;
12292     CONDITION
12293         cond;
12294 
12295     object = (PRIVATE_OBJECT **) callerObject;
12296     cond = checkObject(object, "DCM_ExportStream");
12297     if (cond != DCM_NORMAL)
12298         return cond;
12299 
12300     return exportStream(callerObject, opt, buffer, bufferlength, callback,
12301                         ctx, 0);
12302 }
 

Powered by Plone

This site conforms to the following standards: