TPCCLIB
Loading...
Searching...
No Matches
dcm.c File Reference

IO functions for DICOM files. More...

#include "libtpcimgio.h"

Go to the source code of this file.

Functions

int dcmVerifyMagic (const char *filename, FILE *fp)
unsigned char dcmVRReserved (dcmvr id)
dcmvr dcmVRId (const char *s)
char * dcmVRName (dcmvr id)
size_t dcmVRVLength (dcmvr id)
char * dcmVRDescr (dcmvr id)
char * dcmDA2intl (const char *orig, char *intl)
char * dcmTM2intl (const char *orig, char *intl)
char * dcmDT2intl (const char *orig, char *intl)
unsigned int dcmSOPIdentify (const char *s)
char * dcmSOPName (unsigned int i)
char * dcmSOPUID (unsigned int i)
char * dcmSOPUIDName (const char *s)
dcmtruid dcmTrUID (const char *s)
char * dcmTrUIDDescr (dcmtruid id)
char * dcmTrUIDString (dcmtruid id)
dcmtruid dcmReadTransferSyntaxUID (FILE *fp)
int dcmReadFileTag (FILE *fp, DCMTAG *tag)
int dcmWriteFileTag (FILE *fp, DCMTAG *tag)
int dcmWriteFileSQDelimItem (FILE *fp)
int dcmWriteFileSQItemDelimTag (FILE *fp)
dcmvr dcmReadFileVR (FILE *fp, char *vrstr)
unsigned int dcmReadFileVL (FILE *fp, unsigned int n)
int dcmReadFileVRVL (FILE *fp, dcmvr *vr, unsigned int *vl, unsigned int *n)
int dcmWriteFileVRVL (FILE *fp, dcmvr vr, unsigned int vl, unsigned int *n)
void dcmfileInit (DCMFILE *d)
void dcmitemFree (DCMITEM *d)
void dcmfileFree (DCMFILE *d)
unsigned short int dcmitemMaxDepth (DCMITEM *d)
unsigned short int dcmfileMaxDepth (DCMFILE *df)
unsigned short int dcmitemParentNr (DCMITEM *d)
char * dcmValueString (DCMITEM *d)
long int dcmitemGetInt (DCMITEM *d)
double dcmitemGetReal (DCMITEM *d)
DCMITEMdcmFindTag (DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
void dcmitemPrint (DCMITEM *d)
void dcmTagSet (DCMTAG *tag, unsigned short int group, unsigned short int element)
int dcmAddItem (DCMFILE *dcm, DCMITEM *d, short int aschild, DCMTAG tag, dcmvr vr, unsigned int vl, char *rd, const int verbose)
int dcmFileReadNextElement (DCMFILE *dcm, DCMITEM *prev_item, DCMITEM *parent_item, const short int sub, const short int headerOnly, int verbose)
int dcmFileRead (const char *filename, DCMFILE *dcm, const short int headerOnly, int verbose)
int dcmFileWrite (const char *filename, DCMFILE *dcm, int verbose)

Detailed Description

IO functions for DICOM files.

Definition in file dcm.c.

Function Documentation

◆ dcmAddItem()

int dcmAddItem ( DCMFILE * dcm,
DCMITEM * d,
short int aschild,
DCMTAG tag,
dcmvr vr,
unsigned int vl,
char * rd,
const int verbose )

Add an item to DCMFILE data struct.

See also
dcmfileInit, dcmfileFree
Returns
0 if successful, otherwise >0.
Parameters
dcmPointer to DCMFILE.
dPointer to a previous item in DCMFILE, into which to link this item; enter NULL to add as next item to the highest level.
aschildAdd as child; 1=yes, 0=no.
tagTag
vrVR
vlVL; enter 0xFFFFFFFF to use VR's default length.
rdPointer to the item value as byte array
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 1239 of file dcm.c.

1257 {
1258 if(verbose>0) {
1259 printf("%s(dcm, (%04X,%04X))", __func__, tag.group, tag.element);
1260 if(d==NULL) printf(", null"); else printf(", ptr");
1261 printf(", %d, %s, 0x%08X, rd", aschild, dcmVRName(vr), vl);
1262 printf(")\n");
1263 }
1264 if(dcm==NULL) return(1);
1265 if(vr==DCM_VR_INVALID) return(2);
1266
1267 /* Check that caller has not given previous item pointer when there are none in DCMFILE */
1268 if(d!=NULL && dcm->item==NULL) return(3);
1269 /* Check that caller has not given previous item pointer that already has child */
1270 if(d!=NULL && aschild && d->child_item!=NULL) return(4);
1271
1272 /* Check whether we currently support the Transfer UID */
1273 if(dcm->truid!=DCM_TRUID_LEE) return(5);
1274
1275 /* Allocate memory for the new element; do not free it here, since it will be part of
1276 DCMFILE struct. */
1277 if(verbose>1) printf(" allocating memory for the item\n");
1278 DCMITEM *item=(DCMITEM*)malloc(sizeof(DCMITEM));
1279 if(item==NULL) return(11);
1280 item->next_item=item->child_item=(DCMITEM*)NULL;
1281 item->fp=dcm->fp; item->truid=dcm->truid;
1282 item->rd=(char*)NULL;
1283
1284 /* Set item tag, VR, and VL */
1285 if(verbose>1) printf(" setting item contents\n");
1286 item->tag.group=tag.group;
1287 item->tag.element=tag.element;
1288 item->vr=vr;
1289 item->vl=vl;
1290 /* Allocate memory for item value */
1291 size_t s;
1292 if(vl==0xFFFFFFFF) s=dcmVRVLength(vr); else s=vl;
1293 if(s>0) {
1294 if(item->vl==0xFFFFFFFF) item->vl=(unsigned int)s;
1295 if(verbose>1) printf(" allocating %u bytes for the item value\n", (unsigned int)s);
1296 item->rd=(char*)calloc(s, sizeof(char));
1297 if(item->rd==NULL) {free(item); return(21);}
1298 } else {
1299 if(verbose>1) printf("zero size for item value\n");
1300 if(rd==NULL) {
1301 if(verbose>1) printf("... which is ok since value is empty, too.\n");
1302 } else {
1303 if(verbose>0) printf("... which is not ok because we have value to store.\n");
1304 if(item->rd==NULL) {free(item); return(22);}
1305 }
1306 }
1307 /* Copy the item value */
1308 if(rd!=NULL && s>0) {
1309 if(verbose>1) printf(" copying the item value\n");
1310 /* Special treatment for strings, because those tend to be shorter than told */
1311 if(vr==DCM_VR_LO || vr==DCM_VR_LT || vr==DCM_VR_PN || vr==DCM_VR_SH || vr==DCM_VR_UI || vr==DCM_VR_UR)
1312 {
1313 unsigned int len=strnlen(rd, s);
1314 if(len<s) strlcpy(item->rd, rd, s);
1315 else memcpy(item->rd, rd, s);
1316 } else if(vr==DCM_VR_DS || vr==DCM_VR_IS)
1317 {
1318 unsigned int len=strnlen(rd, s);
1319 if(len<s) strlcpy(item->rd, rd, s);
1320 else memcpy(item->rd, rd, s);
1321 } else {
1322 memcpy(item->rd, rd, s);
1323 }
1324 }
1325
1326
1327 /* If we have the item to link to, then do the linking */
1328 if(verbose>1) printf(" link the item.\n");
1329 if(d!=NULL) {
1330 if(aschild) {
1331 d->child_item=item;
1332 item->parent_item=d;
1333 item->prev_item=(DCMITEM*)NULL;
1334 } else if(d->next_item==NULL) {
1335 d->next_item=item;
1336 item->prev_item=d;
1337 item->parent_item=d->parent_item;
1338 } else {
1339 /* find the last item in the list */
1340 DCMITEM *ip=d; while(ip->next_item!=NULL) ip=ip->next_item;
1341 ip->next_item=item;
1342 item->prev_item=ip;
1343 item->parent_item=ip->parent_item;
1344 }
1345 } else if(dcm->item==NULL) {
1346 /* This is truly the first item ever */
1347 dcm->item=item;
1348 item->prev_item=item->parent_item=(DCMITEM*)NULL;
1349 } else {
1350 /* Caller lets us find the item to link to */
1351 DCMITEM *ip=dcm->item; while(ip->next_item!=NULL) ip=ip->next_item;
1352 ip->next_item=item;
1353 item->prev_item=ip;
1354 item->parent_item=ip->parent_item;
1355 }
1356
1357 if(verbose>2) dcmitemPrint(item);
1358
1359 if(verbose>1) printf(" all done.\n");
1360 return(0);
1361}
size_t dcmVRVLength(dcmvr id)
Definition dcm.c:264
char * dcmVRName(dcmvr id)
Definition dcm.c:246
void dcmitemPrint(DCMITEM *d)
Definition dcm.c:1205
@ DCM_VR_INVALID
Invalid DICOM value representation.
@ DCM_VR_UI
DICOM unique identifier (UID), max 64 bytes.
@ DCM_VR_PN
DICOM person name, max 64 chars per component group.
@ DCM_VR_SH
DICOM short string, max 16 chars.
@ DCM_VR_LT
DICOM long text, max 10240 chars.
@ DCM_VR_DS
DICOM decimal string, max 16 bytes.
@ DCM_VR_IS
DICOM integer string, max 12 bytes.
@ DCM_VR_UR
DICOM URI or URL, string of characters.
@ DCM_VR_LO
DICOM long string, max 64 chars.
@ DCM_TRUID_LEE
Little Endian Explicit VR.
size_t strnlen(const char *s, size_t n)
Definition strext.c:181
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition strext.c:245
dcmtruid truid
DCMITEM * item
FILE * fp
dcmtruid truid
struct DCMITEM * child_item
struct DCMITEM * next_item
unsigned int vl
FILE * fp
char * rd
struct DCMITEM * prev_item
struct DCMITEM * parent_item
DCMTAG tag
unsigned short int element
unsigned short int group

◆ dcmDA2intl()

char * dcmDA2intl ( const char * orig,
char * intl )

Convert DICOM date 'DA' to international format YYYY-MM-DD.

Returns
Returns pointer to the date string, or NULL in case of an error.
Parameters
origPointer to original DICOM string.
intlPointer to string where date in international format will be written; must be allocated for at least 11 characters.

Definition at line 299 of file dcm.c.

305 {
306 if(orig==NULL || intl==NULL) return(NULL);
307 if(strnlen(orig, 10)<8) return(NULL);
308 if(isdigit(orig[4])) { // modern format YYYYMMDD
309 sprintf(intl, "%4.4s-%2.2s-%2.2s", orig, orig+4, orig+6);
310 } else { // old format YYYY.MM.DD
311 sprintf(intl, "%4.4s-%2.2s-%2.2s", orig, orig+5, orig+8);
312 }
313 if(isdate(intl)) {intl[0]=(char)0; return(NULL);}
314 return(intl);
315}
int isdate(char *str)
Definition datetime.c:146

◆ dcmDT2intl()

char * dcmDT2intl ( const char * orig,
char * intl )

Convert DICOM datetime 'DT' to international format YYYY-MM-DD hh:mm:ss.

Returns
Returns pointer to the time string, or NULL in case of an error.
Parameters
origPointer to original DICOM string. Should be in format YYYYMMDDhhmmss.FFFFFF+hhmm
intlPointer to string where date and time in international format will be written; must be allocated for at least 20 characters.

Definition at line 345 of file dcm.c.

352 {
353 if(orig==NULL || intl==NULL) return(NULL);
354 if(strnlen(orig, 26)<14) return(NULL);
355 sprintf(intl, "%4.4s-%2.2s-%2.2s %2.2s:%2.2s:%2.2s",
356 orig, orig+4, orig+6, orig+8, orig+10, orig+12);
357 if(isdatetime(intl, NULL)) {intl[0]=(char)0; return(NULL);}
358 return(intl);
359}
int isdatetime(char *str, char *intdate)
Definition datetime.c:280

◆ dcmfileFree()

void dcmfileFree ( DCMFILE * d)

Free memory allocated for DCMFILE data. All contents are destroyed.

Precondition
Before first use initialize the struct with dcmfileInit().
See also
dcmfileInit
Author
Vesa Oikonen
Parameters
dPointer to DCMFILE.

Definition at line 868 of file dcm.c.

871 {
872 if(d==NULL) return;
873 dcmitemFree(d->item);
874 dcmfileInit(d);
875}
void dcmfileInit(DCMFILE *d)
Definition dcm.c:823
void dcmitemFree(DCMITEM *d)
Definition dcm.c:840

Referenced by dcmFileRead().

◆ dcmfileInit()

void dcmfileInit ( DCMFILE * d)

Initiate the DCMFILE struct before any use.

See also
dcmfileFree
Parameters
dPointer to DCMFILE.

Definition at line 823 of file dcm.c.

826 {
827 if(d==NULL) return;
828 d->filename[0]=(char)0;
829 d->fp=(FILE*)NULL;
831 d->item=(DCMITEM*)NULL;
832}
@ DCM_TRUID_UNKNOWN
Unknown Transfer Syntax UID.
char filename[FILENAME_MAX]

Referenced by dcmfileFree().

◆ dcmfileMaxDepth()

unsigned short int dcmfileMaxDepth ( DCMFILE * df)

Get the maximum depth of DCMFILE items tree.

Returns
Returns the number of item levels under specified DCMFILE, or zero in case of an error or if there are no items.
See also
dcmitemParentNr, dcmitemMaxDepth
Parameters
dfPointer to DCMFILE item.

Definition at line 903 of file dcm.c.

906 {
907 if(df==NULL || df->item==NULL) return(0);
908 unsigned short int m=0, n=0;
909 DCMITEM *sd=df->item;
910 while(sd!=NULL) { // go through all sisters
911 n=dcmitemMaxDepth(sd); if(n>m) m=n;
912 sd=sd->next_item;
913 }
914 return(m+1);
915}
unsigned short int dcmitemMaxDepth(DCMITEM *d)
Definition dcm.c:884

◆ dcmFileRead()

int dcmFileRead ( const char * filename,
DCMFILE * dcm,
const short int headerOnly,
int verbose )

Read a single DICOM file.

See also
dcmVerifyMagic, dcmfileInit, dcmfileFree, dcmReadTransferSyntaxUID, dcmFileWrite
Returns
0 when successful.
Parameters
filenamePointer to filename.
dcmPointer to initiated data structure.
headerOnlyRead only header (1), or read both header and pixel data (0).
verboseVerbose level; if zero, then nothing is printed into stdout or stderr

Definition at line 1687 of file dcm.c.

1696 {
1697 if(filename==NULL || strnlen(filename, 10)<1 || dcm==NULL) return(1);
1698 if(verbose>1) printf("%s('%s', %d)\n", __func__, filename, headerOnly);
1699
1700 /* Delete any previous data */
1701 dcmfileFree(dcm);
1702
1703 /* Open the file */
1704 strlcpy(dcm->filename, filename, FILENAME_MAX);
1705 dcm->fp=fopen(dcm->filename, "rb");
1706 if(dcm->fp==NULL) {
1707 return(2);
1708 }
1709
1710 /* Check the magic number and move file pointer to the end of it */
1711 if(verbose>2) printf("checking DICOM magic number\n");
1712 if(dcmVerifyMagic(NULL, dcm->fp)!=1) {
1713 fclose(dcm->fp);
1714 return(2);
1715 }
1716
1717 /* Get the Transfer Syntax UID */
1718 if(verbose>2) printf("checking Transfer Syntax UID\n");
1720 if(dcm->truid==DCM_TRUID_INVALID) { // not found
1721 fclose(dcm->fp);
1722 return(2);
1723 }
1724 if(verbose>0) { // print the UID
1725 printf("Transfer Syntax UID := %s\n", dcmTrUIDDescr(dcm->truid));
1726 fflush(stdout);
1727 }
1728
1729 /* Check whether we currently support the Transfer UID */
1730 if(dcm->truid!=DCM_TRUID_LEE) {
1731 fclose(dcm->fp);
1732 return(2);
1733 }
1734
1735 /* Read DICOM file elements */
1736 int ret=0;
1737 do {
1738 // note that the next function may need to call itself,
1739 // therefore counting loops here would not be useful.
1740 ret=dcmFileReadNextElement(dcm, NULL, NULL, 0, headerOnly, verbose-10);
1741 } while(ret==0 && !feof(dcm->fp));
1742 fclose(dcm->fp);
1743 /* TPCERROR_NO_KEY means that no (more) tag was found;
1744 other codes still mean that something bad happened. */
1745 if(ret==-1) {
1746 if(verbose>1) printf(" eof\n");
1747 ret=0;
1748 }
1749 return(ret);
1750}
dcmtruid dcmReadTransferSyntaxUID(FILE *fp)
Definition dcm.c:502
char * dcmTrUIDDescr(dcmtruid id)
Definition dcm.c:466
void dcmfileFree(DCMFILE *d)
Definition dcm.c:868
int dcmFileReadNextElement(DCMFILE *dcm, DCMITEM *prev_item, DCMITEM *parent_item, const short int sub, const short int headerOnly, int verbose)
Definition dcm.c:1370
int dcmVerifyMagic(const char *filename, FILE *fp)
Definition dcm.c:157
@ DCM_TRUID_INVALID
Invalid Transfer Syntax UID.

◆ dcmFileReadNextElement()

int dcmFileReadNextElement ( DCMFILE * dcm,
DCMITEM * prev_item,
DCMITEM * parent_item,
const short int sub,
const short int headerOnly,
int verbose )

Read an element from DICOM file, and add it to the given linked list. This function will be called recursively in case of sequential items.

Returns
0 when successful, >0 in case of an error, -1 when no more elements could be read.
See also
dcmFileRead
Parameters
dcmPointer to DCMFILE struct; must be initiated before first call.
prev_itemPointer to previous element; NULL if none exists (yet).
parent_itemPointer to parent element; NULL if none exists (yet).
subAdd as next element (0) or as child element.
headerOnlyRead only header (1), or read both header and pixel data (0).
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 1370 of file dcm.c.

1383 {
1384 if(verbose>0) printf("%s(DCMFILE*, DCMITEM*, DCMITEM*, %d, %d)\n", __func__, sub, headerOnly);
1385 if(dcm==NULL || dcm->fp==NULL) return(1);
1386 if(sub!=0 && parent_item==NULL) return(1);
1387 if(feof(dcm->fp)) return(-1);
1388
1389 /* Check whether we currently support the Transfer UID */
1390 if(dcm->truid!=DCM_TRUID_LEE) return(2);
1391
1392 if(verbose>10) {
1393 if(dcm->item==NULL) printf(" will add first element\n");
1394 else if(sub==0) printf(" will add next element\n");
1395 else printf(" will add subelement\n");
1396 }
1397
1398 /* Is this a child to a sequence element? */
1399 int sq_child=0;
1400 if(parent_item!=NULL && parent_item->vr==DCM_VR_SQ) {sq_child=1;}
1401 if(verbose>10 && sq_child!=0) printf(" we're a child to a sequence element\n");
1402
1403 /* Allocate memory for the new element */
1404 DCMITEM *item=(DCMITEM*)malloc(sizeof(DCMITEM));
1405 if(item==NULL) return(4);
1406 item->prev_item=prev_item;
1407 item->parent_item=parent_item;
1408 item->next_item=item->child_item=(DCMITEM*)NULL;
1409 item->fp=dcm->fp; item->truid=dcm->truid;
1410 item->rd=(char*)NULL;
1411
1412 /* Save current file position (should be the start of element) */
1413 if(fgetpos(dcm->fp, &item->pos)) {
1414 free(item); return(2);
1415 }
1416
1417 /* Read the tag (2x2 bytes) */
1418 if(verbose>10) {
1419 long int tagpos=ftell(dcm->fp);
1420 printf(" reading tag at %ld\n", tagpos);
1421 }
1422 if(dcmReadFileTag(dcm->fp, &item->tag)) {
1423 if(verbose>1 && !feof(dcm->fp)) printf(" error in reading the tag.\n");
1424 free(item);
1425 if(feof(dcm->fp)) return(-1);
1426 return(2);
1427 }
1428
1429 if(verbose>2) {
1430 printf(" tag(%04x,%04x) with %u parents\n",
1431 item->tag.group, item->tag.element, dcmitemParentNr(item));
1432 }
1433
1434 /* If child, then check for item delimitation tag (although it should not be here) */
1435 if(dcmitemParentNr(item)>0 && item->tag.group==0xFFFE && item->tag.element==0xE00D) {
1436 if(verbose>10)
1437 printf(" item delimitation tag(%04x,%04x) found, reading VL\n",
1438 item->tag.group, item->tag.element);
1439 unsigned long int vl=dcmReadFileVL(dcm->fp, 4);
1440 if(verbose>1) printf(" item delimitation tag VL := %lu (0x%08lx)\n", vl, vl);
1441 if(vl!=0) {
1442 if(verbose>1) printf(" error: VL should have been 0\n");
1443 return(3);
1444 }
1445 return(0);
1446 }
1447
1448
1449 /* Read value representation and length (VR and VL, 2x2 or 2x4 bytes) */
1450 {
1451 if(verbose>10) printf(" reading VR and VL\n");
1452 int ret;
1453 unsigned int n;
1454 ret=dcmReadFileVRVL(dcm->fp, &item->vr, &item->vl, &n);
1455 if(ret!=0) {
1456 if(verbose>1) printf(" invalid VR or VL\n");
1457 free(item); return(ret);
1458 }
1459 if(verbose>1) {
1460 printf(" VR := %s (%s)\n", dcmVRName(item->vr), dcmVRDescr(item->vr));
1461 printf(" VL := %u (0x%08x) (%d bytes field)\n", item->vl, item->vl, n/2);
1462 fflush(stdout);
1463 }
1464 }
1465
1466 /* Read value field, and add the current element to the list */
1467 if(item->vr==DCM_VR_SQ) {
1468 if(ftell(dcm->fp)<0) return(2);
1469 unsigned long int sqPos=(unsigned long int)ftell(dcm->fp);
1470 if(verbose>10) {printf(" sequence... at %ld\n", sqPos); fflush(stdout);}
1471 unsigned long int sqContentLength=item->vl;
1472 if(verbose>12) printf(" sequence contents length is %lu\n", sqContentLength);
1473 /* File position is now at the start of first item in the sequence */
1474 int ret;
1475 /* If parent has no previous child, then define this as its child */
1476 if(sq_child!=0 && parent_item->child_item==NULL) {
1477 parent_item->child_item=item;
1478 } else {
1479 /* else, add SQ sequence itself as next element to the list, and later
1480 add each sequence item as child to it */
1481 if(prev_item==NULL) {
1482 if(dcm->item==NULL) { // truly the first item
1483 dcm->item=item;
1484 } else { // search for the previous one
1485 DCMITEM *ip; ip=dcm->item;
1486 while(ip->next_item!=NULL) ip=ip->next_item;
1487 ip->next_item=item; item->prev_item=ip;
1488 }
1489 } else {
1490 prev_item->next_item=item; item->prev_item=prev_item;
1491 }
1492 }
1493 /* Read the first item tag and length, but there is no VR to read this time */
1494 if(verbose>10) {
1495 long int tagpos=ftell(dcm->fp);
1496 printf(" reading first item tag at %ld\n", tagpos);
1497 }
1498 DCMTAG itemtag;
1499 ret=dcmReadFileTag(dcm->fp, &itemtag);
1500 if(ret!=0) {
1501 if(verbose>1) printf(" error %d in reading the tag.\n", ret);
1502 return(2);
1503 }
1504 if(verbose>1) printf(" item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
1505 /* It is common that sequence is empty; check it first */
1506 if(itemtag.group==0xFFFE && (itemtag.element==0xE0DD || itemtag.element==0xE00D)) {
1507 /* yes; then read also the 4 byte LV, which should be zero */
1508 if(verbose>10)
1509 printf(" sequence delimitation item tag(%04x,%04x) found, reading VL\n",
1510 itemtag.group, itemtag.element);
1511 unsigned long int vl=dcmReadFileVL(dcm->fp, 4);
1512 if(verbose>1) printf(" item tag VL := %lu (0x%08lx)\n", vl, vl);
1513 if(vl!=0) {
1514 if(verbose>1) printf(" error: VL should have been 0\n");
1515 return(2);
1516 }
1517 if(verbose>3) printf(" ending sequence before it really started.\n");
1518 return(0);
1519 }
1520 /* If sequence actually contains something, the Item tag must be 0xFFFE,0xE000 */
1521 if(itemtag.group!=0xFFFE || itemtag.element!=0xE000) {
1522 if(verbose>1) printf(" invalid sequence item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
1523 return(2);
1524 }
1525 /* Read past the VL of this item (always 4 bytes) */
1526 unsigned long int itemvl=dcmReadFileVL(dcm->fp, 4);
1527 if(verbose>3) {printf(" item_VL := %lu (0x%08lx)\n", itemvl, itemvl);}
1528 if(ftell(dcm->fp)<0) return(2);
1529 unsigned long int sqItemPos=(unsigned long int)ftell(dcm->fp);
1530 /* Check if that is all of this sequence (probably Siemens) */
1531 if((sqItemPos-sqPos)>=sqContentLength) {
1532 if(verbose>3) printf(" ending sequence since it was found to be empty.\n");
1533 return(0);
1534 }
1535 if(verbose>12) printf(" sequence content start position at %ld\n", sqItemPos);
1536 /* Read the first item value as its own element, adding it as child to SQ */
1537 ret=dcmFileReadNextElement(dcm, NULL, item, 1, headerOnly, verbose-1);
1538 if(ret!=0) {
1539 if(verbose>1) printf(" error in reading the first item value dataset\n");
1540 return(ret);
1541 }
1542 /* Now we continue reading more items, until we reach Sequence Delimitation Item */
1543 while(!feof(dcm->fp)) {
1544 /* Do not read pass the length of the sequence data */
1545 if(ftell(dcm->fp)<0) return(2);
1546 unsigned long int cPos=(unsigned long int)ftell(dcm->fp);
1547 if(sqContentLength>0 && (cPos-sqPos)>=sqContentLength) {
1548 if(verbose>3) printf(" we reached the end of sequence VL %lu\n", sqContentLength);
1549 /* set fake sequence delimitation tag */
1550 itemtag.group=0xFFFE; itemtag.element=0xE0DD;
1551 break;
1552 }
1553 if(verbose>10) {
1554 long int tagpos=ftell(dcm->fp);
1555 printf(" reading next sequence item tag at %ld, %ld after start\n", tagpos, tagpos-sqItemPos);
1556 }
1557 if(dcmReadFileTag(dcm->fp, &itemtag)) return(2);
1558 if(verbose>1) printf(" next item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
1559 itemvl=dcmReadFileVL(dcm->fp, 4); // delimitation tag has this too
1560 if(verbose>3) {printf(" item_VL := %lu (0x%08lx)\n", itemvl, itemvl);}
1561 /* Check if we got sequence delimitation tag */
1562 if(itemtag.group==0xFFFE && itemtag.element==0xE0DD)
1563 {
1564 if(verbose>3) printf(" we got sequence delimitation tag\n");
1565 break;
1566 }
1567 /* Check if we got item delimitation tag from the previous item */
1568 if(itemtag.group==0xFFFE && itemtag.element==0xE00D)
1569 {
1570 if(verbose>3) printf(" we got item delimitation tag\n");
1571 if(itemvl!=0) {
1572 if(verbose>1) printf(" error: VL should have been 0\n");
1573 return(3);
1574 }
1575 continue;
1576 }
1577 /* Otherwise this should be sequence item tag */
1578 if(itemtag.group!=0xFFFE || itemtag.element!=0xE000) {
1579 if(verbose>3) printf(" not sequence item tag, move file position back 2x4 bytes\n");
1580 fseek(dcm->fp, -8, SEEK_CUR); //return(TPCERROR_INVALID_VALUE);
1581 }
1582 /* Read the item value as its own element, adding it to the SQ child list */
1583 DCMITEM *child=item->child_item;
1584 if(child==NULL) {
1585 if(verbose>1) printf(" error had happened in adding the child element\n");
1586 return(2);
1587 }
1588 while(child->next_item!=NULL) child=child->next_item;
1589 ret=dcmFileReadNextElement(dcm, child, item, 0, headerOnly, verbose-1);
1590 if(ret!=0) {
1591 if(verbose>1) printf(" error in reading item value dataset\n");
1592 return(ret);
1593 }
1594 }
1595 /* Check that loop really stopped at sequence delimitation item */
1596 /* 0xE00D means the end of item, 0xE0DD the end of sequence. */
1597 if(itemtag.group!=0xFFFE || itemtag.element!=0xE0DD) {
1598 if(verbose>1)
1599 printf(" invalid sequence delimitation item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
1600 return(2);
1601 }
1602 /* Done. Do not free item! */
1603 if(verbose>10) {printf(" end of sequence.\n"); fflush(stdout);}
1604 } else if(item->vl!=0xFFFFFFFF) {
1605 if(verbose>10) {printf(" reading value of %u bytes...\n", item->vl); fflush(stdout);}
1606 char *buf=NULL;
1607 if(item->vl>0) {
1608 buf=(char*)calloc(item->vl+1, sizeof(char));
1609 if(buf==NULL) {free(item); return(4);}
1610 if(fread(buf, 1, item->vl, item->fp)!=item->vl) {
1611 free(item); free(buf); return(3);
1612 }
1613 /* Do not store pixel data, if that was the request */
1614 if(headerOnly!=0 &&
1615 ((item->tag.group==0x7FE0 && item->tag.element>0) || item->tag.group==0x7FE1))
1616 {
1617 if(verbose>5) {printf(" ...not storing pixel data\n"); fflush(stdout);}
1618 free(buf); buf=(char*)NULL;
1619 } else {
1620 item->rd=buf;
1621 }
1622 } else if(verbose>4) {
1623 printf(" VL=0\n");
1624 }
1625 /* Add to list */
1626 if(sub==0) {
1627 if(prev_item==NULL) {
1628 if(dcm->item==NULL) { // truly the first item
1629 dcm->item=item;
1630 } else { // search for the previous one
1631 DCMITEM *ip; ip=dcm->item;
1632 while(ip->next_item!=NULL) ip=ip->next_item;
1633 ip->next_item=item; item->prev_item=ip;
1634 }
1635 } else {
1636 prev_item->next_item=item; item->prev_item=prev_item;
1637 }
1638 } else { // add as child
1639 parent_item->child_item=item; item->parent_item=parent_item;
1640 }
1641 /* Done. Do no free item or buf! */
1642 return(0);
1643
1644 } else { // VL=0xFFFFFFFF
1645 size_t s=dcmVRVLength(item->vr);
1646 if(s==0) {
1647 if(verbose>0) printf(" Unknown VL!!\n");
1648 free(item);
1649 return(3); //return(TPCERROR_OK);
1650 }
1651 if(verbose>4) printf(" VR_based_VL=%u\n", (unsigned int)s);
1652 char *buf=(char*)calloc(s+1, sizeof(char));
1653 if(buf==NULL) {free(item); return(4);}
1654 if(fread(buf, 1, s, item->fp)!=s) {
1655 free(item); free(buf); return(3);
1656 }
1657 item->rd=buf;
1658 /* Add to list */
1659 if(sub==0) {
1660 if(prev_item==NULL) {
1661 if(dcm->item==NULL) { // truly the first item
1662 dcm->item=item;
1663 } else { // search for the previous one
1664 DCMITEM *ip; ip=dcm->item;
1665 while(ip->next_item!=NULL) ip=ip->next_item;
1666 ip->next_item=item; item->prev_item=ip;
1667 }
1668 } else {
1669 prev_item->next_item=item; item->prev_item=prev_item;
1670 }
1671 } else { // add as child
1672 parent_item->child_item=item; item->parent_item=parent_item;
1673 }
1674 /* Done. Do no free item or buf! */
1675 return(0);
1676 }
1677
1678 return(0);
1679}
int dcmReadFileTag(FILE *fp, DCMTAG *tag)
Definition dcm.c:553
int dcmReadFileVRVL(FILE *fp, dcmvr *vr, unsigned int *vl, unsigned int *n)
Definition dcm.c:724
unsigned int dcmReadFileVL(FILE *fp, unsigned int n)
Definition dcm.c:692
unsigned short int dcmitemParentNr(DCMITEM *d)
Definition dcm.c:923
char * dcmVRDescr(dcmvr id)
Definition dcm.c:282
@ DCM_VR_SQ
DICOM sequence of zero or more elements (used for nested data).
fpos_t pos

Referenced by dcmFileRead(), and dcmFileReadNextElement().

◆ dcmFileWrite()

int dcmFileWrite ( const char * filename,
DCMFILE * dcm,
int verbose )

Write a single DICOM file.

See also
dcmFileRead, dcmfileInit, dcmfileFree
Returns
0 when successful.
Parameters
filenamePointer to file name.
dcmPointer to DICOM data to be written.
verboseVerbose level; if zero, then nothing is printed into stdout or stderr

Definition at line 1758 of file dcm.c.

1765 {
1766 if(filename==NULL || strnlen(filename, 10)<1 || dcm==NULL) return(1);
1767 if(verbose>1) {printf("%s('%s')\n", __func__, filename); fflush(stdout);}
1768
1769 /* Check for the data */
1770 if(dcm->item==NULL) {
1771 return(2);
1772 }
1773
1774 /* Check whether we currently support the Transfer UID */
1775 if(dcm->truid!=DCM_TRUID_LEE) { // Little endian explicit
1776 return(2);
1777 }
1778
1779
1780 /* Open the file */
1781 if(verbose>1) printf("opening the file for writing\n");
1782 FILE *fp;
1783 fp=fopen(filename, "wb");
1784 if(fp==NULL) return(3);
1785
1786 /* Write preamble (just 128 zeroes) and magic number */
1787 {
1788 if(verbose>1) printf("writing preamble\n");
1789 char buf1[128], buf2[5];
1790 for(int i=0; i<128; i++) buf1[i]=(char)0;
1791 strcpy(buf2, "DICM");
1792 if(fwrite(buf1, 128, 1, fp)<1 || fwrite(buf2, 4, 1, fp)<1) {
1793 fclose(fp);
1794 return(3);
1795 }
1796 }
1797
1798
1799 /* Write the contents */
1800 if(verbose>1) printf("writing DICOM contents\n");
1801 int ret=0;
1802 DCMITEM *iptr;
1803 DCMITEM *d1=dcm->item;
1804 while(d1!=NULL) {
1805 if(verbose>2) {dcmitemPrint(d1);}
1806 /* Write */
1807 iptr=d1;
1808 {
1809 size_t n;
1810 /* Write tag */
1811 if(dcmWriteFileTag(fp, &iptr->tag)!=0) {ret=1; break;}
1812 /* Write VR and VL */
1813 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, NULL)!=0) {ret=2; break;}
1814 /* Write value, unless zero length, or SQ, in which case written later */
1815 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
1816 size_t len;
1817 if(iptr->vl==0xFFFFFFFF) {
1818 len=dcmVRVLength(iptr->vr);
1819 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
1820 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
1821 } else {
1822 len=iptr->vl;
1823 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
1824 n=fwrite(iptr->rd, iptr->vl, 1, fp);
1825 }
1826 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
1827 if(n!=1) {ret=4; break;}
1828 } else if(iptr->vr==DCM_VR_SQ && d1->child_item==NULL) {
1829 if(verbose>1) printf("SQ, but no contents to write!\n");
1830 /* Write Sequence Delimitation Item */
1831 if(dcmWriteFileSQDelimItem(fp)!=0) {ret=6; break;}
1832 }
1833 }
1834
1835 /* If this element (SQ) has children, then write those */
1836 /* Data Elements with a group of 0000, 0002 and 0006 shall not be present within Sequence Items,
1837 but that is not verified here */
1838 if(d1->child_item!=NULL) {
1839 DCMITEM *d2=d1->child_item;
1840 unsigned int d2counter=0;
1841 while(d2!=NULL) {
1842 if(verbose>2) {printf(" "); dcmitemPrint(d2);}
1843
1844 /* Write */
1845 iptr=d2;
1846
1847 /* First, write Item tag (FFFE,E000) */
1848 if(d2counter==0) {
1849 DCMTAG tag; tag.group=0xFFFE; tag.element=0xE000;
1850 if(dcmWriteFileTag(fp, &tag)!=0) {ret=11; break;}
1851 }
1852 /* Write item length; write 0xFFFFFFFF for now, correct later when known */
1853 fpos_t d2ilpos; // position for item length
1854 unsigned int d2il=0; // item length
1855 if(d2counter==0) {
1856 if(fgetpos(fp, &d2ilpos)) {ret=12; break;} // save position for writing later
1857 unsigned int ibuf;
1858 ibuf=0xFFFFFFFF;
1859 if(fwrite(&ibuf, 4, 1, fp)!=1) {ret=13; break;}
1860 }
1861 d2counter++;
1862
1863 /* Write item value data set */
1864 {
1865 /* Write tag */
1866 if(dcmWriteFileTag(fp, &iptr->tag)!=0) {ret=14; break;}
1867 d2il+=4;
1868 /* Write VR and VL */
1869 unsigned int s;
1870 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, &s)!=0) {ret=15; break;}
1871 d2il+=s;
1872 /* Write value, unless zero length, or SQ, in which case written later */
1873 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
1874 size_t len, n;
1875 if(iptr->vl==0xFFFFFFFF) {
1876 len=dcmVRVLength(iptr->vr);
1877 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
1878 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
1879 d2il+=len;
1880 } else {
1881 len=iptr->vl;
1882 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
1883 n=fwrite(iptr->rd, iptr->vl, 1, fp);
1884 d2il+=iptr->vl;
1885 }
1886 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
1887 if(n!=1) {ret=17; break;}
1888 } else if(iptr->vr==DCM_VR_SQ && iptr->child_item==NULL) {
1889 if(verbose>1) printf("SQ, but no contents to write!\n");
1890 /* Write Sequence Delimitation Item */
1891 if(dcmWriteFileSQDelimItem(fp)!=0) {ret=19; break;}
1892 }
1893 }
1894
1895 /* If this element has children, then write those */
1896 if(d2->child_item!=NULL) {
1897 DCMITEM *d3=d2->child_item;
1898 unsigned int d3counter=0;
1899 while(d3!=NULL) {
1900 if(verbose>2) {printf(" "); dcmitemPrint(d3);}
1901
1902 /* Write */
1903 iptr=d3;
1904 if(iptr->vr==DCM_VR_SQ) {d3=d3->next_item; continue;} // for now do not write SQs
1905
1906 /* First, write Item tag (FFFE,E000) */
1907 if(d3counter==0) {
1908 DCMTAG tag; tag.group=0xFFFE; tag.element=0xE000;
1909 if(dcmWriteFileTag(fp, &tag)!=0) {ret=31; break;}
1910 d2il+=4;
1911 }
1912 /* Write item length; write 0xFFFFFFFF for now, correct later when known */
1913 fpos_t d3ilpos; // position for item length
1914 unsigned int d3il=0; // item length
1915 if(d3counter==0) {
1916 unsigned int ibuf;
1917 if(fgetpos(fp, &d3ilpos)) {ret=32; break;} // save position for writing later
1918 ibuf=0xFFFFFFFF;
1919 if(fwrite(&ibuf, 4, 1, fp)!=1) {ret=33; break;}
1920 d2il+=4;
1921 }
1922 d3counter++;
1923
1924 /* Write item value data set */
1925 {
1926 /* Write tag */
1927 if(dcmWriteFileTag(fp, &iptr->tag)!=0) {ret=34; break;}
1928 d3il+=4; d2il+=4;
1929 /* Write VR and VL */
1930 unsigned int s;
1931 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, &s)!=0) {ret=35; break;}
1932 d3il+=s; d2il+=s;
1933 /* Write value, unless zero length, or SQ, in which case written later */
1934 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
1935 size_t len, n;
1936 if(iptr->vl==0xFFFFFFFF) {
1937 len=dcmVRVLength(iptr->vr);
1938 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
1939 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
1940 d3il+=len; d2il+=len;
1941 } else {
1942 len=iptr->vl;
1943 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
1944 n=fwrite(iptr->rd, iptr->vl, 1, fp);
1945 d3il+=iptr->vl; d2il+=iptr->vl;
1946 }
1947 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
1948 if(n!=1) {ret=37; break;}
1949 } else if(iptr->vr==DCM_VR_SQ && iptr->child_item==NULL) {
1950 if(verbose>1) printf("SQ, but no contents to write!\n");
1951 /* Write Sequence Delimitation Item */
1952 if(dcmWriteFileSQDelimItem(fp)!=0) {ret=39; break;}
1953 d2il+=8;
1954 }
1955 }
1956
1957 /* If this element has children, then write those */
1958 if(d3->child_item!=NULL) {
1959 //DCMITEM *d4=d3->child_item;
1960 if(verbose>0) fprintf(stderr, "Warning: 4th level items not written.\n");
1961 }
1962
1963 /* now that we known the length, write it to the saved position */
1964 if(0) {
1965 fpos_t opos; // current position to return to
1966 if(fgetpos(fp, &opos)) {ret=40; break;}
1967 fsetpos(fp, &d3ilpos); // go to the position for item length
1968 char buf[4];
1969 memcpy(buf, &d3il, 4);
1970 if(!little_endian()) swabip(buf, 4);
1971 if(fwrite(&buf, 4, 1, fp)!=1) {ret=41; break;}
1972 fsetpos(fp, &opos); // back to the position where we were
1973 }
1974
1975 d3=d3->next_item;
1976 }
1977 if(ret!=0) break;
1978
1979 /* Write Item Delimitation Tag */
1980 if(dcmWriteFileSQItemDelimTag(fp)!=0) {ret=21; break;}
1981 /* End of the sequence - write Sequence Delimitation Item */
1982 if(dcmWriteFileSQDelimItem(fp)!=0) {ret=21; break;}
1983
1984 }
1985
1986
1987 /* now that we known the length, write it to the saved position */
1988 if(0) {
1989 fpos_t opos; // current position to return to
1990 if(fgetpos(fp, &opos)) {ret=18; break;}
1991 fsetpos(fp, &d2ilpos); // go to the position for item length
1992 char buf[4];
1993 memcpy(buf, &d2il, 4);
1994 if(!little_endian()) swabip(buf, 4);
1995 if(fwrite(&buf, 4, 1, fp)!=1) {ret=19; break;}
1996 fsetpos(fp, &opos); // back to the position where we were
1997 }
1998
1999 d2=d2->next_item;
2000 }
2001 if(ret!=0) break;
2002
2003 /* Write Item Delimitation Tag */
2004 if(dcmWriteFileSQItemDelimTag(fp)!=0) {ret=21; break;}
2005 /* End of the sequence - write Sequence Delimitation Item */
2006 if(dcmWriteFileSQDelimItem(fp)!=0) {ret=21; break;}
2007
2008 }
2009
2010 d1=d1->next_item;
2011 } // next
2012 if(ret!=0) {
2013 if(verbose>0) fprintf(stderr, " ret := %d\n", ret);
2014 fclose(fp);
2015 return(3);
2016 }
2017
2018
2019 fclose(fp);
2020
2021 return(0);
2022}
int dcmWriteFileVRVL(FILE *fp, dcmvr vr, unsigned int vl, unsigned int *n)
Definition dcm.c:784
int dcmWriteFileSQItemDelimTag(FILE *fp)
Definition dcm.c:634
int dcmWriteFileTag(FILE *fp, DCMTAG *tag)
Definition dcm.c:583
int dcmWriteFileSQDelimItem(FILE *fp)
Definition dcm.c:609
void swabip(void *buf, long long int size)
Definition swap.c:72
int little_endian()
Definition swap.c:14

