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