TPCCLIB
Loading...
Searching...
No Matches
dcmio.c
Go to the documentation of this file.
1
4/*****************************************************************************/
5#include "tpcclibConfig.h"
6/*****************************************************************************/
7#include <stdio.h>
8#include <stdlib.h>
9#include <math.h>
10#include <time.h>
11#include <string.h>
12/*****************************************************************************/
13#include "tpcextensions.h"
14/*****************************************************************************/
15#include "tpcdcm.h"
16/*****************************************************************************/
17
18/*****************************************************************************/
28 const char *filename,
35 FILE *fp
36) {
37 FILE *lfp;
38
39 if(filename==NULL && fp==NULL) return(0);
40 if(fp!=NULL) {
41 lfp=fp; rewind(lfp);
42 } else {
43 lfp=fopen(filename, "rb");
44 }
45 if(lfp==NULL) return(0);
46
47 /* Skip the first 128 bytes */
48 if(fseek(lfp, 128, SEEK_SET)) {if(fp==NULL) fclose(lfp); return(0);}
49
50 /* Read the next 4 bytes as characters */
51 char buf[5];
52 size_t n=fread(&buf, 1, 4, lfp);
53 buf[4]=(char)0;
54 //if(fp==NULL) fclose(lfp); else rewind(lfp);
55 if(n!=(size_t)4) {rewind(lfp); return(0);}
56
57 /* Check the magic number */
58 if(strncmp(buf, "DICM", 4)==0) {
59 if(fp==NULL) fclose(lfp);
60 return(1);
61 } else {
62 if(fp==NULL) fclose(lfp); else rewind(lfp);
63 return(0);
64 }
65}
66/*****************************************************************************/
67
68/*****************************************************************************/
77 FILE *fp
78) {
79 if(fp==NULL || feof(fp)) return(DCM_TRUID_INVALID);
80 /* Save original file position */
81 fpos_t opos;
82 if(fgetpos(fp, &opos)) return(DCM_TRUID_INVALID);
83 /* Read file until we find DICOM tag 0x0002,0x0010 */
84 DCMTAG tag;
85 int tag_found=0;
86 while(!tag_found && !feof(fp)) {
87 //printf("reading tag\n");
88 if(dcmReadFileTag(fp, &tag)) break;
89 //printf(" -> (%04x,%04x)\n", tag.group, tag.element);
90 if(tag.group==0x0002 && tag.element==0x0010) {tag_found=1; break;}
91 /* not the tag that we want, so just go through this item */
92 //printf("reading vr etc\n");
93 dcmvr vr=dcmReadFileVR(fp, NULL);
94 //printf("-> %s\n", dcmVRName(vr));
95 unsigned int vl=0;
96 if(dcmVRReserved(vr)==0) vl=dcmReadFileVL(fp, 2);
97 else vl=dcmReadFileVL(fp, 4);
98 //printf("reserved=%d\n", dcmVRReserved(vr));
99 if(vr==DCM_VR_SQ) break;
100 //printf("huuh\n");
101 if(vl==0xFFFFFFFF) break;
102 char buf[vl+1];
103 //printf("read buf length %d\n", vl);
104 if(fread(buf, 1, vl, fp)!=vl) break;
105 } // get next tag
106 //printf("end of loop\n");
107 if(!tag_found) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
108 /* Read the UID */
109 //printf("reading vr\n");
110 if(dcmReadFileVR(fp, NULL)!=DCM_VR_UI) {
111 fsetpos(fp, &opos); return(DCM_TRUID_INVALID);
112 }
113 //printf("reading vl\n");
114 unsigned int vl=dcmReadFileVL(fp, 2);
115 if(vl==0 || vl==0xFFFFFFFF) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
116 char uid[vl+1];
117 //printf("reading uid\n");
118 if(fread(uid, 1, vl, fp)!=vl) {fsetpos(fp, &opos); return(DCM_TRUID_INVALID);}
119 /* Return file position to the original */
120 fsetpos(fp, &opos);
121 /* Identify the UID */
122 return(dcmTrUID(uid));
123}
124/*****************************************************************************/
125
126/*****************************************************************************/
137 FILE *fp,
140 DCMTAG *tag
141) {
142 if(tag!=NULL) {tag->group=tag->element=0xFFFC;} // padding
143 if(fp==NULL || feof(fp)) return(1);
144 unsigned short int buf[2];
145 size_t n=fread(&buf, 2, 2, fp);
146 if(n!=2) return(2+n);
147 if(tag!=NULL) {
148 tag->group=buf[0];
149 tag->element=buf[1];
150 if(!endianLittle()) { // tag is by default little endian
151 swap(&tag->group, &tag->group, 2);
152 swap(&tag->element, &tag->element, 2);
153 }
154 }
155 return(0);
156}
157/*****************************************************************************/
158
159/*****************************************************************************/
167 FILE *fp,
169 DCMTAG *tag
170) {
171 if(fp==NULL || tag==NULL) return(TPCERROR_FAIL);
172 unsigned short int buf[2];
173 buf[0]=tag->group;
174 buf[1]=tag->element;
175 if(!endianLittle()) swabip(buf, 4); // tag is by default little endian
176 if(fwrite(&buf, 2, 2, fp)!=2) return TPCERROR_CANNOT_WRITE;
177 return(TPCERROR_OK);
178}
179/*****************************************************************************/
180
181/*****************************************************************************/
193 FILE *fp
194) {
195 if(fp==NULL) return(TPCERROR_FAIL);
196 int ret;
197 DCMTAG tag;
198 tag.group=0xFFFE; tag.element=0xE0DD;
199 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
200 tag.group=0x0000; tag.element=0x0000;
201 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
202 return(TPCERROR_OK);
203}
204/*****************************************************************************/
205
206/*****************************************************************************/
218 FILE *fp
219) {
220 if(fp==NULL) return(TPCERROR_FAIL);
221 int ret;
222 DCMTAG tag;
223 tag.group=0xFFFE; tag.element=0xE00D;
224 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
225 tag.group=0x0000; tag.element=0x0000;
226 ret=dcmWriteFileTag(fp, &tag); if(ret!=TPCERROR_OK) return(ret);
227 return(TPCERROR_OK);
228}
229/*****************************************************************************/
230
231/*****************************************************************************/
239 FILE *fp,
242 char *vrstr
243) {
244 if(vrstr!=NULL) vrstr[0]=(char)0;
245 if(fp==NULL) return(DCM_VR_INVALID);
246
247 /* Read the first two bytes */
248 char buf[3];
249 if(fread(&buf, 1, 2, fp)!=2) return(DCM_VR_INVALID);
250 buf[2]=(char)0;
251
252 /* Identify the VR */
253 dcmvr lvr=dcmVRId(buf);
254 if(vrstr!=NULL) {
255 if(lvr!=DCM_VR_INVALID) strcpy(vrstr, dcmVRName(lvr));
256 else strcpy(vrstr, buf);
257 }
258
259 /* If this VR has extra 2 byte reserved space, then
260 we need to read but do not use the next 2 bytes. */
261 if(dcmVRReserved(lvr)!=0) {
262 if(fread(&buf, 1, 2, fp)!=2) return(DCM_VR_INVALID);
263 }
264 return(lvr);
265}
266/*****************************************************************************/
267
268/*****************************************************************************/
274unsigned int dcmReadFileVL(
276 FILE *fp,
278 unsigned int n
279) {
280 unsigned int vl=0;
281 if(fp==NULL || (n!=2 && n!=4)) return(vl);
282
283 /* Read 2 or 4 bytes */
284 if(n==2) {
285 unsigned short int si;
286 if(fread(&si, 2, 1, fp)!=1) return(vl);
287 if(!endianLittle()) swap(&si, &si, 2);
288 vl=si;
289 } else if(n==4) {
290 unsigned int li;
291 if(fread(&li, 4, 1, fp)!=1) return(vl);
292 if(!endianLittle()) swap(&li, &li, 4);
293 vl=li;
294 }
295 return(vl);
296}
297/*****************************************************************************/
298
299/*****************************************************************************/
308 FILE *fp,
310 dcmvr *vr,
312 unsigned int *vl,
314 unsigned int *n
315) {
316 if(vr!=NULL) *vr=DCM_VR_INVALID;
317 if(vl!=NULL) *vl=0;
318 if(n!=NULL) *n=0;
319 if(fp==NULL) return(TPCERROR_FAIL);
320
321 /* Read the first two bytes */
322 char buf[3];
323 if(fread(&buf, 1, 2, fp)!=2) return(TPCERROR_CANNOT_READ); else if(n!=NULL) *n+=2;
324 buf[2]=(char)0;
325
326 /* Identify the VR */
327 dcmvr lvr=dcmVRId(buf);
328 if(vr!=NULL) *vr=lvr;
329 if(lvr==DCM_VR_INVALID) return(TPCERROR_UNSUPPORTED);
330
331 /* If this VR has extra 2 byte reserved space, then
332 we need to read but do not use the next 2 bytes. */
333 unsigned int bsize=2+dcmVRReserved(lvr);
334 if(bsize==4) {
335 if(fread(&buf, 1, 2, fp)!=2) return(TPCERROR_CANNOT_READ);
336 if(n!=NULL) *n+=2;
337 }
338
339 /* Read VL from the next 2 or 4 bytes */
340 unsigned int lvl=0;
341 if(bsize==2) {
342 unsigned short int si;
343 if(fread(&si, 2, 1, fp)!=1) return(TPCERROR_CANNOT_READ);
344 if(!endianLittle()) swap(&si, &si, 2);
345 lvl=si;
346 } else {
347 unsigned int li;
348 if(fread(&li, 4, 1, fp)!=1) return(TPCERROR_CANNOT_READ);
349 if(!endianLittle()) swap(&li, &li, 4);
350 lvl=li;
351 }
352 if(n!=NULL) *n+=bsize;
353 if(vl!=NULL) *vl=lvl;
354
355 return(TPCERROR_OK);
356}
357/*****************************************************************************/
358
359/*****************************************************************************/
368 FILE *fp,
370 dcmvr vr,
372 unsigned int vl,
374 unsigned int *n
375) {
376 if(n!=NULL) *n=0;
377 if(fp==NULL || vr==DCM_VR_INVALID) return(TPCERROR_FAIL);
378
379 /* If this VR has extra 2 byte reserved space, then
380 we need to write VR and VL with 4 bytes each, other wise with 2 bytes each. */
381 unsigned int bsize=2+dcmVRReserved(vr);
382
383 char buf[10];
384
385 /* Write VR */
386 memcpy(buf, dcmVRName(vr), 2); buf[2]=buf[3]=(char)0;
387 if(fwrite(buf, bsize, 1, fp)!=1) return(TPCERROR_CANNOT_WRITE);
388 if(n!=NULL) *n+=bsize;
389
390 /* Write VL */
391 memcpy(buf, &vl, bsize);
392 if(bsize==2) buf[2]=buf[3]=(char)0;
393// if(!endianLittle()) swabip(buf, bsize);
394 if(!endianLittle()) swap(buf, buf, bsize);
395 if(fwrite(buf, bsize, 1, fp)!=1) return(TPCERROR_CANNOT_WRITE);
396 if(n!=NULL) *n+=bsize;
397
398 return(TPCERROR_OK);
399}
400/*****************************************************************************/
401
402/*****************************************************************************/
411 DCMFILE *dcm,
413 DCMITEM *prev_item,
415 DCMITEM *parent_item,
417 const short int sub,
419 const short int headerOnly,
421 int verbose
422) {
423 if(verbose>0) printf("%s(DCMFILE*, DCMITEM*, DCMITEM*, %d, %d)\n", __func__, sub, headerOnly);
424 if(dcm==NULL || dcm->fp==NULL) return(TPCERROR_FAIL);
425 if(sub!=0 && parent_item==NULL) return(TPCERROR_FAIL);
426 if(feof(dcm->fp)) return(TPCERROR_NO_KEY);
427
428 /* Check whether we currently support the Transfer UID */
429 switch(dcm->truid) {
430 case DCM_TRUID_LEE:
431 break;
432 case DCM_TRUID_LEI: // actually not supported yet
433 break;
434 default:
435 return(TPCERROR_UNSUPPORTED);
436 }
437
438 if(verbose>10) {
439 if(dcm->item==NULL) printf(" will add first element\n");
440 else if(sub==0) printf(" will add next element\n");
441 else printf(" will add sub-element\n");
442 }
443
444 /* Is this a child to a sequence element? */
445 int sq_child=0;
446 if(parent_item!=NULL && parent_item->vr==DCM_VR_SQ) {sq_child=1;}
447 if(verbose>10 && sq_child!=0) printf(" we're a child to a sequence element\n");
448
449 /* Allocate memory for the new element */
450 DCMITEM *item=(DCMITEM*)malloc(sizeof(DCMITEM));
451 if(item==NULL) return(TPCERROR_OUT_OF_MEMORY);
452 item->prev_item=prev_item;
453 item->parent_item=parent_item;
454 item->next_item=item->child_item=(DCMITEM*)NULL;
455 item->fp=dcm->fp; item->truid=dcm->truid;
456 item->rd=(char*)NULL;
457
458 /* Save current file position (should be the start of element) */
459 if(fgetpos(dcm->fp, &item->pos)) {
460 free(item); return(TPCERROR_CANNOT_READ);
461 }
462
463 /* Read the tag (2x2 bytes) */
464 if(verbose>10) {
465 long long int tagpos=ftello(dcm->fp);
466 printf(" reading tag at %lld\n", tagpos);
467 }
468 if(dcmReadFileTag(dcm->fp, &item->tag)) {
469 if(verbose>1 && !feof(dcm->fp)) printf(" error in reading the tag.\n");
470 free(item);
471 if(feof(dcm->fp)) return(TPCERROR_NO_KEY);
472 return(TPCERROR_CANNOT_READ);
473 }
474
475 if(verbose>2) {
476 printf(" tag(%04x,%04x) with %u parents\n",
477 item->tag.group, item->tag.element, dcmitemParentNr(item));
478 }
479
480 /* If child, then check for item delimitation tag (although it should not be here) */
481 if(dcmitemParentNr(item)>0 && item->tag.group==0xFFFE && item->tag.element==0xE00D) {
482 if(verbose>10)
483 printf(" item delimitation tag(%04x,%04x) found, reading VL\n",
484 item->tag.group, item->tag.element);
485 unsigned long int vl=dcmReadFileVL(dcm->fp, 4);
486 if(verbose>1) printf(" item delimitation tag VL := %lu (0x%08lx)\n", vl, vl);
487 if(vl!=0) {
488 if(verbose>1) printf(" error: VL should have been 0\n");
490 }
491 return(TPCERROR_OK);
492 }
493
494
495 /* Read value representation and length (VR and VL, 2x2 or 2x4 bytes) */
496 if(item->tag.group==0x0002 || dcm->truid==DCM_TRUID_LEE) {
497 // Group 0x0002 is always DCM_TRUID_LEE, the other groups are specified by
498 // the Transfer Syntax UID
499 if(verbose>10) printf(" reading VR and VL\n");
500 int ret;
501 unsigned int n;
502 ret=dcmReadFileVRVL(dcm->fp, &item->vr, &item->vl, &n);
503 if(ret!=TPCERROR_OK) {
504 if(verbose>1) printf(" invalid VR or VL\n");
505 free(item); return(ret);
506 }
507 if(verbose>1) {
508 printf(" VR := %s (%s)\n", dcmVRName(item->vr), dcmVRDescr(item->vr));
509 printf(" VL := %u (0x%08x) (%d bytes field)\n", item->vl, item->vl, n/2);
510 fflush(stdout);
511 }
512 } else if(dcm->truid==DCM_TRUID_LEI) {
513 if(verbose>10) printf(" set VR based on the tag\n");
514 unsigned int i=dcmDictFindTag(&item->tag);
515 item->vr=dcmVRId(dcmDictIndexVR(i));
516 if(item->vr!=DCM_VR_INVALID) {
517 if(verbose>1) {
518 printf(" VR := %s (%s)\n", dcmVRName(item->vr), dcmVRDescr(item->vr));
519 fflush(stdout);
520 }
521 } else {
522 if(verbose>1) printf(" VR not known for tag(%04x,%04x)\n",
523 item->tag.group, item->tag.element);
524 }
525 if(verbose>10) printf(" reading VL\n");
526 item->vl=dcmReadFileVL(dcm->fp, 4);
527 if(verbose>1) {
528 printf(" VL := %u (0x%08x)\n", item->vl, item->vl);
529 fflush(stdout);
530 }
531 }
532
533 /* Read value field, and add the current element to the list */
534 if(item->vr==DCM_VR_SQ) {
535 if(ftello(dcm->fp)<0) return(TPCERROR_INVALID_FORMAT);
536 unsigned long long int sqPos=(unsigned long int)ftello(dcm->fp);
537 if(verbose>10) {printf(" sequence... at %llu\n", sqPos); fflush(stdout);}
538 unsigned long int sqContentLength=item->vl;
539 if(verbose>12) printf(" sequence contents length is %lu\n", sqContentLength);
540 /* File position is now at the start of first item in the sequence */
541 int ret;
542 /* If parent has no previous child, then define this as its child */
543 if(sq_child!=0 && parent_item->child_item==NULL) {
544 parent_item->child_item=item;
545 } else {
546 /* else, add SQ sequence itself as next element to the list, and later
547 add each sequence item as child to it */
548 if(prev_item==NULL) {
549 if(dcm->item==NULL) { // truly the first item
550 dcm->item=item;
551 } else { // search for the previous one
552 DCMITEM *ip; ip=dcm->item;
553 while(ip->next_item!=NULL) ip=ip->next_item;
554 ip->next_item=item; item->prev_item=ip;
555 }
556 } else {
557 prev_item->next_item=item; item->prev_item=prev_item;
558 }
559 }
560 /* Read the first item tag and length, but there is no VR to read this time */
561 if(verbose>10) {
562 long long int tagpos=ftello(dcm->fp);
563 printf(" reading first item tag at %lld\n", tagpos);
564 }
565 DCMTAG itemtag;
566 ret=dcmReadFileTag(dcm->fp, &itemtag);
567 if(ret!=0) {
568 if(verbose>1) printf(" error %d in reading the tag.\n", ret);
569 return(TPCERROR_CANNOT_READ);
570 }
571 if(verbose>1) printf(" item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
572 /* It is common that sequence is empty; check it first */
573 if(itemtag.group==0xFFFE && (itemtag.element==0xE0DD || itemtag.element==0xE00D)) {
574 /* yes; then read also the 4 byte LV, which should be zero */
575 if(verbose>10)
576 printf(" sequence delimitation item tag(%04x,%04x) found, reading VL\n",
577 itemtag.group, itemtag.element);
578 unsigned long int vl=dcmReadFileVL(dcm->fp, 4);
579 if(verbose>1) printf(" item tag VL := %lu (0x%08lx)\n", vl, vl);
580 if(vl!=0) {
581 if(verbose>1) printf(" error: VL should have been 0\n");
583 }
584 if(verbose>3) printf(" ending sequence before it really started.\n");
585 return(TPCERROR_OK);
586 }
587 /* If sequence actually contains something, the Item tag must be 0xFFFE,0xE000 */
588 if(itemtag.group!=0xFFFE || itemtag.element!=0xE000) {
589 if(verbose>1) printf(" invalid sequence item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
590 return(TPCERROR_INVALID_FORMAT); //return(TPCERROR_OK);
591 }
592 /* Read past the VL of this item (always 4 bytes) */
593 unsigned long int itemvl=dcmReadFileVL(dcm->fp, 4);
594 if(verbose>3) {printf(" item_VL := %lu (0x%08lx)\n", itemvl, itemvl);}
595 if(ftello(dcm->fp)<0) return(TPCERROR_INVALID_FORMAT);
596 unsigned long int sqItemPos=(unsigned long int)ftell(dcm->fp);
597 /* Check if that is all of this sequence (probably Siemens) */
598 if((sqItemPos-sqPos)>=sqContentLength) {
599 if(verbose>3) printf(" ending sequence since it was found to be empty.\n");
600 return(TPCERROR_OK);
601 }
602 if(verbose>12) printf(" sequence content start position at %ld\n", sqItemPos);
603 /* Read the first item value as its own element, adding it as child to SQ */
604 ret=dcmFileReadNextElement(dcm, NULL, item, 1, headerOnly, verbose-1);
605 if(ret!=TPCERROR_OK) {
606 if(verbose>1) printf(" error in reading the first item value dataset\n");
607 return(ret);
608 }
609 /* Now we continue reading more items, until we reach Sequence Delimitation Item */
610 while(!feof(dcm->fp)) {
611 /* Do not read pass the length of the sequence data */
612 if(ftello(dcm->fp)<0) return(TPCERROR_INVALID_FORMAT);
613 unsigned long long int cPos=(unsigned long long int)ftello(dcm->fp);
614 if(sqContentLength>0 && (cPos-sqPos)>=sqContentLength) {
615 if(verbose>3) printf(" we reached the end of sequence VL %lu\n", sqContentLength);
616 /* set fake sequence delimitation tag */
617 itemtag.group=0xFFFE; itemtag.element=0xE0DD;
618 break;
619 }
620 if(verbose>10) {
621 long long int tagpos=ftello(dcm->fp);
622 printf(" reading next sequence item tag at %lld, %lld after start\n", tagpos, tagpos-sqItemPos);
623 }
624 if(dcmReadFileTag(dcm->fp, &itemtag)) return(TPCERROR_CANNOT_READ);
625 if(verbose>1) printf(" next item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
626 itemvl=dcmReadFileVL(dcm->fp, 4); // delimitation tag has this too
627 if(verbose>3) {printf(" item_VL := %lu (0x%08lx)\n", itemvl, itemvl);}
628 /* Check if we got sequence delimitation tag */
629 if(itemtag.group==0xFFFE && itemtag.element==0xE0DD)
630 {
631 if(verbose>3) printf(" we got sequence delimitation tag\n");
632 break;
633 }
634 /* Check if we got item delimitation tag from the previous item */
635 if(itemtag.group==0xFFFE && itemtag.element==0xE00D)
636 {
637 if(verbose>3) printf(" we got item delimitation tag\n");
638 if(itemvl!=0) {
639 if(verbose>1) printf(" error: VL should have been 0\n");
641 }
642 continue;
643 }
644 /* Otherwise this should be sequence item tag */
645 if(itemtag.group!=0xFFFE || itemtag.element!=0xE000) {
646 if(verbose>3) printf(" not sequence item tag, move file position back 2x4 bytes\n");
647 fseeko(dcm->fp, -8, SEEK_CUR); //return(TPCERROR_INVALID_VALUE);
648 }
649 /* Read the item value as its own element, adding it to the SQ child list */
650 DCMITEM *child=item->child_item;
651 if(child==NULL) {
652 if(verbose>1) printf(" error had happened in adding the child element\n");
653 return(TPCERROR_UNSUPPORTED);
654 }
655 while(child->next_item!=NULL) child=child->next_item;
656 ret=dcmFileReadNextElement(dcm, child, item, 0, headerOnly, verbose-1);
657 if(ret!=TPCERROR_OK) {
658 if(verbose>1) printf(" error in reading item value dataset\n");
659 return(ret);
660 }
661 }
662 /* Check that loop really stopped at sequence delimitation item */
663 /* 0xE00D means the end of item, 0xE0DD the end of sequence. */
664 if(itemtag.group!=0xFFFE || itemtag.element!=0xE0DD) {
665 if(verbose>1)
666 printf(" invalid sequence delimitation item tag(%04x,%04x)\n", itemtag.group, itemtag.element);
667 return(TPCERROR_UNSUPPORTED);
668 }
669 /* Done. Do not free item! */
670 if(verbose>10) {printf(" end of sequence.\n"); fflush(stdout);} //return(TPCERROR_OK);
671 } else if(item->vl!=0xFFFFFFFF) {
672 if(verbose>10) {printf(" reading value of %u bytes...\n", item->vl); fflush(stdout);}
673 char *buf=NULL;
674 if(item->vl>0) {
675 buf=(char*)calloc(item->vl+1, sizeof(char));
676 if(buf==NULL) {free(item); return(TPCERROR_OUT_OF_MEMORY);}
677 if(fread(buf, 1, item->vl, item->fp)!=item->vl) {
678 free(item); free(buf); return(TPCERROR_NO_VALUE);
679 }
680 /* Do not store pixel data, if that was the request */
681 if(headerOnly!=0 &&
682 ((item->tag.group==0x7FE0 && item->tag.element>0) || item->tag.group==0x7FE1))
683 {
684 if(verbose>5) {printf(" ...not storing pixel data\n"); fflush(stdout);}
685 free(buf); buf=(char*)NULL;
686 } else {
687 item->rd=buf;
688 }
689 } else if(verbose>4) {
690 printf(" VL=0\n");
691 }
692 /* Add to list */
693 if(sub==0) {
694 if(prev_item==NULL) {
695 if(dcm->item==NULL) { // truly the first item
696 dcm->item=item;
697 } else { // search for the previous one
698 DCMITEM *ip; ip=dcm->item;
699 while(ip->next_item!=NULL) ip=ip->next_item;
700 ip->next_item=item; item->prev_item=ip;
701 }
702 } else {
703 prev_item->next_item=item; item->prev_item=prev_item;
704 }
705 } else { // add as child
706 parent_item->child_item=item; item->parent_item=parent_item;
707 }
708 /* Print tag and its value */
709 if(verbose>1) {
710 char *tagval=dcmValueString(item);
711 printf(" (%04x,%04x) %s := %s\n", item->tag.group, item->tag.element,
712 dcmDictIndexDescr(dcmDictFindTag(&item->tag)), tagval);
713 free(tagval);
714 }
715 /* Done. Do no free item or buf! */
716 return(TPCERROR_OK);
717
718 } else { // VL=0xFFFFFFFF
719 size_t s=dcmVRVLength(item->vr);
720 if(s==0) {
721 if(verbose>0) printf(" Unknown VL!!\n");
722 free(item);
723 return(TPCERROR_INVALID_VALUE); //return(TPCERROR_OK);
724 }
725 if(verbose>4) printf(" VR_based_VL=%u\n", (unsigned int)s);
726 char *buf=(char*)calloc(s+1, sizeof(char));
727 if(buf==NULL) {free(item); return(TPCERROR_OUT_OF_MEMORY);}
728 if(fread(buf, 1, s, item->fp)!=s) {
729 free(item); free(buf); return(TPCERROR_NO_VALUE);
730 }
731 item->rd=buf;
732 /* Add to list */
733 if(sub==0) {
734 if(prev_item==NULL) {
735 if(dcm->item==NULL) { // truly the first item
736 dcm->item=item;
737 } else { // search for the previous one
738 DCMITEM *ip; ip=dcm->item;
739 while(ip->next_item!=NULL) ip=ip->next_item;
740 ip->next_item=item; item->prev_item=ip;
741 }
742 } else {
743 prev_item->next_item=item; item->prev_item=prev_item;
744 }
745 } else { // add as child
746 parent_item->child_item=item; item->parent_item=parent_item;
747 }
748 /* Print tag and its value */
749 if(verbose>1) {
750 char *tagval=dcmValueString(item);
751 printf(" (%04x,%04x) %s := %s\n", item->tag.group, item->tag.element,
752 dcmDictIndexDescr(dcmDictFindTag(&item->tag)), tagval);
753 free(tagval);
754 }
755 /* Done. Do no free item or buf! */
756 return(TPCERROR_OK);
757 }
758
759 return(TPCERROR_OK);
760}
761/*****************************************************************************/
762
763/*****************************************************************************/
770 const char *filename,
772 DCMFILE *dcm,
774 const short int headerOnly,
776 TPCSTATUS *status
777) {
778 int verbose=0; if(status!=NULL) verbose=status->verbose;
779 if(filename==NULL || strnlen(filename, 10)<1 || dcm==NULL) {
780 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
781 return TPCERROR_FAIL;
782 }
783 if(verbose>1) printf("%s('%s', %d)\n", __func__, filename, headerOnly);
784
785 /* Delete any previous data */
786 dcmfileFree(dcm);
787
788 /* Open the file */
789 strlcpy(dcm->filename, filename, FILENAME_MAX);
790 dcm->fp=fopen(dcm->filename, "rb");
791 if(dcm->fp==NULL) {
792 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_OPEN);
794 }
795
796 /* Check the magic number and move file pointer to the end of it */
797 if(verbose>2) printf("checking DICOM magic number\n");
798 if(dcmVerifyMagic(NULL, dcm->fp)!=1) {
799 fclose(dcm->fp);
800 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FORMAT);
802 }
803
804 /* Get the Transfer Syntax UID */
805 if(verbose>2) printf("checking Transfer Syntax UID\n");
807 if(dcm->truid==DCM_TRUID_INVALID) { // not found
808 fclose(dcm->fp);
809 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_INVALID_FORMAT);
811 }
812 if(verbose>0) { // print the UID
813 printf("Transfer Syntax UID := %s\n", dcmTrUIDDescr(dcm->truid));
814 fflush(stdout);
815 }
816
817 /* Check whether we currently support the Transfer UID */
818 switch(dcm->truid) {
819 case DCM_TRUID_LEE:
820 case DCM_TRUID_LEI: // actually not supported yet
821 break;
822 default:
823 fclose(dcm->fp);
824 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
826 }
827
828 /* Read DICOM file elements */
829 int ret=TPCERROR_OK;
830 do {
831 // note that the next function may need to call itself,
832 // therefore counting loops here would not be useful.
833 ret=dcmFileReadNextElement(dcm, NULL, NULL, 0, headerOnly, verbose-10);
834 } while(ret==TPCERROR_OK && !feof(dcm->fp));
835 fclose(dcm->fp);
836 /* TPCERROR_NO_KEY means that no (more) tag was found;
837 other codes still mean that something bad happened. */
838 if(ret==TPCERROR_NO_KEY) {
839 if(verbose>1) printf(" eof\n");
840 ret=TPCERROR_OK;
841 }
842 statusSet(status, __func__, __FILE__, __LINE__, ret);
843 return(ret);
844}
845/*****************************************************************************/
846
847/*****************************************************************************/
854 const char *filename,
856 DCMFILE *dcm,
858 TPCSTATUS *status
859) {
860 int verbose=0; if(status!=NULL) verbose=status->verbose;
861 if(filename==NULL || strnlen(filename, 10)<1 || dcm==NULL) {
862 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_FAIL);
863 return TPCERROR_FAIL;
864 }
865 if(verbose>1) {printf("%s('%s')\n", __func__, filename); fflush(stdout);}
866
867 /* Check for the data */
868 if(dcm->item==NULL) {
869 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
870 return TPCERROR_NO_DATA;
871 }
872
873 /* Check whether we currently support the Transfer UID */
874 if(dcm->truid!=DCM_TRUID_LEE) { // Little endian explicit
875 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_UNSUPPORTED);
877 }
878
879
880 /* Open the file */
881 if(verbose>1) printf("opening the file for writing\n");
882 FILE *fp;
883 fp=fopen(filename, "wb");
884 if(fp==NULL) {
885 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
887 }
888
889 /* Write preamble (just 128 zeroes) and magic number */
890 {
891 if(verbose>1) printf("writing preamble\n");
892 char buf1[128], buf2[5];
893 for(int i=0; i<128; i++) buf1[i]=(char)0;
894 strcpy(buf2, "DICM");
895 if(fwrite(buf1, 128, 1, fp)<1 || fwrite(buf2, 4, 1, fp)<1) {
896 fclose(fp); statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
898 }
899 }
900
901
902 /* Write the contents */
903 if(verbose>1) printf("writing DICOM contents\n");
904 int ret=0;
905 DCMITEM *iptr;
906 DCMITEM *d1=dcm->item;
907 while(d1!=NULL) {
908 if(verbose>2) {dcmitemPrint(d1);}
909 /* Write */
910 iptr=d1;
911 {
912 size_t n;
913 /* Write tag */
914 if(dcmWriteFileTag(fp, &iptr->tag)!=TPCERROR_OK) {ret=1; break;}
915 /* Write VR and VL */
916 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, NULL)!=TPCERROR_OK) {ret=2; break;}
917 /* Write value, unless zero length, or SQ, in which case written later */
918 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
919 size_t len;
920 if(iptr->vl==0xFFFFFFFF) {
921 len=dcmVRVLength(iptr->vr);
922 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
923 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
924 } else {
925 len=iptr->vl;
926 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
927 n=fwrite(iptr->rd, iptr->vl, 1, fp);
928 }
929 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
930 if(n!=1) {ret=4; break;}
931 } else if(iptr->vr==DCM_VR_SQ && d1->child_item==NULL) {
932 if(verbose>1) printf("SQ, but no contents to write!\n");
933 /* Write Sequence Delimitation Item */
934 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=6; break;}
935 }
936 }
937
938 /* If this element (SQ) has children, then write those */
939 /* Data Elements with a group of 0000, 0002 and 0006 shall not be present within Sequence Items,
940 but that is not verified here */
941 if(d1->child_item!=NULL) {
942 DCMITEM *d2=d1->child_item;
943 unsigned int d2counter=0;
944 while(d2!=NULL) {
945 if(verbose>2) {printf(" "); dcmitemPrint(d2);}
946
947 /* Write */
948 iptr=d2;
949
950 /* First, write Item tag (FFFE,E000) */
951 if(d2counter==0) {
952 DCMTAG tag; tag.group=0xFFFE; tag.element=0xE000;
953 if(dcmWriteFileTag(fp, &tag)!=TPCERROR_OK) {ret=11; break;}
954 }
955 /* Write item length; write 0xFFFFFFFF for now, correct later when known */
956 fpos_t d2ilpos; // position for item length
957 unsigned int d2il=0; // item length
958 if(d2counter==0) {
959 if(fgetpos(fp, &d2ilpos)) {ret=12; break;} // save position for writing later
960 unsigned int ibuf;
961 ibuf=0xFFFFFFFF;
962 if(fwrite(&ibuf, 4, 1, fp)!=1) {ret=13; break;}
963 }
964 d2counter++;
965
966 /* Write item value data set */
967 {
968 /* Write tag */
969 if(dcmWriteFileTag(fp, &iptr->tag)!=TPCERROR_OK) {ret=14; break;}
970 d2il+=4;
971 /* Write VR and VL */
972 unsigned int s;
973 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, &s)!=TPCERROR_OK) {ret=15; break;}
974 d2il+=s;
975 /* Write value, unless zero length, or SQ, in which case written later */
976 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
977 size_t len, n;
978 if(iptr->vl==0xFFFFFFFF) {
979 len=dcmVRVLength(iptr->vr);
980 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
981 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
982 d2il+=len;
983 } else {
984 len=iptr->vl;
985 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
986 n=fwrite(iptr->rd, iptr->vl, 1, fp);
987 d2il+=iptr->vl;
988 }
989 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
990 if(n!=1) {ret=17; break;}
991 } else if(iptr->vr==DCM_VR_SQ && iptr->child_item==NULL) {
992 if(verbose>1) printf("SQ, but no contents to write!\n");
993 /* Write Sequence Delimitation Item */
994 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=19; break;}
995 }
996 }
997
998 /* If this element has children, then write those */
999 if(d2->child_item!=NULL) {
1000 DCMITEM *d3=d2->child_item;
1001 unsigned int d3counter=0;
1002 while(d3!=NULL) {
1003 if(verbose>2) {printf(" "); dcmitemPrint(d3);}
1004
1005 /* Write */
1006 iptr=d3;
1007 if(iptr->vr==DCM_VR_SQ) {d3=d3->next_item; continue;} // for now do not write SQs
1008
1009 /* First, write Item tag (FFFE,E000) */
1010 if(d3counter==0) {
1011 DCMTAG tag; tag.group=0xFFFE; tag.element=0xE000;
1012 if(dcmWriteFileTag(fp, &tag)!=TPCERROR_OK) {ret=31; break;}
1013 d2il+=4;
1014 }
1015 /* Write item length; write 0xFFFFFFFF for now, correct later when known */
1016 fpos_t d3ilpos; // position for item length
1017 unsigned int d3il=0; // item length
1018 if(d3counter==0) {
1019 unsigned int ibuf;
1020 if(fgetpos(fp, &d3ilpos)) {ret=32; break;} // save position for writing later
1021 ibuf=0xFFFFFFFF;
1022 if(fwrite(&ibuf, 4, 1, fp)!=1) {ret=33; break;}
1023 d2il+=4;
1024 }
1025 d3counter++;
1026
1027 /* Write item value data set */
1028 {
1029 /* Write tag */
1030 if(dcmWriteFileTag(fp, &iptr->tag)!=TPCERROR_OK) {ret=34; break;}
1031 d3il+=4; d2il+=4;
1032 /* Write VR and VL */
1033 unsigned int s;
1034 if(dcmWriteFileVRVL(fp, iptr->vr, iptr->vl, &s)!=TPCERROR_OK) {ret=35; break;}
1035 d3il+=s; d2il+=s;
1036 /* Write value, unless zero length, or SQ, in which case written later */
1037 if(iptr->vl>0 && iptr->vr!=DCM_VR_SQ) {
1038 size_t len, n;
1039 if(iptr->vl==0xFFFFFFFF) {
1040 len=dcmVRVLength(iptr->vr);
1041 if(verbose>30) printf(" value_len1 := %u\n", (unsigned int)len);
1042 n=fwrite(iptr->rd, dcmVRVLength(iptr->vr), 1, fp);
1043 d3il+=len; d2il+=len;
1044 } else {
1045 len=iptr->vl;
1046 if(verbose>30) printf(" value_len3 := %u\n", (unsigned int)len);
1047 n=fwrite(iptr->rd, iptr->vl, 1, fp);
1048 d3il+=iptr->vl; d2il+=iptr->vl;
1049 }
1050 if(verbose>30) printf(" value_len := %u\n", (unsigned int)len);
1051 if(n!=1) {ret=37; break;}
1052 } else if(iptr->vr==DCM_VR_SQ && iptr->child_item==NULL) {
1053 if(verbose>1) printf("SQ, but no contents to write!\n");
1054 /* Write Sequence Delimitation Item */
1055 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=39; break;}
1056 d2il+=8;
1057 }
1058 }
1059
1060 /* If this element has children, then write those */
1061 if(d3->child_item!=NULL) {
1062 //DCMITEM *d4=d3->child_item;
1063 if(verbose>0) fprintf(stderr, "Warning: 4th level items not written.\n");
1064 }
1065
1066 /* now that we known the length, write it to the saved position */
1067 if(0) {
1068 fpos_t opos; // current position to return to
1069 if(fgetpos(fp, &opos)) {ret=40; break;}
1070 fsetpos(fp, &d3ilpos); // go to the position for item length
1071 char buf[4];
1072 memcpy(buf, &d3il, 4);
1073 if(!endianLittle()) swabip(buf, 4);
1074 if(fwrite(&buf, 4, 1, fp)!=1) {ret=41; break;}
1075 fsetpos(fp, &opos); // back to the position where we were
1076 }
1077
1078 d3=d3->next_item;
1079 }
1080 if(ret!=0) break;
1081
1082 /* Write Item Delimitation Tag */
1083 if(dcmWriteFileSQItemDelimTag(fp)!=0) {ret=21; break;}
1084 /* End of the sequence - write Sequence Delimitation Item */
1085 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=21; break;}
1086
1087 }
1088
1089
1090 /* now that we known the length, write it to the saved position */
1091 if(0) {
1092 fpos_t opos; // current position to return to
1093 if(fgetpos(fp, &opos)) {ret=18; break;}
1094 fsetpos(fp, &d2ilpos); // go to the position for item length
1095 char buf[4];
1096 memcpy(buf, &d2il, 4);
1097 if(!endianLittle()) swabip(buf, 4);
1098 if(fwrite(&buf, 4, 1, fp)!=1) {ret=19; break;}
1099 fsetpos(fp, &opos); // back to the position where we were
1100 }
1101
1102 d2=d2->next_item;
1103 }
1104 if(ret!=0) break;
1105
1106 /* Write Item Delimitation Tag */
1107 if(dcmWriteFileSQItemDelimTag(fp)!=0) {ret=21; break;}
1108 /* End of the sequence - write Sequence Delimitation Item */
1109 if(dcmWriteFileSQDelimItem(fp)!=TPCERROR_OK) {ret=21; break;}
1110
1111 }
1112
1113 d1=d1->next_item;
1114 } // next
1115 if(ret!=0) {
1116 if(verbose>0) fprintf(stderr, " ret := %d\n", ret);
1117 fclose(fp);
1118 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
1119 return TPCERROR_CANNOT_WRITE;
1120 }
1121
1122
1123 fclose(fp);
1124
1125 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
1126 return(TPCERROR_OK);
1127}
1128/*****************************************************************************/
1129
1130/*****************************************************************************/
void dcmfileFree(DCMFILE *d)
Definition dcmdata.c:67
void dcmitemPrint(DCMITEM *d)
Definition dcmdata.c:467
unsigned short int dcmitemParentNr(DCMITEM *d)
Definition dcmdata.c:122
char * dcmValueString(DCMITEM *d)
Definition dcmdata.c:141
char * dcmDictIndexVR(unsigned int i)
char * dcmDictIndexDescr(unsigned int i)
unsigned int dcmDictFindTag(DCMTAG *tag)
dcmtruid dcmReadTransferSyntaxUID(FILE *fp)
Definition dcmio.c:73
int dcmWriteFileVRVL(FILE *fp, dcmvr vr, unsigned int vl, unsigned int *n)
Definition dcmio.c:366
dcmvr dcmReadFileVR(FILE *fp, char *vrstr)
Definition dcmio.c:237
int dcmReadFileTag(FILE *fp, DCMTAG *tag)
Definition dcmio.c:135
int dcmFileRead(const char *filename, DCMFILE *dcm, const short int headerOnly, TPCSTATUS *status)
Definition dcmio.c:768
int dcmReadFileVRVL(FILE *fp, dcmvr *vr, unsigned int *vl, unsigned int *n)
Definition dcmio.c:306
int dcmFileWrite(const char *filename, DCMFILE *dcm, TPCSTATUS *status)
Definition dcmio.c:852
int dcmFileReadNextElement(DCMFILE *dcm, DCMITEM *prev_item, DCMITEM *parent_item, const short int sub, const short int headerOnly, int verbose)
Definition dcmio.c:409
int dcmWriteFileSQItemDelimTag(FILE *fp)
Definition dcmio.c:216
unsigned int dcmReadFileVL(FILE *fp, unsigned int n)
Definition dcmio.c:274
int dcmWriteFileTag(FILE *fp, DCMTAG *tag)
Definition dcmio.c:165
int dcmVerifyMagic(const char *filename, FILE *fp)
Definition dcmio.c:25
int dcmWriteFileSQDelimItem(FILE *fp)
Definition dcmio.c:191
char * dcmTrUIDDescr(dcmtruid id)
Definition dcmuid.c:87
dcmtruid dcmTrUID(const char *s)
Definition dcmuid.c:66
unsigned char dcmVRReserved(dcmvr id)
Definition dcmvr.c:85
size_t dcmVRVLength(dcmvr id)
Definition dcmvr.c:144
dcmvr dcmVRId(const char *s)
Definition dcmvr.c:103
char * dcmVRName(dcmvr id)
Definition dcmvr.c:126
char * dcmVRDescr(dcmvr id)
Definition dcmvr.c:162
void swabip(void *buf, int size)
Definition endian.c:115
int endianLittle()
Definition endian.c:53
void swap(void *from, void *to, int size)
Definition endian.c:69
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strnlen(const char *s, size_t n)
Definition stringext.c:566
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
dcmtruid truid
Definition tpcdcm.h:162
DCMITEM * item
Definition tpcdcm.h:164
char filename[FILENAME_MAX]
Definition tpcdcm.h:158
FILE * fp
Definition tpcdcm.h:160
dcmtruid truid
Definition tpcdcm.h:135
dcmvr vr
Definition tpcdcm.h:139
struct DCMITEM * child_item
Definition tpcdcm.h:143
struct DCMITEM * next_item
Definition tpcdcm.h:147
unsigned int vl
Definition tpcdcm.h:141
FILE * fp
Definition tpcdcm.h:131
fpos_t pos
Definition tpcdcm.h:133
char * rd
Definition tpcdcm.h:152
struct DCMITEM * prev_item
Definition tpcdcm.h:149
struct DCMITEM * parent_item
Definition tpcdcm.h:145
DCMTAG tag
Definition tpcdcm.h:137
unsigned short int element
Definition tpcdcm.h:44
unsigned short int group
Definition tpcdcm.h:42
int verbose
Verbose level, used by statusPrint() etc.
Header file for libtpcdcm.
dcmvr
Definition tpcdcm.h:91
@ DCM_VR_INVALID
Invalid DICOM value representation.
Definition tpcdcm.h:123
@ DCM_VR_UI
DICOM unique identifier (UID), max 64 bytes.
Definition tpcdcm.h:117
@ DCM_VR_SQ
DICOM sequence of zero or more elements (used for nested data).
Definition tpcdcm.h:112
dcmtruid
Definition tpcdcm.h:57
@ DCM_TRUID_LEI
Little Endian Implicit VR (DICOM default)
Definition tpcdcm.h:59
@ DCM_TRUID_INVALID
Invalid Transfer Syntax UID.
Definition tpcdcm.h:78
@ DCM_TRUID_LEE
Little Endian Explicit VR.
Definition tpcdcm.h:60
Header file for library libtpcextensions.
@ TPCERROR_INVALID_VALUE
Invalid value.
@ TPCERROR_NO_VALUE
Value not found.
@ TPCERROR_FAIL
General error.
@ TPCERROR_INVALID_FORMAT
Invalid file format.
@ TPCERROR_CANNOT_OPEN
Cannot open file.
@ TPCERROR_OUT_OF_MEMORY
Cannot allocate memory.
@ TPCERROR_NO_KEY
Key not found.
@ TPCERROR_UNSUPPORTED
Unsupported file type.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_CANNOT_READ
Cannot read file.
@ TPCERROR_CANNOT_WRITE
Cannot write file.