◆ dcmFindTag()

DCMITEM * dcmFindTag ( DCMITEM * d,
const short int omit,
DCMTAG * tag,
const int verbose )

Search for specified tag in DCMITEM data tree.

Returns
Returns pointer to next item with the tag, or NULL if not found.
Parameters
dPointer to current DICOM item.
omitOmit this item from the search.
tagPointer to the DICOM tag that is searched for.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout.

Definition at line 1163 of file dcm.c.

1172 {
1173 if(d==NULL || tag==NULL) return(NULL);
1174 if(verbose>0) printf("%s(%04X,%04X)\n", __func__, tag->group, tag->element);
1175 DCMITEM *iptr;
1176 if(omit==0) iptr=d; else iptr=d->next_item;
1177 while(iptr!=NULL) {
1178 if(verbose>2)
1179 printf(" checking tag(%04X,%04X)...\n", iptr->tag.group, iptr->tag.element);
1180 if(iptr->tag.group==tag->group && iptr->tag.element==tag->element) {
1181 if(verbose>2) printf(" found!\n");
1182 break;
1183 }
1184 /* Check if this item has children */
1185 if(iptr->child_item!=NULL) {
1186 if(verbose>2) printf(" going to search inside children...\n");
1187 DCMITEM *rptr=dcmFindTag(iptr->child_item, 0, tag, verbose);
1188 if(rptr!=NULL) return(rptr);
1189 if(verbose>3) printf(" nothing found in any of the children\n");
1190 }
1191 iptr=iptr->next_item;
1192 }
1193 /* Stop if we found tag, or if we do not have parent */
1194 if(iptr!=NULL) return(iptr);
1195 if(d->parent_item==NULL) return(NULL);
1196
1197 /* Search from the parent */
1198 if(verbose>2) printf(" going to search inside parent...\n");
1199 return(dcmFindTag(d->parent_item, 1, tag, verbose));
1200}
DCMITEM * dcmFindTag(DCMITEM *d, const short int omit, DCMTAG *tag, const int verbose)
Definition dcm.c:1163

