]> Creatis software - gdcm.git/blob - src/gdcmFile.cxx
* Remove some useless methods in gdcm::Document, gdcm::Header and gdcm::File
[gdcm.git] / src / gdcmFile.cxx
1   /*=========================================================================
2                                                                                 
3   Program:   gdcm
4   Module:    $RCSfile: gdcmFile.cxx,v $
5   Language:  C++
6   Date:      $Date: 2004/11/26 10:55:04 $
7   Version:   $Revision: 1.166 $
8                                                                                 
9   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
10   l'Image). All rights reserved. See Doc/License.txt or
11   http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
12                                                                                 
13      This software is distributed WITHOUT ANY WARRANTY; without even
14      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15      PURPOSE.  See the above copyright notices for more information.
16                                                                                 
17 =========================================================================*/
18
19 #include "gdcmFile.h"
20 #include "gdcmDocument.h"
21 #include "gdcmDebug.h"
22 #include "gdcmUtil.h"
23 #include "gdcmBinEntry.h"
24 #include <fstream>
25
26 namespace gdcm 
27 {
28 typedef std::pair<TagDocEntryHT::iterator,TagDocEntryHT::iterator> IterHT;
29
30 //-------------------------------------------------------------------------
31 // Constructor / Destructor
32 /**
33  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
34  *        file (Header only deals with the ... header)
35  *        Opens (in read only and when possible) an existing file and checks
36  *        for DICOM compliance. Returns NULL on failure.
37  *        It will be up to the user to load the pixels into memory
38  *        (see GetImageData, GetImageDataRaw)
39  * \note  the in-memory representation of all available tags found in
40  *        the DICOM header is post-poned to first header information access.
41  *        This avoid a double parsing of public part of the header when
42  *        user sets an a posteriori shadow dictionary (efficiency can be
43  *        seen as a side effect).   
44  * @param header already built Header
45  */
46 File::File(Header *header)
47 {
48    HeaderInternal = header;
49    SelfHeader = false;
50    Initialise();
51 }
52
53 /**
54  * \brief Constructor dedicated to deal with the *pixels* area of a ACR/DICOMV3
55  *        file (Header only deals with the ... header)
56  *        Opens (in read only and when possible) an existing file and checks
57  *        for DICOM compliance. Returns NULL on failure.
58  *        It will be up to the user to load the pixels into memory
59  *        (see GetImageData, GetImageDataRaw)
60  * \note  the in-memory representation of all available tags found in
61  *        the DICOM header is post-poned to first header information access.
62  *        This avoid a double parsing of public part of the header when
63  *        one sets an a posteriori shadow dictionary (efficiency can be
64  *        seen as a side effect).   
65  * @param filename file to be opened for parsing
66  */
67 File::File(std::string const & filename )
68 {
69    HeaderInternal = new Header( filename );
70    SelfHeader = true;
71    Initialise();
72 }
73
74 /**
75  * \brief Factorization for various forms of constructors.
76  */
77 void File::Initialise()
78 {
79    WriteMode = WMODE_DECOMPRESSED;
80    WriteType = WTYPE_IMPL_VR;
81
82    PixelConverter = new PixelConvert;
83    Archive = new DocEntryArchive( HeaderInternal );
84
85    if ( HeaderInternal->IsReadable() )
86    {
87       PixelConverter->GrabInformationsFromHeader( HeaderInternal );
88    }
89
90    Pixel_Data = 0;
91    ImageDataSize = 0;
92 }
93
94 /**
95  * \brief canonical destructor
96  * \note  If the Header was created by the File constructor,
97  *        it is destroyed by the File
98  */
99 File::~File()
100
101    if( PixelConverter )
102    {
103       delete PixelConverter;
104    }
105    if( Archive )
106    {
107       delete Archive;
108    }
109
110    if( SelfHeader )
111    {
112       delete HeaderInternal;
113    }
114    HeaderInternal = 0;
115 }
116
117 //-----------------------------------------------------------------------------
118 // Print
119
120 //-----------------------------------------------------------------------------
121 // Public
122 /**
123  * \brief   Get the size of the image data
124  * 
125  *          If the image can be RGB (with a lut or by default), the size 
126  *          corresponds to the RGB image
127  * @return  The image size
128  */
129 size_t File::GetImageDataSize()
130 {
131    return PixelConverter->GetRGBSize();
132 }
133
134 /**
135  * \brief   Get the size of the image data
136  * 
137  *          If the image can be RGB by transformation in a LUT, this
138  *          transformation isn't considered
139  * @return  The raw image size
140  */
141 size_t File::GetImageDataRawSize()
142 {
143    return PixelConverter->GetDecompressedSize();
144 }
145
146 /**
147  * \brief   - Allocates necessary memory, 
148  *          - Reads the pixels from disk (uncompress if necessary),
149  *          - Transforms YBR pixels, if any, into RGB pixels
150  *          - Transforms 3 planes R, G, B, if any, into a single RGB Plane
151  *          - Transforms single Grey plane + 3 Palettes into a RGB Plane
152  *          - Copies the pixel data (image[s]/volume[s]) to newly allocated zone.
153  * @return  Pointer to newly allocated pixel data.
154  *          NULL if alloc fails 
155  */
156 uint8_t* File::GetImageData()
157 {
158    if ( ! GetDecompressed() )
159    {
160       // If the decompression failed nothing can be done.
161       return 0;
162    }
163
164    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
165    {
166       return PixelConverter->GetRGB();
167    }
168    else
169    {
170       // When no LUT or LUT conversion fails, return the decompressed
171       return PixelConverter->GetDecompressed();
172    }
173 }
174
175 /**
176  * \brief
177  *          Read the pixels from disk (uncompress if necessary),
178  *          Transforms YBR pixels, if any, into RGB pixels
179  *          Transforms 3 planes R, G, B, if any, into a single RGB Plane
180  *          Transforms single Grey plane + 3 Palettes into a RGB Plane   
181  *          Copies at most MaxSize bytes of pixel data to caller allocated
182  *          memory space.
183  * \warning This function allows people that want to build a volume
184  *          from an image stack *not to* have, first to get the image pixels, 
185  *          and then move them to the volume area.
186  *          It's absolutely useless for any VTK user since vtk chooses 
187  *          to invert the lines of an image, that is the last line comes first
188  *          (for some axis related reasons?). Hence he will have 
189  *          to load the image line by line, starting from the end.
190  *          VTK users have to call GetImageData
191  *     
192  * @param   destination Address (in caller's memory space) at which the
193  *          pixel data should be copied
194  * @param   maxSize Maximum number of bytes to be copied. When MaxSize
195  *          is not sufficient to hold the pixel data the copy is not
196  *          executed (i.e. no partial copy).
197  * @return  On success, the number of bytes actually copied. Zero on
198  *          failure e.g. MaxSize is lower than necessary.
199  */
200 size_t File::GetImageDataIntoVector (void* destination, size_t maxSize)
201 {
202    if ( ! GetDecompressed() )
203    {
204       // If the decompression failed nothing can be done.
205       return 0;
206    }
207
208    if ( HeaderInternal->HasLUT() && PixelConverter->BuildRGBImage() )
209    {
210       if ( PixelConverter->GetRGBSize() > maxSize )
211       {
212          dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
213                         "than caller's expected MaxSize");
214          return 0;
215       }
216       memcpy( destination,
217               (void*)PixelConverter->GetRGB(),
218               PixelConverter->GetRGBSize() );
219       return PixelConverter->GetRGBSize();
220    }
221
222    // Either no LUT conversion necessary or LUT conversion failed
223    if ( PixelConverter->GetDecompressedSize() > maxSize )
224    {
225       dbg.Verbose(0, "File::GetImageDataIntoVector: pixel data bigger"
226                      "than caller's expected MaxSize");
227       return 0;
228    }
229    memcpy( destination,
230            (void*)PixelConverter->GetDecompressed(),
231            PixelConverter->GetDecompressedSize() );
232    return PixelConverter->GetDecompressedSize();
233 }
234
235 /**
236  * \brief   Allocates necessary memory, 
237  *          Transforms YBR pixels (if any) into RGB pixels
238  *          Transforms 3 planes R, G, B  (if any) into a single RGB Plane
239  *          Copies the pixel data (image[s]/volume[s]) to newly allocated zone. 
240  *          DOES NOT transform Grey plane + 3 Palettes into a RGB Plane
241  * @return  Pointer to newly allocated pixel data.
242  * \        NULL if alloc fails 
243  */
244 uint8_t* File::GetImageDataRaw ()
245 {
246    return GetDecompressed();
247 }
248
249 uint8_t* File::GetDecompressed()
250 {
251    uint8_t* decompressed = PixelConverter->GetDecompressed();
252    if ( ! decompressed )
253    {
254       // The decompressed image migth not be loaded yet:
255       std::ifstream* fp = HeaderInternal->OpenFile();
256       PixelConverter->ReadAndDecompressPixelData( fp );
257       if(fp) 
258          HeaderInternal->CloseFile();
259
260       decompressed = PixelConverter->GetDecompressed();
261       if ( ! decompressed )
262       {
263          dbg.Verbose(0, "File::GetDecompressed: read/decompress of "
264                         "pixel data apparently went wrong.");
265          return 0;
266       }
267    }
268
269    return decompressed;
270 }
271
272 /**
273  * \brief   Points the internal Pixel_Data pointer to the callers inData
274  *          image representation, BUT WITHOUT COPYING THE DATA.
275  *          'image' Pixels are presented as C-like 2D arrays : line per line.
276  *          'volume'Pixels are presented as C-like 3D arrays : plane per plane 
277  * \warning Since the pixels are not copied, it is the caller's responsability
278  *          not to deallocate it's data before gdcm uses them (e.g. with
279  *          the Write() method.
280  * @param inData user supplied pixel area
281  * @param expectedSize total image size, in Bytes
282  *
283  * @return boolean
284  */
285 bool File::SetImageData(uint8_t* inData, size_t expectedSize)
286 {
287 // FIXME : if already allocated, memory leak !
288    Pixel_Data     = inData;
289    ImageDataSize = expectedSize;
290 // FIXME : 7fe0, 0010 IS NOT set ...
291    return true;
292 }
293
294 /**
295  * \brief Writes on disk A SINGLE Dicom file
296  *        NO test is performed on  processor "Endiannity".
297  *        It's up to the user to call his Reader properly
298  * @param fileName name of the file to be created
299  *                 (any already existing file is over written)
300  * @return false if write fails
301  */
302
303 bool File::WriteRawData(std::string const & fileName)
304 {
305   std::ofstream fp1(fileName.c_str(), std::ios::out | std::ios::binary );
306    if (!fp1)
307    {
308       dbg.Verbose(2, "Fail to open (write) file:", fileName.c_str());
309       return false;
310    }
311    fp1.write((char*)Pixel_Data, ImageDataSize);
312    fp1.close();
313
314    return true;
315 }
316
317 /**
318  * \brief Writes on disk A SINGLE Dicom file, 
319  *        using the Implicit Value Representation convention
320  *        NO test is performed on  processor "Endiannity".
321  * @param fileName name of the file to be created
322  *                 (any already existing file is overwritten)
323  * @return false if write fails
324  */
325
326 bool File::WriteDcmImplVR (std::string const & fileName)
327 {
328    SetWriteTypeToDcmImplVR();
329    return Write(fileName);
330 }
331
332 /**
333 * \brief Writes on disk A SINGLE Dicom file, 
334  *        using the Explicit Value Representation convention
335  *        NO test is performed on  processor "Endiannity". * @param fileName name of the file to be created
336  *                 (any already existing file is overwritten)
337  * @return false if write fails
338  */
339
340 bool File::WriteDcmExplVR (std::string const & fileName)
341 {
342    SetWriteTypeToDcmExplVR();
343    return Write(fileName);
344 }
345
346 /**
347  * \brief Writes on disk A SINGLE Dicom file, 
348  *        using the ACR-NEMA convention
349  *        NO test is performed on  processor "Endiannity".
350  *        (a l'attention des logiciels cliniques 
351  *        qui ne prennent en entrée QUE des images ACR ...
352  * \warning if a DICOM_V3 header is supplied,
353  *         groups < 0x0008 and shadow groups are ignored
354  * \warning NO TEST is performed on processor "Endiannity".
355  * @param fileName name of the file to be created
356  *                 (any already existing file is overwritten)
357  * @return false if write fails
358  */
359
360 bool File::WriteAcr (std::string const & fileName)
361 {
362    SetWriteTypeToAcr();
363    return Write(fileName);
364 }
365
366 bool File::Write(std::string const& fileName)
367 {
368    switch(WriteType)
369    {
370       case WTYPE_IMPL_VR:
371          return WriteBase(fileName,ImplicitVR);
372       case WTYPE_EXPL_VR:
373          return WriteBase(fileName,ExplicitVR);
374       case WTYPE_ACR:
375          return WriteBase(fileName,ACR);
376    }
377    return(false);
378 }
379
380 /**
381  * \brief Access to the underlying \ref PixelConverter RGBA LUT
382  */
383 uint8_t* File::GetLutRGBA()
384 {
385    return PixelConverter->GetLutRGBA();
386 }
387
388 //-----------------------------------------------------------------------------
389 // Protected
390 /**
391  * \brief NOT a end user inteded function
392  *        (used by WriteDcmExplVR, WriteDcmImplVR, WriteAcr, etc)
393  * @param fileName name of the file to be created
394  *                 (any already existing file is overwritten)
395  * @param  type file type (ExplicitVR, ImplicitVR, ...)
396  * @return false if write fails
397  */
398 bool File::WriteBase (std::string const & fileName, FileType type)
399 {
400    switch(type)
401    {
402       case ImplicitVR:
403          SetWriteFileTypeToImplicitVR();
404          break;
405       case ExplicitVR:
406          SetWriteFileTypeToExplicitVR();
407          break;
408       case ACR:
409          SetWriteFileTypeToACR();
410          break;
411       case ACR_LIBIDO:
412          SetWriteFileTypeToACRLibido();
413          break;
414       default:
415          SetWriteFileTypeToExplicitVR();
416    }
417   
418    switch(WriteMode)
419    {
420       case WMODE_NATIVE :
421          SetWriteToNative();
422          break;
423       case WMODE_DECOMPRESSED :
424          SetWriteToDecompressed();
425          break;
426       case WMODE_RGB :
427          SetWriteToRGB();
428          break;
429    }
430
431    // --------------------------------------------------------------
432    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
433    //
434    // if recognition code tells us we dealt with a LibIDO image
435    // we reproduce on disk the switch between lineNumber and columnNumber
436    // just before writting ...
437    /// \todo the best trick would be *change* the recognition code
438    ///       but pb expected if user deals with, e.g. COMPLEX images
439 /*   if ( HeaderInternal->GetFileType() == ACR_LIBIDO)
440    {
441       SetWriteToLibido();
442    }*/
443    // ----------------- End of Special Patch ----------------
444
445    bool check = CheckWriteIntegrity();
446    if(check)
447    {
448       check = HeaderInternal->Write(fileName,type);
449    }
450
451    // --------------------------------------------------------------
452    // Special Patch to allow gdcm to re-write ACR-LibIDO formated images
453    // 
454    // ...and we restore the Header to be Dicom Compliant again 
455    // just after writting
456 /*   if ( HeaderInternal->GetFileType() == ACR_LIBIDO )
457    {
458       RestoreWriteFromLibido();
459    }*/
460    // ----------------- End of Special Patch ----------------
461
462    RestoreWrite();
463    RestoreWriteFileType();
464
465    return check;
466 }
467
468 /**
469  * \brief Check the write integrity
470  *
471  * The tests made are :
472  *  - verify the size of the image to write with the possible write
473  *    when the user set an image data
474  * @return true if the check successfulls
475  */
476 bool File::CheckWriteIntegrity()
477 {
478    if(Pixel_Data)
479    {
480       int numberBitsAllocated = HeaderInternal->GetBitsAllocated();
481       if ( numberBitsAllocated == 0 || numberBitsAllocated == 12 )
482       {
483          numberBitsAllocated = 16;
484       }
485
486       size_t decSize = HeaderInternal->GetXSize()
487                     * HeaderInternal->GetYSize() 
488                     * HeaderInternal->GetZSize()
489                     * ( numberBitsAllocated / 8 )
490                     * HeaderInternal->GetSamplesPerPixel();
491       size_t rgbSize = decSize;
492       if( HeaderInternal->HasLUT() )
493          rgbSize = decSize * 3;
494
495       switch(WriteMode)
496       {
497          case WMODE_NATIVE :
498             break;
499          case WMODE_DECOMPRESSED :
500             if( decSize!=ImageDataSize )
501             {
502                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect");
503                //std::cerr<<"Dec : "<<decSize<<" | "<<ImageDataSize<<std::endl;
504                return false;
505             }
506             break;
507          case WMODE_RGB :
508             if( rgbSize!=ImageDataSize )
509             {
510                dbg.Verbose(0, "File::CheckWriteIntegrity: Data size is incorrect");
511                //std::cerr<<"RGB : "<<decSize<<" | "<<ImageDataSize<<std::endl;
512                return false;
513             }
514             break;
515       }
516    }
517    
518    return true;
519 }
520
521 void File::SetWriteToNative()
522 {
523    if(Pixel_Data)
524    {
525       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
526       pixel->SetValue(GDCM_BINLOADED);
527       pixel->SetBinArea(Pixel_Data,false);
528       pixel->SetLength(ImageDataSize);
529
530       Archive->Push(pixel);
531    }
532 }
533
534 void File::SetWriteToDecompressed()
535 {
536    if(HeaderInternal->GetNumberOfScalarComponents()==3 && !HeaderInternal->HasLUT())
537    {
538       SetWriteToRGB();
539    } 
540    else
541    {
542       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
543       if(HeaderInternal->HasLUT())
544       {
545          photInt->SetValue("PALETTE COLOR ");
546          photInt->SetLength(14);
547       }
548       else
549       {
550          photInt->SetValue("MONOCHROME1 ");
551          photInt->SetLength(12);
552       }
553
554       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
555       pixel->SetValue(GDCM_BINLOADED);
556       if(Pixel_Data)
557       {
558          pixel->SetBinArea(Pixel_Data,false);
559          pixel->SetLength(ImageDataSize);
560       }
561       else
562       {
563          pixel->SetBinArea(PixelConverter->GetDecompressed(),false);
564          pixel->SetLength(PixelConverter->GetDecompressedSize());
565       }
566
567       Archive->Push(photInt);
568       Archive->Push(pixel);
569    }
570 }
571
572 void File::SetWriteToRGB()
573 {
574    if(HeaderInternal->GetNumberOfScalarComponents()==3)
575    {
576       PixelConverter->BuildRGBImage();
577       
578       ValEntry* spp = CopyValEntry(0x0028,0x0002);
579       spp->SetValue("3 ");
580       spp->SetLength(2);
581
582       ValEntry* planConfig = CopyValEntry(0x0028,0x0006);
583       planConfig->SetValue("0 ");
584       planConfig->SetLength(2);
585
586       ValEntry* photInt = CopyValEntry(0x0028,0x0004);
587       photInt->SetValue("RGB ");
588       photInt->SetLength(4);
589
590       BinEntry* pixel = CopyBinEntry(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
591       pixel->SetValue(GDCM_BINLOADED);
592       if(Pixel_Data)
593       {
594          pixel->SetBinArea(Pixel_Data,false);
595          pixel->SetLength(ImageDataSize);
596       }
597       else if(PixelConverter->GetRGB())
598       {
599          pixel->SetBinArea(PixelConverter->GetRGB(),false);
600          pixel->SetLength(PixelConverter->GetRGBSize());
601       }
602       else // Decompressed data
603       {
604          pixel->SetBinArea(PixelConverter->GetDecompressed(),false);
605          pixel->SetLength(PixelConverter->GetDecompressedSize());
606       }
607
608       Archive->Push(spp);
609       Archive->Push(planConfig);
610       Archive->Push(photInt);
611       Archive->Push(pixel);
612
613       // Remove any LUT
614       Archive->Push(0x0028,0x1101);
615       Archive->Push(0x0028,0x1102);
616       Archive->Push(0x0028,0x1103);
617       Archive->Push(0x0028,0x1201);
618       Archive->Push(0x0028,0x1202);
619       Archive->Push(0x0028,0x1203);
620
621       // For old ACR-NEMA
622       // Thus, we have a RGB image and the bits allocated = 24 and 
623       // samples per pixels = 1 (in the read file)
624       if(HeaderInternal->GetBitsAllocated()==24) 
625       {
626          ValEntry* bitsAlloc = CopyValEntry(0x0028,0x0100);
627          bitsAlloc->SetValue("8 ");
628          bitsAlloc->SetLength(2);
629
630          ValEntry* bitsStored = CopyValEntry(0x0028,0x0101);
631          bitsStored->SetValue("8 ");
632          bitsStored->SetLength(2);
633
634          ValEntry* highBit = CopyValEntry(0x0028,0x0102);
635          highBit->SetValue("7 ");
636          highBit->SetLength(2);
637
638          Archive->Push(bitsAlloc);
639          Archive->Push(bitsStored);
640          Archive->Push(highBit);
641       }
642    }
643    else
644    {
645       SetWriteToDecompressed();
646    }
647 }
648
649 void File::RestoreWrite()
650 {
651    Archive->Restore(0x0028,0x0002);
652    Archive->Restore(0x0028,0x0004);
653    Archive->Restore(0x0028,0x0006);
654    Archive->Restore(GetHeader()->GetGrPixel(),GetHeader()->GetNumPixel());
655
656    // For old ACR-NEMA (24 bits problem)
657    Archive->Restore(0x0028,0x0100);
658    Archive->Restore(0x0028,0x0101);
659    Archive->Restore(0x0028,0x0102);
660
661    // For the LUT
662    Archive->Restore(0x0028,0x1101);
663    Archive->Restore(0x0028,0x1102);
664    Archive->Restore(0x0028,0x1103);
665    Archive->Restore(0x0028,0x1201);
666    Archive->Restore(0x0028,0x1202);
667    Archive->Restore(0x0028,0x1203);
668 }
669
670 void File::SetWriteFileTypeToACR()
671 {
672    Archive->Push(0x0002,0x0010);
673 }
674
675 void File::SetWriteFileTypeToACRLibido()
676 {
677    SetWriteFileTypeToACR();
678 }
679
680 void File::SetWriteFileTypeToExplicitVR()
681 {
682    std::string ts = Util::DicomString( 
683       Document::GetTransferSyntaxValue(ExplicitVRLittleEndian).c_str() );
684
685    ValEntry* tss = CopyValEntry(0x0002,0x0010);
686    tss->SetValue(ts);
687    tss->SetLength(ts.length());
688
689    Archive->Push(tss);
690 }
691
692 void File::SetWriteFileTypeToImplicitVR()
693 {
694    std::string ts = Util::DicomString(
695       Document::GetTransferSyntaxValue(ImplicitVRLittleEndian).c_str() );
696
697    ValEntry* tss = CopyValEntry(0x0002,0x0010);
698    tss->SetValue(ts);
699    tss->SetLength(ts.length());
700 }
701
702 void File::RestoreWriteFileType()
703 {
704    Archive->Restore(0x0002,0x0010);
705 }
706
707 void File::SetWriteToLibido()
708 {
709    ValEntry *oldRow = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0010));
710    ValEntry *oldCol = dynamic_cast<ValEntry *>(HeaderInternal->GetDocEntryByNumber(0x0028, 0x0011));
711    
712    if( oldRow && oldCol )
713    {
714       std::string rows, columns; 
715
716       ValEntry *newRow=new ValEntry(oldRow->GetDictEntry());
717       ValEntry *newCol=new ValEntry(oldCol->GetDictEntry());
718
719       newRow->Copy(oldCol);
720       newCol->Copy(oldRow);
721
722       newRow->SetValue(oldCol->GetValue());
723       newCol->SetValue(oldRow->GetValue());
724
725       Archive->Push(newRow);
726       Archive->Push(newCol);
727    }
728 }
729
730 void File::RestoreWriteFromLibido()
731 {
732    Archive->Restore(0x0028,0x0010);
733    Archive->Restore(0x0028,0x0011);
734 }
735
736 ValEntry* File::CopyValEntry(uint16_t group,uint16_t element)
737 {
738    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
739    ValEntry* newE;
740
741    if(oldE)
742    {
743       newE = new ValEntry(oldE->GetDictEntry());
744       newE->Copy(oldE);
745    }
746    else
747    {
748       newE = GetHeader()->NewValEntryByNumber(group,element);
749    }
750
751    return(newE);
752 }
753
754 BinEntry* File::CopyBinEntry(uint16_t group,uint16_t element)
755 {
756    DocEntry* oldE = HeaderInternal->GetDocEntryByNumber(group, element);
757    BinEntry* newE;
758
759    if(oldE)
760    {
761       newE = new BinEntry(oldE->GetDictEntry());
762       newE->Copy(oldE);
763    }
764    else
765    {
766       newE = GetHeader()->NewBinEntryByNumber(group,element);
767    }
768
769
770    return(newE);
771 }
772
773 //-----------------------------------------------------------------------------
774 // Private
775
776 //-----------------------------------------------------------------------------
777 } // end namespace gdcm
778