Referenced by dcmFindTag().

◆ dcmitemFree()

void dcmitemFree ( DCMITEM * d)

Recursively free memory allocated for DCMITEM items and their children items.

See also
dcmfileFree
Author
Vesa Oikonen
Parameters
dPointer to DCMITEM.

Definition at line 840 of file dcm.c.

843 {
844 if(d==NULL) return;
845 /* find the last item in the list */
846 DCMITEM *ip=d; while(ip->next_item!=NULL) ip=ip->next_item;
847 while(ip!=NULL) {
848 /* Free items child and their children */
849 if(ip->child_item!=NULL) dcmitemFree(ip->child_item);
850 /* Free this item and move to previous item */
851 if(ip->prev_item!=NULL) {
852 ip=ip->prev_item;
853 free(ip->next_item->rd); free(ip->next_item);
854 ip->next_item=NULL;
855 } else {
856 free(ip->rd); free(ip); ip=NULL;
857 }
858 }
859}

Referenced by dcmfileFree(), and dcmitemFree().

◆ dcmitemGetInt()

long int dcmitemGetInt ( DCMITEM * d)

Read integer value from given DICOM item.

VR must be either UL, US, SL, SS, or IS; otherwise 0 is returned.

Returns
Returns the value as long int, in order to cope with originally unsigned integers.
See also
dcmitemGetInt, dcmValueString, dcmFindTag
Parameters
dPointer to item.

Definition at line 1084 of file dcm.c.

1087 {
1088 if(d==NULL || d->rd==NULL) return(0);
1089 long int li=0;
1090 if(d->vr==DCM_VR_UL) { // unsigned 32-bit int
1091 unsigned int i;
1092 memcpy(&i, d->rd, 4); if(!little_endian()) swap(&i, &i, 4);
1093 li=(long int)i;
1094 } else if(d->vr==DCM_VR_US) { // unsigned 16-bit int
1095 unsigned short int i;
1096 memcpy(&i, d->rd, 2); if(!little_endian()) swap(&i, &i, 2);
1097 li=(long int)i;
1098 } else if(d->vr==DCM_VR_SL) { // signed 32-bit int
1099 int i;
1100 memcpy(&i, d->rd, 4); if(!little_endian()) swap(&i, &i, 4);
1101 li=(long int)i;
1102 } else if(d->vr==DCM_VR_SS) { // signed 16-bit int
1103 short int i;
1104 memcpy(&i, d->rd, 2); if(!little_endian()) swap(&i, &i, 2);
1105 li=(long int)i;
1106 } else if(d->vr==DCM_VR_IS) { // integer string
1107 li=atol(d->rd);
1108 }
1109 return(li);
1110}
@ DCM_VR_SS
DICOM signed short (16-bit integer), 2 bytes fixed.
@ DCM_VR_US
DICOM unsigned short (16-bit) integer, 2 bytes fixed.
@ DCM_VR_UL
DICOM unsigned long (32-bit) integer, 4 bytes fixed.
@ DCM_VR_SL
DICOM signed long (32-bit integer), 4 bytes fixed.
void swap(void *orig, void *new, int size)
Definition swap.c:31

◆ dcmitemGetReal()

double dcmitemGetReal ( DCMITEM * d)

Read floating point value from given DICOM item.

VR must be either FL, FD, DS, UL, US, SL, SS, or IS; otherwise 0 is returned.

Returns
Returns the value as double.
See also
dcmitemGetInt, dcmValueString, dcmFindTag
Parameters
dPointer to item.

Definition at line 1120 of file dcm.c.

1123 {
1124 if(d==NULL || d->rd==NULL) return(0);
1125 double r=0.0;
1126 if(d->vr==DCM_VR_FL) { // 32-bit float
1127 float f;
1128 memcpy(&f, d->rd, 4); if(!little_endian()) swap(&f, &f, 4);
1129 r=(double)f;
1130 } else if(d->vr==DCM_VR_FD) { // 64-bit double
1131 double f;
1132 memcpy(&f, d->rd, 8); if(!little_endian()) swap(&f, &f, 8);
1133 r=f;
1134 } else if(d->vr==DCM_VR_DS) { // decimal string
1135 r=atof(d->rd);
1136 } else if(d->vr==DCM_VR_UL) { // unsigned 32-bit int
1137 unsigned int i;
1138 memcpy(&i, d->rd, 4); if(!little_endian()) swap(&i, &i, 4);
1139 r=(double)i;
1140 } else if(d->vr==DCM_VR_US) { // unsigned 16-bit int
1141 unsigned short int i;
1142 memcpy(&i, d->rd, 2); if(!little_endian()) swap(&i, &i, 2);
1143 r=(double)i;
1144 } else if(d->vr==DCM_VR_SL) { // signed 32-bit int
1145 int i;
1146 memcpy(&i, d->rd, 4); if(!little_endian()) swap(&i, &i, 4);
1147 r=(double)i;
1148 } else if(d->vr==DCM_VR_SS) { // signed 16-bit int
1149 short int i;
1150 memcpy(&i, d->rd, 2); if(!little_endian()) swap(&i, &i, 2);
1151 r=(double)i;
1152 } else if(d->vr==DCM_VR_IS) { // integer string
1153 r=(double)atol(d->rd);
1154 }
1155 return(r);
1156}
@ DCM_VR_FD
DICOM floating point double precision, 8 bytes fixed.
@ DCM_VR_FL
DICOM floating point single precision, 4 bytes fixed.

◆ dcmitemMaxDepth()

unsigned short int dcmitemMaxDepth ( DCMITEM * d)

Get the maximum depth of DCMITEM tree.

Returns
Returns the number of levels under specified item, not including given item itself.
See also
dcmitemParentNr, dcmfileMaxDepth
Parameters
dPointer to DCMITEM item.

Definition at line 884 of file dcm.c.

887 {
888 if(d==NULL || d->child_item==NULL) return(0);
889 unsigned short int m=0, n=0;
890 DCMITEM *cd=d->child_item;
891 /* go through all children */
892 while(cd!=NULL) {
893 n=dcmitemMaxDepth(cd); if(n>m) m=n;
894 cd=cd->next_item;
895 }
896 return(m+1);
897}

Referenced by dcmfileMaxDepth(), and dcmitemMaxDepth().

◆ dcmitemParentNr()

unsigned short int dcmitemParentNr ( DCMITEM * d)

Check how deep in DCMITEM tree this item is.

Returns
Returns the number of parents this item has.
See also
dcmitemMaxDepth, dcmfileMaxDepth
Parameters
dPointer to DCMITEM.

Definition at line 923 of file dcm.c.

926 {
927 if(d==NULL) return(0);
928 unsigned short int n=0;
929 DCMITEM *pd=d->parent_item;
930 while(pd!=NULL) {n++; pd=pd->parent_item;}
931 return(n);
932}

Referenced by dcmFileReadNextElement().

◆ dcmitemPrint()

void dcmitemPrint ( DCMITEM * d)

Print contents of given DICOM item into stdout.

Parameters
dPointer to item.

Definition at line 1205 of file dcm.c.

1208 {
1209 if(d==NULL) {printf("(null)\n"); fflush(stdout); return;}
1210 printf("tag(%04X,%04X)", d->tag.group, d->tag.element); fflush(stdout);
1211 printf(" VR=%s", dcmVRName(d->vr)); fflush(stdout);
1212 if(d->vl==0xFFFFFFFF) printf(" VL=%08X", d->vl); else printf(" VL=%u", d->vl);
1213 fflush(stdout);
1214 char *buf=dcmValueString(d); printf(" '%s'", buf); free(buf);
1215 printf("\n"); fflush(stdout);
1216}
char * dcmValueString(DCMITEM *d)
Definition dcm.c:942

Referenced by dcmAddItem(), and dcmFileWrite().

◆ dcmReadFileTag()

int dcmReadFileTag ( FILE * fp,
DCMTAG * tag )

Read DICOM tag from current file position.

Note
Tag validity is not verified here; error may be caused by end-of-file. Alternatively, read may seem to be successful, but tag contents are file padding symbols (0xFFFC).
See also
dcmReadFile, dcmReadFileElement
Returns
Returns 0 when successful, otherwise >0.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the start of the element (and tag).
tagPointer to DICOM tag struct; enter NULL if you just need to move file position over the tag.

Definition at line 553 of file dcm.c.

559 {
560 if(tag!=NULL) {tag->group=tag->element=0xFFFC;} // padding
561 if(fp==NULL || feof(fp)) return(1);
562 unsigned short int buf[2];
563 size_t n=fread(&buf, 2, 2, fp);
564 if(n!=2) return(2+n);
565 if(tag!=NULL) {
566 tag->group=buf[0];
567 tag->element=buf[1];
568 if(!little_endian()) { // tag is by default little endian
569 swap(&tag->group, &tag->group, 2);
570 swap(&tag->element, &tag->element, 2);
571 }
572 }
573 return(0);
574}

Referenced by dcmFileReadNextElement(), and dcmReadTransferSyntaxUID().

◆ dcmReadFileVL()

unsigned int dcmReadFileVL ( FILE * fp,
unsigned int n )

Read DICOM value length (2 or 4 bytes, depending on VR) from current file position.

See also
dcmReadFileTag, dcmReadFileVR, dcmReadFileElement
Returns
Returns the value length.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the VL start.
nNumber of bytes (2 or 4) in the VL representation.

Definition at line 692 of file dcm.c.

697 {
698 unsigned int vl=0;
699 if(fp==NULL || (n!=2 && n!=4)) return(vl);
700
701 /* Read 2 or 4 bytes */
702 if(n==2) {
703 unsigned short int si;
704 if(fread(&si, 2, 1, fp)!=1) return(vl);
705 if(!little_endian()) swap(&si, &si, 2);
706 vl=si;
707 } else if(n==4) {
708 unsigned int li;
709 if(fread(&li, 4, 1, fp)!=1) return(vl);
710 if(!little_endian()) swap(&li, &li, 4);
711 vl=li;
712 }
713 return(vl);
714}

Referenced by dcmFileReadNextElement(), and dcmReadTransferSyntaxUID().

◆ dcmReadFileVR()

dcmvr dcmReadFileVR ( FILE * fp,
char * vrstr )

Read DICOM value representation (2 or 4 bytes) from current file position.

See also
dcmReadFileTag, dcmReadFileElement
Returns
Returns the enumerated VR number, DCM_VR_INVALID in case of an error.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the VR start.
vrstrPointer for VR string, allocated for at least 3 characters to have space for the trailing null; enter NULL if not needed.

Definition at line 655 of file dcm.c.

661 {
662 if(vrstr!=NULL) vrstr[0]=(char)0;
663 if(fp==NULL) return(DCM_VR_INVALID);
664
665 /* Read the first two bytes */
666 char buf[3];
667 if(fread(&buf, 1, 2, fp)!=2) return(DCM_VR_INVALID);
668 buf[2]=(char)0;
669
670 /* Identify the VR */
671 dcmvr lvr=dcmVRId(buf);
672 if(vrstr!=NULL) {
673 if(lvr!=DCM_VR_INVALID) strcpy(vrstr, dcmVRName(lvr));
674 else strcpy(vrstr, buf);
675 }
676
677 /* If this VR has extra 2 byte reserved space, then
678 we need to read but do not use the next 2 bytes. */
679 if(dcmVRReserved(lvr)!=0) {
680 if(fread(&buf, 1, 2, fp)!=2) return(DCM_VR_INVALID);
681 }
682 return(lvr);
683}
unsigned char dcmVRReserved(dcmvr id)
Definition dcm.c:205
dcmvr dcmVRId(const char *s)
Definition dcm.c:223
dcmvr

Referenced by dcmReadTransferSyntaxUID().

◆ dcmReadFileVRVL()

int dcmReadFileVRVL ( FILE * fp,
dcmvr * vr,
unsigned int * vl,
unsigned int * n )

Read DICOM Value Representation (VR, 2 or 4 bytes) and Value Length (VL, 2 or 4 bytes) from current file position.

See also
dcmReadFileVR, dcmReadFileVL, dcmReadFileTag, dcmReadFileElement, dcmWriteFileVRVL
Returns
0 when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, positioned at the VR start.
vrPointer for enumerated VR value; enter NULL if not needed (file pointer moved anyway).
vlPointer for VL; enter NULL if not needed (file pointer moved anyway).
nPointer for number of bytes read from file; enter NULL if not needed.

Definition at line 724 of file dcm.c.

733 {
734 if(vr!=NULL) *vr=DCM_VR_INVALID;
735 if(vl!=NULL) *vl=0;
736 if(n!=NULL) *n=0;
737 if(fp==NULL) return(1);
738
739 /* Read the first two bytes */
740 char buf[3];
741 if(fread(&buf, 1, 2, fp)!=2) return(2); else if(n!=NULL) *n+=2;
742 buf[2]=(char)0;
743
744 /* Identify the VR */
745 dcmvr lvr=dcmVRId(buf);
746 if(vr!=NULL) *vr=lvr;
747 if(lvr==DCM_VR_INVALID) return(3);
748
749 /* If this VR has extra 2 byte reserved space, then
750 we need to read but do not use the next 2 bytes. */
751 unsigned int bsize=2+dcmVRReserved(lvr);
752 if(bsize==4) {
753 if(fread(&buf, 1, 2, fp)!=2) return(2);
754 if(n!=NULL) *n+=2;
755 }
756
757 /* Read VL from the next 2 or 4 bytes */
758 unsigned int lvl=0;
759 if(bsize==2) {
760 unsigned short int si;
761 if(fread(&si, 2, 1, fp)!=1) return(2);
762 if(!little_endian()) swap(&si, &si, 2);
763 lvl=si;
764 } else {
765 unsigned int li;
766 if(fread(&li, 4, 1, fp)!=1) return(2);
767 if(!little_endian()) swap(&li, &li, 4);
768 lvl=li;
769 }
770 if(n!=NULL) *n+=bsize;
771 if(vl!=NULL) *vl=lvl;
772
773 return(0);
774}

Referenced by dcmFileReadNextElement().

◆ dcmReadTransferSyntaxUID()

dcmtruid dcmReadTransferSyntaxUID ( FILE * fp)

Read and identify the DICOM Transfer Syntax UID.

Returns
Returns the enumerated UID, or DCM_TRUID_INVALID.
See also
dcmVerifyMagic
Parameters
fpPointer to DICOM file opened in binary format, and positioned right after the Magic number. Position will be returned to this position.

Definition at line 502 of file dcm.c.

507 {
508 if(fp==NULL || feof(fp)) return(DCM_TRUID_INVALID);
509 /* Save original file position */
510 fpos_t opos;
511 if(fgetpos(fp, &opos)) return(DCM_TRUID_INVALID);
512 /* Read file until we find DICOM tag 0x0002,0x0010 */
513 DCMTAG tag;
514 int tag_found=0;
515 while(!tag_found && !feof(fp)) {
516 if(dcmReadFileTag(fp, &tag)) break;
517 if(tag.group==0x0002 && tag.element==0x0010) {tag_found=1; break;}
518 /* not the tag that we want, so just go through this item */
519 dcmvr vr=dcmReadFileVR(fp, NULL);
520 unsigned int vl=0;
521 if(dcmVRReserved(vr)==0) vl=dcmReadFileVL(fp, 2);
522 else vl=dcmReadFileVL(fp, 4);
523 if(vr==DCM_VR_SQ) break;
524 if(vl==0xFFFFFFFF) break;
525 char buf[vl+1];
526 if(fread(buf, 1, vl, fp)!=vl) break;
527 } // get next tag
528 if(!tag_found) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
529 /* Read the UID */
530 if(dcmReadFileVR(fp, NULL)!=DCM_VR_UI) {
531 fsetpos(fp, &opos); return(DCM_TRUID_INVALID);
532 }
533 unsigned int vl=dcmReadFileVL(fp, 2);
534 if(vl==0 || vl==0xFFFFFFFF) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
535 char uid[vl+1];
536 if(fread(uid, 1, vl, fp)!=vl) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
537 /* Return file position to the original */
538 fsetpos(fp, &opos);
539 /* Identify the UID */
540 return(dcmTrUID(uid));
541}
dcmvr dcmReadFileVR(FILE *fp, char *vrstr)
Definition dcm.c:655
dcmtruid dcmTrUID(const char *s)
Definition dcm.c:445

Referenced by dcmFileRead().

◆ dcmSOPIdentify()

unsigned int dcmSOPIdentify ( const char * s)

Identify the DICOM SOP UID.

Returns
Returns the SOP UID list index.
See also
dcmSOPName, dcmSOPUID
Parameters
sSOP UID string.

Definition at line 367 of file dcm.c.

370 {
371 if(s==NULL || strnlen(s, 3)<3) return(0);
372
373 /* Identify the SOP UID */
374 unsigned int i=0;
375 while(strcmp(dcm_sop[i].uid, "unknown")!=0) {
376 if(strcmp(dcm_sop[i].uid, s)==0) return(i);
377 i++;
378 }
379 return(i);
380}

◆ dcmSOPName()

char * dcmSOPName ( unsigned int i)

Get the DICOM SOP UID Name.

Returns
Returns pointer to the SOP Name string.
See also
dcmSOPIdentify, dcmSOPUID
Parameters
iSOP UID list index.

Definition at line 388 of file dcm.c.

391 {
392 unsigned int j=0;
393 while(strcmp(dcm_sop[j].uid, "unknown")!=0) {
394 if(i==j) return(dcm_sop[j].name);
395 j++;
396 }
397 return(dcm_sop[j].name);
398}

◆ dcmSOPUID()

char * dcmSOPUID ( unsigned int i)

Get the DICOM SOP UID.

Returns
Returns pointer to the UID string.
See also
dcmSOPIdentify, dcmSOPName
Parameters
iSOP UID list index.

Definition at line 406 of file dcm.c.

409 {
410 unsigned int j=0;
411 while(strcmp(dcm_sop[j].uid, "unknown")!=0) {
412 if(i==j) return(dcm_sop[j].uid);
413 j++;
414 }
415 return(dcm_sop[j].uid);
416}

◆ dcmSOPUIDName()

char * dcmSOPUIDName ( const char * s)

Get the name of DICOM SOP UID.

Returns
Returns pointer to the SOP UID name string.
See also
dcmSOPName, dcmSOPUID
Parameters
sSOP UID string.

Definition at line 424 of file dcm.c.

427 {
428 if(s==NULL || strnlen(s, 3)<3) return(dcm_sop[0].name);
429
430 /* Identify the SOP UID */
431 unsigned int i=0;
432 while(strcmp(dcm_sop[i].uid, "unknown")!=0) {
433 if(strcmp(dcm_sop[i].uid, s)==0) return(dcm_sop[i].name);
434 i++;
435 }
436 return(dcm_sop[i].name);
437}

◆ dcmTagSet()

void dcmTagSet ( DCMTAG * tag,
unsigned short int group,
unsigned short int element )

Set DICOM Tag group and element.

Parameters
tagPointer to Tag to set.
groupTag Group
elementTag Element

Definition at line 1221 of file dcm.c.

1228 {
1229 tag->group=group;
1230 tag->element=element;
1231}

◆ dcmTM2intl()

char * dcmTM2intl ( const char * orig,
char * intl )

Convert DICOM time 'TM' to international format hh:mm:ss.

Returns
Returns pointer to the time string, or NULL in case of an error.
Parameters
origPointer to original DICOM string.
intlPointer to string where time in international format will be written; must be allocated for at least 9 characters.

Definition at line 322 of file dcm.c.

328 {
329 if(orig==NULL || intl==NULL) return(NULL);
330 if(strnlen(orig, 14)<6) return(NULL);
331 if(isdigit(orig[2])) { // modern format hhmmss.fract
332 sprintf(intl, "%2.2s:%2.2s:%2.2s", orig, orig+2, orig+4);
333 } else { // old format hh.mm.ss
334 sprintf(intl, "%2.2s:%2.2s:%2.2s", orig, orig+3, orig+6);
335 }
336 if(istime(intl)) {intl[0]=(char)0; return(NULL);}
337 return(intl);
338}
int istime(char *str)
Definition datetime.c:259

◆ dcmTrUID()

dcmtruid dcmTrUID ( const char * s)

Identify the DICOM Transfer Syntax UID.

Returns
Returns the enumerated id.
See also
dcmTrUIDDescr
Parameters
sUID string.

Definition at line 445 of file dcm.c.

448 {
449 if(s==NULL || strnlen(s, 5)<5) return(DCM_TRUID_INVALID);
450
451 /* Identify the UID */
452 unsigned short int i=1; // 1 because 0 is unknown
453 while(dcm_truid[i].id!=DCM_TRUID_INVALID) {
454 if(strcmp(dcm_truid[i].uid, s)==0) return(dcm_truid[i].id);
455 i++;
456 }
457 return(DCM_TRUID_UNKNOWN);
458}

Referenced by dcmReadTransferSyntaxUID().

◆ dcmTrUIDDescr()

char * dcmTrUIDDescr ( dcmtruid id)

Get the DICOM Transfer Syntax UID description.

Returns
Returns pointer to the description string.
See also
dcmTrUID
Parameters
idTransfer Syntax UID id (DCM_TRUID_LEI, ...).

Definition at line 466 of file dcm.c.

469 {
470 unsigned short int i=0;
471 while(dcm_truid[i].id!=DCM_TRUID_INVALID) {
472 if(id==dcm_truid[i].id) return(dcm_truid[i].descr);
473 i++;
474 }
475 return(dcm_truid[DCM_TRUID_INVALID].descr);
476}

Referenced by dcmFileRead().

◆ dcmTrUIDString()

char * dcmTrUIDString ( dcmtruid id)

Get the DICOM Transfer Syntax UID string.

Returns
Returns pointer to the description string.
See also
dcmTrUID
Parameters
idTransfer Syntax UID id (DCM_TRUID_LEI, ...).

Definition at line 484 of file dcm.c.

487 {
488 unsigned short int i=0;
489 while(dcm_truid[i].id!=DCM_TRUID_INVALID) {
490 if(id==dcm_truid[i].id) return(dcm_truid[i].uid);
491 i++;
492 }
493 return(dcm_truid[DCM_TRUID_INVALID].uid);
494}

◆ dcmValueString()

char * dcmValueString ( DCMITEM * d)

Pre-process the DICOM element value into format suitable for printing.

Note
Use only for printing information for the user.
Returns
Returns pointer to locally allocated null-terminated string.
Postcondition
Free the pointer after use.
See also
dcmitemGetInt, dcmitemGetReal, dcmFindTag

Attribute tag

Float

Double

Unsigned 32-bit int

Unsigned 16-bit int

Signed 32-bit int

Signed 16-bit int

Parameters
dPointer to item containing the value to print.

Definition at line 942 of file dcm.c.

945 {
946 if(d==NULL) return((char*)NULL);
947
948 /* For sequence, return string 'na' */
949 if(d->vr==DCM_VR_SQ) {
950 char *s=malloc(3); strcpy(s, "na"); // do not write char *s="na";
951 return(s);
952 }
953
954 /* If there is no value, then return string 'empty', or
955 'na', if value just was not stored (pixel data) */
956 if(d->vl==0) {
957 char *s=malloc(6); strcpy(s, "empty");
958 return(s);
959 } else if(d->rd==NULL) {
960 char *s=malloc(3); strcpy(s, "na");
961 return(s);
962 }
963
964 unsigned int len;
965 if(d->vl==0xFFFFFFFF) len=(unsigned int)dcmVRVLength(d->vr); else len=d->vl;
966
967 /* String values */
968 if(d->vr==DCM_VR_CS || d->vr==DCM_VR_DS || d->vr==DCM_VR_IS ||
969 d->vr==DCM_VR_LO || d->vr==DCM_VR_LT || d->vr==DCM_VR_PN ||
970 d->vr==DCM_VR_SH || d->vr==DCM_VR_ST)
971 {
972 char *s=malloc(len+1);
973 memcpy(s, d->rd, len); s[len]=(char)0;
974 return(s);
975 }
976
977 /* More string values */
978 if(d->vr==DCM_VR_AS || d->vr==DCM_VR_PN ||
979 d->vr==DCM_VR_DA || d->vr==DCM_VR_DT || d->vr==DCM_VR_TM ||
980 d->vr==DCM_VR_UT || d->vr==DCM_VR_AE ||
981 d->vr==DCM_VR_UI || d->vr==DCM_VR_UR)
982 {
983 char *s=malloc(len+1);
984 memcpy(s, d->rd, len); s[len]=(char)0;
985 return(s);
986 }
987
989 if(d->vr==DCM_VR_AT) {
990 DCMTAG tag;
991 memcpy(&tag.group, d->rd, 2);
992 memcpy(&tag.element, d->rd+2, 2);
993 if(!little_endian()) {
994 swap(&tag.group, &tag.group, 2);
995 swap(&tag.element, &tag.element, 2);
996 }
997 char *s=malloc(14);
998 sprintf(s, "0x%04x,0x%04x", tag.group, tag.element);
999 return(s);
1000 }
1001
1003 if(d->vr==DCM_VR_FL) {
1004 float f;
1005 memcpy(&f, d->rd, 4);
1006 if(!little_endian()) swap(&f, &f, 4);
1007 char *s=malloc(16);
1008 sprintf(s, "%g", f);
1009 return(s);
1010 }
1011
1013 if(d->vr==DCM_VR_FD) {
1014 char *s=malloc(32);
1015 double f;
1016 memcpy(&f, d->rd, 8);
1017 if(!little_endian()) swap(&f, &f, 8);
1018 sprintf(s, "%g", f);
1019 return(s);
1020 }
1021
1023 if(d->vr==DCM_VR_UL) {
1024 unsigned int i;
1025 memcpy(&i, d->rd, 4);
1026 if(!little_endian()) swap(&i, &i, 4);
1027 char *s=malloc(16);
1028 sprintf(s, "%u", i);
1029 return(s);
1030 }
1031
1033 if(d->vr==DCM_VR_US) {
1034 unsigned short int i;
1035 memcpy(&i, d->rd, 2);
1036 if(!little_endian()) swap(&i, &i, 2);
1037 char *s=malloc(8);
1038 sprintf(s, "%u", i);
1039 return(s);
1040 }
1041
1043 if(d->vr==DCM_VR_SL) {
1044 int i;
1045 memcpy(&i, d->rd, 4);
1046 if(!little_endian()) swap(&i, &i, 4);
1047 char *s=malloc(16);
1048 sprintf(s, "%d", i);
1049 return(s);
1050 }
1051
1053 if(d->vr==DCM_VR_SS) {
1054 short int i;
1055 memcpy(&i, d->rd, 2);
1056 if(!little_endian()) swap(&i, &i, 2);
1057 char *s=malloc(8);
1058 sprintf(s, "%d", i);
1059 return(s);
1060 }
1061
1062/* Not (yet) printed:
1063 DCM_VR_OB, ///< DICOM other byte string, even bytes, endian insensitive.
1064 DCM_VR_OD, ///< DICOM other double (64-bit) stream, endian sensitive.
1065 DCM_VR_OF, ///< DICOM other float (32-bit) stream, endian sensitive.
1066 DCM_VR_OL, ///< DICOM other long (32-bit) stream, endian sensitive.
1067 DCM_VR_OW, ///< DICOM other word (16-bit) stream, even bytes, endian sensitive.
1068 DCM_VR_UC, ///< DICOM unlimited characters.
1069 DCM_VR_UN, ///< DICOM unknown, any valid length of another VR.
1070 DCM_VR_INVALID ///< Invalid DICOM value representation.
1071*/
1072 char *s=malloc(3); strcpy(s, "na"); // do not write char *s="na";
1073 return(s);
1074}
@ DCM_VR_DT
DICOM date time, max 26 bytes.
@ DCM_VR_CS
DICOM code (control) string, max 16 bytes.
@ DCM_VR_UT
DICOM unlimited text, character string.
@ DCM_VR_TM
DICOM time HHMMSS.FFFFFF, max 14 bytes.
@ DCM_VR_AS
DICOM age string, 4 bytes fixed.
@ DCM_VR_ST
DICOM short text, max 1024 chars.
@ DCM_VR_AT
DICOM attribute tag, 4 bytes fixed.
@ DCM_VR_DA
DICOM date in format YYYYMMDD, 8 bytes fixed.
@ DCM_VR_AE
DICOM application entity, max 16 bytes.

Referenced by dcmitemPrint().

◆ dcmVerifyMagic()

int dcmVerifyMagic ( const char * filename,
FILE * fp )

Verify that given file (either file name or file pointer) appears to be DICOM file, based on the magic number.

See also
dcmReadFile, dcmReadTransferSyntaxUID
Returns
Returns 1 if DICOM magic number can be found, or 0 if not.
Author
Vesa Oikonen
Parameters
filenameName of file to open and to verify for the magic number; enter NULL to use the file pointer (next argument) instead.
fpFile pointer of file to check, opened with fp=fopen(filename, "rb"); enter NULL to open file (previous argument) locally. Previously opened file pointer is first rewound to start; if DICOM magic number is found, then file pointer is left to the end of magic number, and if not, it is rewound to the file start.

Definition at line 157 of file dcm.c.

168 {
169 FILE *lfp;
170
171 if(filename==NULL && fp==NULL) return(0);
172 if(fp!=NULL) {
173 lfp=fp; rewind(lfp);
174 } else {
175 lfp=fopen(filename, "rb");
176 }
177 if(lfp==NULL) return(0);
178
179 /* Skip the first 128 bytes */
180 if(fseek(lfp, 128, SEEK_SET)) {if(fp==NULL) fclose(lfp); return(0);}
181
182 /* Read the next 4 bytes as characters */
183 char buf[5];
184 size_t n=fread(&buf, 1, 4, lfp);
185 buf[4]=(char)0;
186 if(n!=(size_t)4) {rewind(lfp); return(0);}
187
188 /* Check the magic number */
189 if(strncmp(buf, "DICM", 4)==0) {
190 if(fp==NULL) fclose(lfp);
191 return(1);
192 } else {
193 if(fp==NULL) fclose(lfp); else rewind(lfp);
194 return(0);
195 }
196}

Referenced by dcmFileRead(), and imgFormatDetermine().

◆ dcmVRDescr()

char * dcmVRDescr ( dcmvr id)

Get the DICOM VR description.

Returns
Returns pointer to the description string.
See also
dcmIdentifyVR
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 282 of file dcm.c.

285 {
286 unsigned short int i=0;
287 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
288 if(id==dcm_vr[i].vr) return(dcm_vr[i].descr);
289 i++;
290 }
291 return(dcm_vr[DCM_VR_INVALID].descr);
292}

Referenced by dcmFileReadNextElement().

◆ dcmVRId()

dcmvr dcmVRId ( const char * s)

Identify the DICOM VR based on the two-character long string.

Returns
Returns the VR id.
See also
dcmVRName
Parameters
sVR string. Two first characters are used. String does not need to be null-terminated.

Definition at line 223 of file dcm.c.

227 {
228 if(s==NULL) return(DCM_VR_INVALID);
229 char buf[3]; buf[0]=s[0]; buf[1]=s[1]; buf[2]=(char)0;
230
231 /* Identify the VR */
232 unsigned short int i=0;
233 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
234 if(strncmp(dcm_vr[i].name, buf, 2)==0) return(dcm_vr[i].vr);
235 i++;
236 }
237 return(DCM_VR_INVALID);
238}

Referenced by dcmReadFileVR(), and dcmReadFileVRVL().

◆ dcmVRName()

char * dcmVRName ( dcmvr id)

Get the DICOM VR name.

Returns
Returns pointer to the name string.
See also
dcmIdentifyVR
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 246 of file dcm.c.

249 {
250 unsigned short int i=0;
251 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
252 if(id==dcm_vr[i].vr) return(dcm_vr[i].name);
253 i++;
254 }
255 return(dcm_vr[DCM_VR_INVALID].name);
256}

Referenced by dcmAddItem(), dcmFileReadNextElement(), dcmitemPrint(), dcmReadFileVR(), and dcmWriteFileVRVL().

◆ dcmVRReserved()

unsigned char dcmVRReserved ( dcmvr id)

Is the explicit VR (2 bytes) followed by reserved 2 bytes? If yes, then the following Value Length is also given as 32-byte integer, if no, then as 16-bit integer.

Returns
Returns 0, if not, and 2, if it is.
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 205 of file dcm.c.

208 {
209 unsigned short int i=0;
210 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
211 if(id==dcm_vr[i].vr) return(dcm_vr[i].res);
212 i++;
213 }
214 return(2);
215}

Referenced by dcmReadFileVR(), dcmReadFileVRVL(), dcmReadTransferSyntaxUID(), and dcmWriteFileVRVL().

◆ dcmVRVLength()

size_t dcmVRVLength ( dcmvr id)

Get the DICOM VR max value length in bytes; 0 if not defined.

Returns
Returns the length in bytes.
See also
dcmIdentifyVR
Parameters
idVR id (DCM_VR_AE, ...).

Definition at line 264 of file dcm.c.

267 {
268 unsigned short int i=0;
269 while(dcm_vr[i].vr!=DCM_VR_INVALID) {
270 if(id==dcm_vr[i].vr) return(dcm_vr[i].s);
271 i++;
272 }
273 return(dcm_vr[DCM_VR_INVALID].s);
274}

Referenced by dcmAddItem(), dcmFileReadNextElement(), dcmFileWrite(), and dcmValueString().

◆ dcmWriteFileSQDelimItem()

int dcmWriteFileSQDelimItem ( FILE * fp)

Write DICOM Sequence delimitation item into current file position.

This item consists of four byte sequence delimitation tag (0xFFFE, 0xE0DD) and four byte item length (0x00000000), i.e. together 8 bytes.

See also
dcmWriteFileTag, dcmReadFileTag, dcmWriteFileSQItemDelimTag
Returns
0 when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, at the write position.

Definition at line 609 of file dcm.c.

612 {
613 if(fp==NULL) return(1);
614 int ret;
615 DCMTAG tag;
616 tag.group=0xFFFE; tag.element=0xE0DD;
617 ret=dcmWriteFileTag(fp, &tag); if(ret!=0) return(ret);
618 tag.group=0x0000; tag.element=0x0000;
619 ret=dcmWriteFileTag(fp, &tag); if(ret!=0) return(ret);
620 return(0);
621}

Referenced by dcmFileWrite().

◆ dcmWriteFileSQItemDelimTag()

int dcmWriteFileSQItemDelimTag ( FILE * fp)

Write DICOM Sequence Item Delimitation Tag with VL into current file position.

This tag consists of four bytes, sequence item delimitation tag (0xFFFE, 0xE00D), followed by four byte item length (0x00000000), i.e. together 8 bytes.

See also
dcmWriteFileTag, dcmReadFileTag, dcmWriteFileSQDelimItem
Returns
0 when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, at the write position.

Definition at line 634 of file dcm.c.

637 {
638 if(fp==NULL) return(1);
639 int ret;
640 DCMTAG tag;
641 tag.group=0xFFFE; tag.element=0xE00D;
642 ret=dcmWriteFileTag(fp, &tag); if(ret!=0) return(ret);
643 tag.group=0x0000; tag.element=0x0000;
644 ret=dcmWriteFileTag(fp, &tag); if(ret!=0) return(ret);
645 return(0);
646}

Referenced by dcmFileWrite().

◆ dcmWriteFileTag()

int dcmWriteFileTag ( FILE * fp,
DCMTAG * tag )

Write DICOM tag into current file position.

See also
dcmWriteFile, dcmReadFileTag
Returns
0 when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, at the write position.
tagPointer to DICOM tag struct to write.

Definition at line 583 of file dcm.c.

588 {
589 if(fp==NULL || tag==NULL) return(1);
590 unsigned short int buf[2];
591 buf[0]=tag->group;
592 buf[1]=tag->element;
593 if(!little_endian()) swabip(buf, 4); // tag is by default little endian
594 if(fwrite(&buf, 2, 2, fp)!=2) return(2);
595 return(0);
596}

Referenced by dcmFileWrite(), dcmWriteFileSQDelimItem(), and dcmWriteFileSQItemDelimTag().

◆ dcmWriteFileVRVL()

int dcmWriteFileVRVL ( FILE * fp,
dcmvr vr,
unsigned int vl,
unsigned int * n )

Write DICOM Value Representation (VR, 2 or 4 bytes) and Value Length (VL, 2 or 4 bytes) into current file position.

See also
dcmWriteFileTag, dcmReadFileElement, dcmWriteFileVRVL
Returns
0 when successful.
Author
Vesa Oikonen
Parameters
fpFile pointer, opened fro writing in binary mode.
vrEnumerated VR value.
vlVL
nPointer for number of bytes written into file; enter NULL if not needed.

Definition at line 784 of file dcm.c.

793 {
794 if(n!=NULL) *n=0;
795 if(fp==NULL || vr==DCM_VR_INVALID) return(1);
796
797 /* If this VR has extra 2 byte reserved space, then
798 we need to write VR and VL with 4 bytes each, other wise with 2 bytes each. */
799 unsigned int bsize=2+dcmVRReserved(vr);
800
801 char buf[10];
802
803 /* Write VR */
804 memcpy(buf, dcmVRName(vr), 2); buf[2]=buf[3]=(char)0;
805 if(fwrite(buf, bsize, 1, fp)!=1) return(2);
806 if(n!=NULL) *n+=bsize;
807
808 /* Write VL */
809 memcpy(buf, &vl, bsize);
810 if(bsize==2) buf[2]=buf[3]=(char)0;
811 if(!little_endian()) swap(buf, buf, bsize);
812 if(fwrite(buf, bsize, 1, fp)!=1) return(2);
813 if(n!=NULL) *n+=bsize;
814
815 return(0);
816}

Referenced by dcmFileWrite().