//-----------------------------------------------------------------------------
#include "gdcmDocument.h"
+#include "gdcmValEntry.h"
+#include "gdcmBinEntry.h"
+#include "gdcmSeqEntry.h"
+
#include "gdcmGlobal.h"
#include "gdcmUtil.h"
#include "gdcmDebug.h"
#define UI1_2_840_10008_1_2_1 "1.2.840.10008.1.2.1"
#define UI1_2_840_10008_1_2_2 "1.2.840.10008.1.2.2"
#define UI1_2_840_10008_1_2_1_99 "1.2.840.10008.1.2.1.99"
+#define UI1_1_2_840_10008_1_2_5 "1.2.840.10008.1.2.5"
-typedef struct {
- guint32 totalSQlength;
- guint32 alreadyParsedlength;
-} pileElem;
+#define str2num(str, typeNum) *((typeNum *)(str))
//-----------------------------------------------------------------------------
// Refer to gdcmDocument::CheckSwap()
gdcmDocument::gdcmDocument(const char *inFilename,
bool exception_on_error,
bool enable_sequences,
- bool ignore_shadow) {
+ bool ignore_shadow)
+ : gdcmElementSet(-1) {
enableSequences=enable_sequences;
ignoreShadow =ignore_shadow;
if ( !OpenFile(exception_on_error))
return;
+
+ rewind(fp);
+ //if (!CheckSwap())
+ // return false; // to go on compiling
+
+ fseek(fp,0L,SEEK_END);
+ long lgt = ftell(fp);
+
+ rewind(fp);
+ CheckSwap();
+ long beg = ftell(fp);
+ lgt -= beg;
+
+ SQDepthLevel=0;
+
+ long l=ParseDES( this, beg, lgt, false); // le Load sera fait a la volee
+ CloseFile();
+
+ // --------------------------------------------------------------
+ // Special Patch to allow gdcm to read ACR-LibIDO formated images
+ //
+ // if recognition code tells us we deal with a LibIDO image
+ // we switch lineNumber and columnNumber
+ //
+ std::string RecCode;
+ RecCode = GetEntryByNumber(0x0008, 0x0010); // recognition code
+ if (RecCode == "ACRNEMA_LIBIDO_1.1" ||
+ RecCode == "CANRME_AILIBOD1_1." ) // for brain-damaged softwares
+ // with "little-endian strings"
+ {
+ filetype = gdcmACR_LIBIDO;
+ std::string rows = GetEntryByNumber(0x0028, 0x0010);
+ std::string columns = GetEntryByNumber(0x0028, 0x0011);
+ SetEntryByNumber(columns, 0x0028, 0x0010);
+ SetEntryByNumber(rows , 0x0028, 0x0011);
+ }
+ // ----------------- End of Special Patch ----------------
- LoadDocEntries();
- CloseFile();
-
- wasUpdated = 0; // will be set to 1 if user adds an entry
printLevel = 1; // 'Medium' print level by default
}
* \brief constructor
* @param exception_on_error
*/
-gdcmDocument::gdcmDocument(bool exception_on_error) {
- (void)exception_on_error;
+gdcmDocument::gdcmDocument(bool exception_on_error)
+ :gdcmElementSet(-1) {
+ (void)exception_on_error;
enableSequences=0;
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Initialise();
- wasUpdated = 0; // will be set to 1 if user adds an entry
printLevel = 1; // 'Medium' print level by default
}
//-----------------------------------------------------------------------------
// Print
/**
- * \brief Prints the Doc Entries (Dicom Elements)
- * from the chained list
- * @return
- */
-void gdcmDocument::PrintEntry(std::ostream & os) {
-
- for (ListTag::iterator i = listEntries.begin();
- i != listEntries.end();
- ++i)
- {
- (*i)->SetPrintLevel(printLevel);
- (*i)->Print(os);
- }
-}
-
+
/**
* \brief Prints The Dict Entries of THE public Dicom Dictionary
* false otherwise.
*/
bool gdcmDocument::IsReadable(void) {
- if(filetype==Unknown) {
+ if(filetype==gdcmUnknown) {
+ std::cout << "wrong filetype" <<std::endl;
return(false);
}
- if(listEntries.size()<=0) {
+ if(!tagHT.empty()<=0) {
+ std::cout << "wrong tagHT size "<< tagHT.size() <<std::endl;
return(false);
}
* @return True when ImplicitVRLittleEndian found. False in all other cases.
*/
bool gdcmDocument::IsImplicitVRLittleEndianTransferSyntax(void) {
- gdcmHeaderEntry *Element = GetHeaderEntryByNumber(0x0002, 0x0010);
+ gdcmDocEntry *Element = GetDocEntryByNumber(0x0002, 0x0010);
if ( !Element )
return false;
- LoadHeaderEntrySafe(Element);
+ LoadDocEntrySafe(Element);
- std::string Transfer = Element->GetValue();
+ std::string Transfer = ((gdcmValEntry *)Element)->GetValue();
if ( Transfer == UI1_2_840_10008_1_2 )
return true;
return false;
* @return True when ExplicitVRLittleEndian found. False in all other cases.
*/
bool gdcmDocument::IsExplicitVRLittleEndianTransferSyntax(void) {
- gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
+ gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010);
if ( !Element )
return false;
- LoadHeaderEntrySafe(Element);
+ LoadDocEntrySafe(Element);
- std::string Transfer = Element->GetValue();
+ std::string Transfer = ((gdcmValEntry *)Element)->GetValue();
if ( Transfer == UI1_2_840_10008_1_2_1 )
return true;
return false;
* @return True when DeflatedExplicitVRLittleEndian found. False in all other cases.
*/
bool gdcmDocument::IsDeflatedExplicitVRLittleEndianTransferSyntax(void) {
- gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
+ gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010);
if ( !Element )
return false;
- LoadHeaderEntrySafe(Element);
+ LoadDocEntrySafe(Element);
- std::string Transfer = Element->GetValue();
+ std::string Transfer = ((gdcmValEntry *)Element)->GetValue();
if ( Transfer == UI1_2_840_10008_1_2_1_99 )
return true;
return false;
* @return True when big endian found. False in all other cases.
*/
bool gdcmDocument::IsExplicitVRBigEndianTransferSyntax(void) {
- gdcmHeaderEntry* Element = GetHeaderEntryByNumber(0x0002, 0x0010);
+ gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010);
if ( !Element )
return false;
- LoadHeaderEntrySafe(Element);
+ LoadDocEntrySafe(Element);
- std::string Transfer = Element->GetValue();
+ std::string Transfer = ((gdcmValEntry *)Element)->GetValue();
if ( Transfer == UI1_2_840_10008_1_2_2 ) //1.2.2 ??? A verifier !
return true;
return false;
}
/**
- * \brief Writes in a file all the Doc Entries (Dicom Elements)
+ * \brief Writes in a file all the Header Entries (Dicom Elements)
* of the Chained List
* @param fp file pointer on an already open file
* @param type Type of the File to be written
/// ==============
/// The stuff will have to be rewritten using the SeQuence based
/// tree-like stucture instead of the chained list .
-/// (so we shall remove the GroupHT from the gdcmDocument)
+/// (so we shall remove the Group*HT from the gdcmDocument)
/// To be checked
/// =============
/// a moins de se livrer a un tres complique ajout des champs manquants.
/// faire un CheckAndCorrectHeader (?)
- if (type == ImplicitVR)
+ if (type == gdcmImplicitVR)
{
std::string implicitVRTransfertSyntax = UI1_2_840_10008_1_2;
ReplaceOrCreateByNumber(implicitVRTransfertSyntax,0x0002, 0x0010);
SetEntryLengthByNumber(18, 0x0002, 0x0010);
}
- if (type == ExplicitVR)
+ if (type == gdcmExplicitVR)
{
std::string explicitVRTransfertSyntax = UI1_2_840_10008_1_2_1;
ReplaceOrCreateByNumber(explicitVRTransfertSyntax,0x0002, 0x0010);
/**
* \brief Modifies the value of a given Header Entry (Dicom Element)
* when it exists. Create it with the given value when unexistant.
- * \warning Adds the Header Entry to the HTable, NOT to the chained List
* @param Value Value to be set
- * @param Group Group of the Entry
- * @param Elem Element of the Entry
+ * @param Group Group number of the Entry
+ * @param Elem Element number of the Entry
* \return pointer to the modified/created Header Entry (NULL when creation
* failed).
*/
-gdcmHeaderEntry * gdcmDocument::ReplaceOrCreateByNumber(
+
+
+gdcmDocEntry * gdcmDocument::ReplaceOrCreateByNumber(
std::string Value,
guint16 Group,
guint16 Elem ){
- gdcmHeaderEntry* a;
- a = GetHeaderEntryByNumber( Group, Elem);
+ gdcmDocEntry* a;
+ a = GetDocEntryByNumber( Group, Elem);
if (a == NULL) {
- a =NewHeaderEntryByNumber(Group, Elem);
+ a =NewDocEntryByNumber(Group, Elem);
if (a == NULL)
return NULL;
- AddHeaderEntry(a);
+ AddEntry(a);
}
- //CLEANME SetEntryByNumber(Value, Group, Elem);
- a->SetValue(Value);
+ SetEntryByNumber(Value, Group, Elem);
+ //a->SetValue(Value);
return(a);
}
* \brief Set a new value if the invoked element exists
* Seems to be useless !!!
* @param Value new element value
- * @param Group group of the Entry
- * @param Elem element of the Entry
+ * @param Group group number of the Entry
+ * @param Elem element number of the Entry
* \return boolean
*/
bool gdcmDocument::ReplaceIfExistByNumber(char* Value, guint16 Group, guint16 Elem )
// Protected
/**
- * \brief Checks if a given Dicom Element exists
- * within the H table
- * @param group Group number of the searched Dicom Element
+ * \brief Checks if a given Dicom Element exists within the H table
+ * @param group Group number of the searched Dicom Element
* @param element Element number of the searched Dicom Element
* @return number of occurences
*/
}
/**
- * \brief Searches within Doc Entries (Dicom Elements) parsed with
+ * \brief Searches within Header Entries (Dicom Elements) parsed with
* the public and private dictionaries
* for the element value of a given tag.
* \warning Don't use any longer : use GetPubEntryByName
}
/**
- * \brief Searches within Doc Entries (Dicom Elements) parsed with
+ * \brief Searches within Header Entries (Dicom Elements) parsed with
* the public and private dictionaries
* for the element value representation of a given tag.
*
if( dictEntry == NULL)
return GDCM_UNFOUND;
- gdcmHeaderEntry* elem = GetHeaderEntryByNumber(dictEntry->GetGroup(),
- dictEntry->GetElement());
+ gdcmDocEntry* elem = GetDocEntryByNumber(dictEntry->GetGroup(),
+ dictEntry->GetElement());
return elem->GetVR();
}
/**
- * \brief Searches within Doc Entries (Dicom Elements) parsed with
+ * \brief Searches within Header Entries (Dicom Elements) parsed with
* the public and private dictionaries
* for the element value representation of a given tag.
- * @param group Group of the searched tag.
- * @param element Element of the searched tag.
+ * @param group Group number of the searched tag.
+ * @param element Element number of the searched tag.
* @return Corresponding element value representation when it exists,
* and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
*/
TagKey key = gdcmDictEntry::TranslateToKey(group, element);
if ( ! tagHT.count(key))
return GDCM_UNFOUND;
- return tagHT.find(key)->second->GetValue();
+ return ((gdcmValEntry *)tagHT.find(key)->second)->GetValue();
}
/**
- * \brief Searches within Doc Entries (Dicom Elements) parsed with
+ * \brief Searches within Header Entries (Dicom Elements) parsed with
* the public and private dictionaries
* for the element value representation of a given tag..
*
* to convert the string typed content to caller's native type
* (think of C++ vs Python). The VR is actually of a higher level
* of semantics than just the native C++ type.
- * @param group Group of the searched tag.
- * @param element Element of the searched tag.
+ * @param group Group number of the searched tag.
+ * @param element Element number of the searched tag.
* @return Corresponding element value representation when it exists,
* and the string GDCM_UNFOUND ("gdcm::Unfound") otherwise.
*/
std::string gdcmDocument::GetEntryVRByNumber(guint16 group, guint16 element) {
- gdcmHeaderEntry* elem = GetHeaderEntryByNumber(group, element);
+ gdcmDocEntry* elem = GetDocEntryByNumber(group, element);
if ( !elem )
return GDCM_UNFOUND;
return elem->GetVR();
}
/**
- * \brief Searches within Doc Entries (Dicom Elements) parsed with
+ * \brief Searches within Header Entries (Dicom Elements) parsed with
* the public and private dictionaries
* for the value length of a given tag..
- * @param group Group of the searched tag.
- * @param element Element of the searched tag.
+ * @param group Group number of the searched tag.
+ * @param element Element number of the searched tag.
* @return Corresponding element length; -2 if not found
*/
int gdcmDocument::GetEntryLengthByNumber(guint16 group, guint16 element) {
- gdcmHeaderEntry* elem = GetHeaderEntryByNumber(group, element);
+ gdcmDocEntry* elem = GetDocEntryByNumber(group, element);
if ( !elem )
return -2;
return elem->GetLength();
}
/**
- * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element)
+ * \brief Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
* through it's (group, element) and modifies it's content with
* the given value.
- * \warning Don't use any longer : use SetPubEntryByNumber
* @param content new value to substitute with
- * @param group group of the Dicom Element to modify
- * @param element element of the Dicom Element to modify
+ * @param group group number of the Dicom Element to modify
+ * @param element element number of the Dicom Element to modify
*/
bool gdcmDocument::SetEntryByNumber(std::string content,
guint16 group,
content = content + '\0';
}
- gdcmHeaderEntry * a;
- IterHT p;
- TagHeaderEntryHT::iterator p2;
- // DO NOT remove the following lines : they explain the stuff
- //p= tagHT.equal_range(key); // get a pair of iterators first-last synonym
- //p2=p.first; // iterator on the first synonym
- //a=p2->second; // H Table target column (2-nd col)
-
- // or, easier :
- a = ((tagHT.equal_range(key)).first)->second;
-
- a-> SetValue(content);
+ gdcmDocEntry * a;
+ a = tagHT[key];
+
+ ((gdcmValEntry*)a)->SetValue(content);
std::string vr = a->GetVR();
}
/**
- * \brief Accesses an existing gdcmHeaderEntry (i.e. a Dicom Element)
- * in the PubHeaderEntrySet of this instance
+ * \brief Accesses an existing gdcmDocEntry (i.e. a Dicom Element)
+ * in the PubDocEntrySet of this instance
* through it's (group, element) and modifies it's length with
* the given value.
* \warning Use with extreme caution.
* @param l new length to substitute with
- * @param group group of the Entry to modify
- * @param element element of the Entry to modify
+ * @param group group number of the Entry to modify
+ * @param element element number of the Entry to modify
* @return true on success, false otherwise.
*/
bool gdcmDocument::SetEntryLengthByNumber(guint32 l,
/**
* \brief Gets (from Header) the offset of a 'non string' element value
* (LoadElementValues has already be executed)
- * @param Group group of the Entry
- * @param Elem element of the Entry
+ * @param Group group number of the Entry
+ * @param Elem element number of the Entry
* @return File Offset of the Element Value
*/
size_t gdcmDocument::GetEntryOffsetByNumber(guint16 Group, guint16 Elem)
{
- gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem);
+ gdcmDocEntry* Entry = GetDocEntryByNumber(Group, Elem);
if (!Entry)
{
- dbg.Verbose(1, "gdcmDocument::GetHeaderEntryByNumber",
- "failed to Locate gdcmHeaderEntry");
+ dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber",
+ "failed to Locate gdcmDocEntry");
return (size_t)0;
}
return Entry->GetOffset();
/**
* \brief Gets (from Header) a 'non string' element value
* (LoadElementValues has already be executed)
- * @param Group group of the Entry
- * @param Elem element of the Entry
+ * @param Group group number of the Entry
+ * @param Elem element number of the Entry
* @return Pointer to the 'non string' area
*/
void * gdcmDocument::GetEntryVoidAreaByNumber(guint16 Group, guint16 Elem)
{
- gdcmHeaderEntry* Entry = GetHeaderEntryByNumber(Group, Elem);
+ gdcmDocEntry* Entry = GetDocEntryByNumber(Group, Elem);
if (!Entry)
{
- dbg.Verbose(1, "gdcmDocument::GetHeaderEntryByNumber",
- "failed to Locate gdcmHeaderEntry");
+ dbg.Verbose(1, "gdcmDocument::GetDocEntryByNumber",
+ "failed to Locate gdcmDocEntry");
return (NULL);
}
- return Entry->GetVoidArea();
+ return ((gdcmBinEntry *)Entry)->GetVoidArea();
}
/**
* \brief Loads (from disk) the element content
* when a string is not suitable
- * @param Group group of the Entry
- * @param Elem element of the Entry
+ * @param Group group number of the Entry
+ * @param Elem element number of the Entry
*/
void *gdcmDocument::LoadEntryVoidArea(guint16 Group, guint16 Elem)
{
- gdcmHeaderEntry * Element= GetHeaderEntryByNumber(Group, Elem);
+ gdcmDocEntry * Element= GetDocEntryByNumber(Group, Elem);
if ( !Element )
return NULL;
size_t o =(size_t)Element->GetOffset();
/**
* \brief Sets a 'non string' value to a given Dicom Element
* @param area
- * @param group Group number of the searched Dicom Element
+ * @param group Group number of the searched Dicom Element
* @param element Element number of the searched Dicom Element
* @return
*/
TagKey key = gdcmDictEntry::TranslateToKey(group, element);
if ( ! tagHT.count(key))
return false;
- ( ((tagHT.equal_range(key)).first)->second )->SetVoidArea(area);
+ // This was for multimap ?
+ (( gdcmBinEntry *)( ((tagHT.equal_range(key)).first)->second ))->SetVoidArea(area);
+
return true;
}
void gdcmDocument::UpdateShaEntries(void) {
gdcmDictEntry *entry;
std::string vr;
-
+
+ // TODO : if still any use (?) explore recursively the whole structure
+/*
for(ListTag::iterator it=listEntries.begin();
it!=listEntries.end();
++it)
else
vr=(*it)->GetVR();
- (*it)->SetValue(GetHeaderEntryUnvalue(*it));
+ (*it)->SetValue(GetDocEntryUnvalue(*it)); // to go on compiling
if(entry){
// Set the new entry and the new value
(*it)->SetDictEntry(entry);
- CheckHeaderEntryVR(*it,vr);
+ CheckDocEntryVR(*it,vr);
- (*it)->SetValue(GetHeaderEntryValue(*it));
+ (*it)->SetValue(GetDocEntryValue(*it)); // to go on compiling
+
}
else
{
(*it)->SetDictEntry(NewVirtualDictEntry((*it)->GetGroup(),(*it)->GetElement(),vr));
}
}
+*/
}
/**
- * \brief Searches within the Doc Entries for a Dicom Element of
+ * \brief Searches within the Header Entries for a Dicom Element of
* a given tag.
* @param tagName name of the searched Dicom Element.
* @return Corresponding Dicom Element when it exists, and NULL
* otherwise.
*/
- gdcmHeaderEntry *gdcmDocument::GetHeaderEntryByName(std::string tagName) {
+ gdcmDocEntry *gdcmDocument::GetDocEntryByName(std::string tagName) {
gdcmDictEntry *dictEntry = RefPubDict->GetDictEntryByName(tagName);
if( dictEntry == NULL)
return NULL;
- return(GetHeaderEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));
+ return(GetDocEntryByNumber(dictEntry->GetGroup(),dictEntry->GetElement()));
}
/**
* @param element Element number of the searched Dicom Element
* @return
*/
-gdcmHeaderEntry* gdcmDocument::GetHeaderEntryByNumber(guint16 group, guint16 element)
+gdcmDocEntry* gdcmDocument::GetDocEntryByNumber(guint16 group, guint16 element)
{
TagKey key = gdcmDictEntry::TranslateToKey(group, element);
if ( ! tagHT.count(key))
return tagHT.find(key)->second;
}
-/**
- * \brief retrieves the Dicom Elements (all of them) using (group, element)
- * @param group Group number of the searched Dicom Element.
- * @param element Element number of the searched Dicom Element.
- * @return a range (i.e.pair<,>) containing all elements whose key is group|element)
- */
-
-IterHT gdcmDocument::GetHeaderEntrySameNumber(guint16 group, guint16 element){
- TagKey key = gdcmDictEntry::TranslateToKey(group, element);
- return (tagHT.equal_range(key));
-}
-
/**
* \brief Loads the element while preserving the current
* underlying file position indicator as opposed to
- * to LoadHeaderEntry that modifies it.
+ * to LoadDocEntry that modifies it.
* @param entry Header Entry whose value shall be loaded.
* @return
*/
-void gdcmDocument::LoadHeaderEntrySafe(gdcmHeaderEntry * entry) {
+void gdcmDocument::LoadDocEntrySafe(gdcmDocEntry * entry) {
long PositionOnEntry = ftell(fp);
- LoadHeaderEntry(entry);
+ LoadDocEntry(entry);
fseek(fp, PositionOnEntry, SEEK_SET);
}
-/**
- * \brief Re-computes the length of a ACR-NEMA/Dicom group from a DcmHeader
- * \warning : to be re-written using the chained list instead of the H table.
- * \warning : DO NOT use (doesn't work any longer because of the multimap)
- * \todo : to be re-written using the chained list instead of the H table
- * @param SkipSequence TRUE if we don't want to write Sequences (ACR-NEMA Files)
- * @param type Type of the File (ExplicitVR,ImplicitVR, ACR, ...)
- */
-void gdcmDocument::UpdateGroupLength(bool SkipSequence, FileType type) {
- guint16 gr, el;
- std::string vr;
-
- gdcmHeaderEntry *elem;
- char trash[10];
- std::string str_trash;
-
- GroupKey key;
- GroupHT groupHt; // to hold the length of each group
- TagKey tk;
- // remember :
- // typedef std::map<GroupKey, int> GroupHT;
-
- gdcmHeaderEntry *elemZ;
-
- // for each Tag in the DCM Header
-
- for (TagHeaderEntryHT::iterator tag2 = tagHT.begin();
- tag2 != tagHT.end();
- ++tag2)
- {
- elem = tag2->second;
- gr = elem->GetGroup();
- el = elem->GetElement();
- vr = elem->GetVR();
-
- sprintf(trash, "%04x", gr);
- key = trash; // generate 'group tag'
-
- // if the caller decided not to take SEQUENCEs into account
- // e.g : he wants to write an ACR-NEMA File
-
- if (SkipSequence && vr == "SQ")
- continue;
-
- // Still unsolved problem :
- // we cannot find the 'Sequence Delimitation Item'
- // since it's at the end of the Hash Table
- // (fffe,e0dd)
-
- // there is SEQUENCE in ACR-NEMA
- // WARNING :
- // --> la descente a l'interieur' des SQ
- // devrait etre faite avec une liste chainee, pas avec une HTable...
-
- if ( groupHt.count(key) == 0) // we just read the first elem of a given group
- {
- if (el == 0x0000) // the first elem is 0x0000
- {
- groupHt[key] = 0; // initialize group length
- }
- else
- {
- groupHt[key] = 2 + 2 + 4 + elem->GetLength(); // non 0x0000 first group elem
- }
- }
- else // any elem but the first
- {
- if (type == ExplicitVR)
- {
- if ( (vr == "OB") || (vr == "OW") || (vr == "SQ") )
- {
- groupHt[key] += 4; // explicit VR AND OB, OW, SQ : 4 more bytes
- }
- }
- groupHt[key] += 2 + 2 + 4 + elem->GetLength();
- }
- }
-
- unsigned short int gr_bid;
-
- for (GroupHT::iterator g = groupHt.begin(); // for each group we found
- g != groupHt.end();
- ++g)
- {
- // FIXME: g++ -Wall -Wstrict-prototypes reports on following line:
- // warning: unsigned int format, different type arg
- sscanf(g->first.c_str(),"%x",&gr_bid); //FIXME
- tk = g->first + "|0000"; // generate the element full tag
-
- if ( tagHT.count(tk) == 0) // if element 0x0000 not found
- {
- gdcmDictEntry * tagZ = new gdcmDictEntry(gr_bid, 0x0000, "UL");
- elemZ = new gdcmHeaderEntry(tagZ);
- elemZ->SetLength(4);
- AddHeaderEntry(elemZ); // create it
- }
- else
- {
- elemZ=GetHeaderEntryByNumber(gr_bid, 0x0000);
- }
- sprintf(trash ,"%d",g->second);
- str_trash=trash;
- elemZ->SetValue(str_trash);
- }
-}
/**
* \brief Writes in a file (according to the requested format)
* the group, the element, the value representation and the length
- * of a single gdcmHeaderEntry passed as argument.
- * @param tag pointer on the gdcmHeaderEntry to be written
+ * of a single gdcmDocEntry passed as argument.
+ * @param tag pointer on the gdcmDocEntry to be written
* @param _fp already open file pointer
* @param type type of the File to be written
*/
-void gdcmDocument::WriteEntryTagVRLength(gdcmHeaderEntry *tag,
+void gdcmDocument::WriteEntryTagVRLength(gdcmDocEntry *tag,
FILE *_fp,
FileType type)
{
fwrite ( &group,(size_t)2 ,(size_t)1 ,_fp); //group
fwrite ( &el,(size_t)2 ,(size_t)1 ,_fp); //element
- if ( type == ExplicitVR ) {
+ if ( type == gdcmExplicitVR ) {
// Special case of delimiters:
if (group == 0xfffe) {
/**
* \brief Writes in a file (according to the requested format)
- * the value of a single gdcmHeaderEntry passed as argument.
- * @param tag Pointer on the gdcmHeaderEntry to be written
+ * the value of a single gdcmDocEntry passed as argument.
+ * @param tag Pointer on the gdcmDocEntry to be written
* @param _fp Already open file pointer
* @param type type of the File to be written
*/
-void gdcmDocument::WriteEntryValue(gdcmHeaderEntry *tag, FILE *_fp,FileType type)
+
+ // TODO : to be re -written recursively !
+
+void gdcmDocument::WriteEntryValue(gdcmDocEntry *tag, FILE *_fp,FileType type)
{
(void)type;
guint16 group = tag->GetGroup();
if (group == 0xfffe)
// Delimiters have no associated value:
return;
-
+
+ //--------------------------------
+ //
+ // FIXME
+ //
+ // -------------------------------
+
+
+/* // to go on compiling
void *voidArea;
- voidArea = tag->GetVoidArea();
+ voidArea = tag->GetVoidArea(); // to go on compiling
if (voidArea != NULL)
{ // there is a 'non string' LUT, overlay, etc
fwrite ( voidArea,(size_t)lgr ,(size_t)1 ,_fp); // Elem value
return;
}
-
+*/
if (vr == "US" || vr == "SS")
{
// some 'Short integer' fields may be mulivaluated
// we split the string and write each value as a short int
std::vector<std::string> tokens;
tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
- Tokenize (tag->GetValue(), tokens, "\\");
+ Tokenize (((gdcmValEntry *)tag)->GetValue(), tokens, "\\");
for (unsigned int i=0; i<tokens.size();i++)
{
guint16 val_uint16 = atoi(tokens[i].c_str());
{
std::vector<std::string> tokens;
tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
- Tokenize (tag->GetValue(), tokens, "\\");
+ Tokenize (((gdcmValEntry *)tag)->GetValue(), tokens, "\\");
for (unsigned int i=0; i<tokens.size();i++)
{
guint32 val_uint32 = atoi(tokens[i].c_str());
tokens.clear();
return;
}
- fwrite (tag->GetValue().c_str(), (size_t)lgr ,(size_t)1, _fp); // Elem value
+ fwrite (((gdcmValEntry *)tag)->GetValue().c_str(), (size_t)lgr ,(size_t)1, _fp); // Elem value
}
/**
* \brief Writes in a file (according to the requested format)
- * a single gdcmHeaderEntry passed as argument.
+ * a single gdcmDocEntry passed as argument.
* \sa WriteEntryValue, WriteEntryTagVRLength.
- * @param tag Pointer on the gdcmHeaderEntry to be written
+ * @param tag Pointer on the gdcmDocEntry to be written
* @param _fp Already open file pointer
* @param type type of the File to be written
*/
-bool gdcmDocument::WriteEntry(gdcmHeaderEntry *tag, FILE *_fp,FileType type)
+bool gdcmDocument::WriteEntry(gdcmDocEntry *tag, FILE *_fp,FileType type)
{
guint32 length = tag->GetLength();
-
+ gdcmValEntry * Vtag = (gdcmValEntry *) tag;
+std::cout << "gdcmDocument::WriteEntry Vtag->GetValue() " << Vtag->GetValue() << std::endl;
// The value of a tag MUST (see the DICOM norm) be an odd number of
// bytes. When this is not the case, pad with an additional byte:
if(length%2==1)
{
- tag->SetValue(tag->GetValue()+"\0");
- tag->SetLength(tag->GetReadLength()+1);
+ Vtag->SetValue(Vtag->GetValue()+"\0");
+ Vtag->SetLength(Vtag->GetReadLength()+1);
}
- WriteEntryTagVRLength(tag, _fp, type);
- WriteEntryValue(tag, _fp, type);
+ WriteEntryTagVRLength(Vtag, _fp, type);
+ std::cout << "after WriteEntryTagVRLength " << std::endl;
+ WriteEntryValue(Vtag, _fp, type);
+ std::cout << "after WriteEntryValue " << std::endl;
return true;
}
* (function CheckHeaderCoherence to be written)
* \warning DON'T try, right now, to write a DICOM image
* from an ACR Header (meta elements will be missing!)
- * \sa WriteEntriesDeprecated (Special temporary method for Theralys)
* @param type type of the File to be written
* (ACR-NEMA, ExplicitVR, ImplicitVR)
* @param _fp already open file pointer
*/
bool gdcmDocument::WriteEntries(FILE *_fp,FileType type)
-{
+{
+
+// FIXME : explore recursively the whole structure...
+
/// \todo (?) check write failures (after *each* fwrite)
-
- for (ListTag::iterator tag2=listEntries.begin();
- tag2 != listEntries.end();
- ++tag2)
+
+ std::cout << "--------------------- gdcmDocument::WriteEntries " << std::endl;
+ for (TagDocEntryHT::iterator tag2=tagHT.begin();
+ tag2 != tagHT.end();
+ ++tag2)
{
- if ( type == ACR ){
- if ((*tag2)->GetGroup() < 0x0008)
+
+ (*tag2).second->Print();
+
+ if ( type == gdcmACR ){
+ if ((*tag2).second->GetGroup() < 0x0008)
// Ignore pure DICOM V3 groups
continue;
- if ((*tag2)->GetElement() %2)
+ if ((*tag2).second->GetGroup() %2)
// Ignore the "shadow" groups
continue;
- if ((*tag2)->GetVR() == "SQ" ) // ignore Sequences
+ if ((*tag2).second->GetVR() == "SQ" ) // ignore Sequences
continue;
- if ((*tag2)->GetSQDepthLevel() != 0) // Not only ignore the SQ element
- continue;
+ //if ((*tag2).second->GetDepthLevel() != 0) // Not only ignore the SQ element
+ // continue;
}
- if (! WriteEntry(*tag2,_fp,type) )
+ if (! WriteEntry((*tag2).second,_fp,type) ) {
+ std::cout << "Write Failure " << std::endl;
return false;
+ } else {
+
+ }
}
return true;
}
-/**
- * \brief writes on disc according to the requested format
- * (ACR-NEMA, ExplicitVR, ImplicitVR) the image,
- * using only the last synonym of each mutimap H Table post.
- * \warning Uses the H Table, instead of the Chained List
- * in order to be compliant with the old way to proceed
- * (added elements taken in to account)
- * Only THERALYS, during a transitory phase is supposed
- * to use this method !!!
- * \warning DON'T try, right now, to write a DICOM image
- * from an ACR Header (meta elements will be missing!)
- * \sa WriteEntries
- * @param _fp already open file pointer
- * @param type type of the File to be written
- * (ACR-NEMA, ExplicitVR, ImplicitVR)
- */
-void gdcmDocument::WriteEntriesDeprecated(FILE *_fp,FileType type) {
-
- // restent a tester les echecs en ecriture (apres chaque fwrite)
-
- for (TagHeaderEntryHT::iterator tag2=tagHT.begin();
- tag2 != tagHT.end();
- ++tag2){
- if ( type == ACR ){
- if ((*tag2->second).GetGroup() < 0x0008) continue; // ignore pure DICOM V3 groups
- if ((*tag2->second).GetElement() %2) continue; // ignore shadow groups
- if ((*tag2->second).GetVR() == "SQ" ) continue; // ignore Sequences
- if ((*tag2->second).GetSQDepthLevel() != 0) continue; // Not only ignore the SQ element
- }
- if ( ! WriteEntry(tag2->second,_fp,type))
- break;
- }
-}
/**
* \brief Swaps back the bytes of 4-byte long integer accordingly to
a=( ((a<<8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) );
break;
default :
+ std::cout << "swapCode= " << sw << std::endl;
dbg.Error(" gdcmDocument::SwapLong : unset swap code");
a=0;
}
//-----------------------------------------------------------------------------
// Private
+/**
+ * \brief Parses a DocEntrySet (Zero-level DocEntries or SQ Item DocEntries)
+ * @return false if file is not ACR-NEMA / PAPYRUS / DICOM
+ */
+
+long gdcmDocument::ParseDES(gdcmDocEntrySet *set, long offset, long l_max, bool delim_mode) {
+
+ gdcmDocEntry *NewDocEntry = (gdcmDocEntry *)0;
+ gdcmValEntry *vl;
+ gdcmBinEntry *bn;
+ gdcmSeqEntry *sq;
+ VRKey vr;
+ long l;
+ int depth;
+
+ depth = set->GetDepthLevel();
+ while (true) {
+
+ if ( !delim_mode && ftell(fp)-offset >= l_max) {
+ break;
+ }
+ NewDocEntry = ReadNextDocEntry( );
+ if (!NewDocEntry)
+ break;
+
+ vr = NewDocEntry->GetVR();
+ if (vr!="SQ") {
+
+ if ( gdcmGlobal::GetVR()->IsVROfGdcmStringRepresentable(vr) )
+ {
+ /////// ValEntry
+ vl= new gdcmValEntry(NewDocEntry->GetDictEntry());
+ vl->Copy(NewDocEntry);
+ vl->SetDepthLevel(depth);
+ set->AddEntry(vl);
+ LoadDocEntry(vl);
+ if (/*!delim_mode && */vl->isItemDelimitor())
+ break;
+ if ( !delim_mode && ftell(fp)-offset >= l_max)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if ( ! gdcmGlobal::GetVR()->IsVROfGdcmBinaryRepresentable(vr) )
+ {
+ ////// Neither ValEntry NOR BinEntry: should mean UNKOWN VR
+ dbg.Verbose(0, "gdcmDocument::ParseDES: neither Valentry, "
+ "nor BinEntry. Probably unknown VR.");
+ }
+
+ ////// BinEntry or UNKOWN VR:
+ bn = new gdcmBinEntry(NewDocEntry->GetDictEntry());
+ bn->Copy(NewDocEntry);
+ set->AddEntry(bn);
+ LoadDocEntry(bn);
+ }
+
+ if (NewDocEntry->GetGroup() == 0x7fe0 &&
+ NewDocEntry->GetElement() == 0x0010 )
+ {
+ if (NewDocEntry->GetLength()==0xffffffff)
+ // Broken US.3405.1.dcm
+ Parse7FE0(); // to skip the pixels
+ // (multipart JPEG/RLE are trouble makers)
+ }
+ else
+ {
+ // to be sure we are at the beginning
+ SkipToNextDocEntry(NewDocEntry);
+ l = NewDocEntry->GetFullLength();
+ }
+ } else { // VR = "SQ"
+
+ l=NewDocEntry->GetReadLength();
+ if (l != 0) // don't mess the delim_mode for zero-length sequence
+ if (l == 0xffffffff)
+ delim_mode = true;
+ else
+ delim_mode = false;
+ // no other way to create it ...
+ sq = new gdcmSeqEntry(NewDocEntry->GetDictEntry(),
+ set->GetDepthLevel());
+ sq->Copy(NewDocEntry);
+ sq->SetDelimitorMode(delim_mode);
+ sq->SetDepthLevel(depth);
+
+ if (l != 0)
+ { // Don't try to parse zero-length sequences
+ long lgt = ParseSQ( sq,
+ NewDocEntry->GetOffset(),
+ l, delim_mode);
+ }
+ // FIXME : on en fait quoi, de lgt ?
+ set->AddEntry(sq);
+ if ( !delim_mode && ftell(fp)-offset >= l_max)
+ {
+ break;
+ }
+ }
+ }
+ delete NewDocEntry;
+ return l; // ??
+}
+
+/**
+ * \brief Parses a Sequence ( SeqEntry after SeqEntry)
+ * @return parsed length for this level
+ */
+long gdcmDocument::ParseSQ(gdcmSeqEntry *set, long offset, long l_max, bool delim_mode) {
+ int SQItemNumber = 0;
+ gdcmDocEntry *NewDocEntry = (gdcmDocEntry *)0;
+ gdcmSQItem *itemSQ;
+ bool dlm_mod;
+ int lgr, l, lgth;
+ int depth = set->GetDepthLevel();
+ while (true) {
+
+ NewDocEntry = ReadNextDocEntry();
+ if(delim_mode) {
+ if (NewDocEntry->isSequenceDelimitor()) {
+ //add the Sequence Delimitor // TODO : find the trick to put it properly !
+ set->SetSequenceDelimitationItem(NewDocEntry);
+ break;
+ }
+ }
+ if (!delim_mode && (ftell(fp)-offset) >= l_max) {
+ break;
+ }
+ itemSQ = new gdcmSQItem(set->GetDepthLevel());
+ itemSQ->AddEntry(NewDocEntry); // no value, no voidArea. Think of it while printing !
+ l= NewDocEntry->GetReadLength();
+
+ if (l ==0xffffffff)
+ dlm_mod = true;
+ else
+ dlm_mod=false;
+
+ lgr=ParseDES(itemSQ, NewDocEntry->GetOffset(), l, dlm_mod);
+
+ set->AddEntry(itemSQ);
+ SQItemNumber ++; // a voir
+ if (!delim_mode && (ftell(fp)-offset) >= l_max) {
+ break;
+ }
+ }
+ lgth = ftell(fp) - offset;
+ return(lgth);
+}
+
/**
* \brief Loads the element content if its length doesn't exceed
* the value specified with gdcmDocument::SetMaxSizeLoadEntry()
* @param Entry Header Entry (Dicom Element) to be dealt with
*/
-void gdcmDocument::LoadHeaderEntry(gdcmHeaderEntry *Entry) {
+void gdcmDocument::LoadDocEntry(gdcmDocEntry *Entry) {
size_t item_read;
guint16 group = Entry->GetGroup();
std::string vr= Entry->GetVR();
// (fffe e00d) tells us an Element just ended
// (fffe e0dd) tells us the current SeQuence just ended
if( group == 0xfffe ) {
- Entry->SetValue("gdcm::Skipped");
+ // NO more value field for SQ !
+ //Entry->SetValue("gdcm::Skipped");
+ // appel recursif de Load Value
+ // (meme pb que pour le parsing)
return;
}
// When the length is zero things are easy:
if ( length == 0 ) {
- Entry->SetValue("");
+ ((gdcmValEntry *)Entry)->SetValue("");
return;
}
// are not loaded. Instead we leave a short notice of the offset of
// the element content and it's length.
if (length > MaxSizeLoadEntry) {
- std::ostringstream s;
- s << "gdcm::NotLoaded.";
- s << " Address:" << (long)Entry->GetOffset();
- s << " Length:" << Entry->GetLength();
- s << " x(" << std::hex << Entry->GetLength() << ")";
- Entry->SetValue(s.str());
+ if (gdcmValEntry* ValEntryPtr = dynamic_cast< gdcmValEntry* >(Entry) )
+ {
+ std::ostringstream s;
+ s << "gdcm::NotLoaded.";
+ s << " Address:" << (long)Entry->GetOffset();
+ s << " Length:" << Entry->GetLength();
+ s << " x(" << std::hex << Entry->GetLength() << ")";
+ ValEntryPtr->SetValue(s.str());
+ }
+ // to be sure we are at the end of the value ...
+ fseek(fp,(long)Entry->GetOffset()+(long)Entry->GetLength(),SEEK_SET);
+
return;
}
// Any compacter code suggested (?)
- if ( IsHeaderEntryAnInteger(Entry) ) {
+ if ( IsDocEntryAnInteger(Entry) ) {
guint32 NewInt;
std::ostringstream s;
int nbInt;
s << std::ends; // to avoid oddities on Solaris
#endif //GDCM_NO_ANSI_STRING_STREAM
- Entry->SetValue(s.str());
+ ((gdcmValEntry *)Entry)->SetValue(s.str());
return;
}
item_read = fread(&(NewValue[0]), (size_t)length, (size_t)1, fp);
if ( item_read != 1 ) {
dbg.Verbose(1, "gdcmDocument::LoadElementValue","unread element value");
- Entry->SetValue("gdcm::UnRead");
+ ((gdcmValEntry *)Entry)->SetValue("gdcm::UnRead");
return;
}
if( (vr == "UI") ) // Because of correspondance with the VR dic
- Entry->SetValue(NewValue.c_str());
+ ((gdcmValEntry *)Entry)->SetValue(NewValue.c_str());
else
- Entry->SetValue(NewValue);
+ ((gdcmValEntry *)Entry)->SetValue(NewValue);
}
-/**
- * \brief add a new Dicom Element pointer to
- * the H Table and at the end of the chained List
- * \warning push_bash in listEntries ONLY during ParseHeader
- * \todo something to allow further Elements addition,
- * (at their right place in the chained list)
- * when position to be taken care of
- * @param newHeaderEntry
- */
-void gdcmDocument::AddHeaderEntry(gdcmHeaderEntry *newHeaderEntry) {
- tagHT.insert( PairHT( newHeaderEntry->GetKey(),newHeaderEntry) );
- listEntries.push_back(newHeaderEntry);
- wasUpdated = 1;
-}
/**
* \brief Find the value Length of the passed Header Entry
* @param Entry Header Entry whose length of the value shall be loaded.
*/
- void gdcmDocument::FindHeaderEntryLength (gdcmHeaderEntry *Entry) {
+ void gdcmDocument::FindDocEntryLength (gdcmDocEntry *Entry) {
guint16 element = Entry->GetElement();
//guint16 group = Entry->GetGroup(); //FIXME
std::string vr = Entry->GetVR();
guint16 length16;
- if ( (filetype == ExplicitVR) && (! Entry->IsImplicitVR()) )
+ if ( (filetype == gdcmExplicitVR) && (! Entry->IsImplicitVR()) )
{
if ( (vr=="OB") || (vr=="OW") || (vr=="SQ") || (vr=="UN") )
{
if ( (vr == "OB") && (length32 == 0xffffffff) )
{
- Entry->SetLength(FindHeaderEntryLengthOB());
+ Entry->SetLength(FindDocEntryLengthOB());
return;
}
- FixHeaderEntryFoundLength(Entry, length32);
+ FixDocEntryFoundLength(Entry, length32);
return;
}
// Actually, length= 0xffff means that we deal with
// Unknown Sequence Length
}
- FixHeaderEntryFoundLength(Entry, (guint32)length16);
+ FixDocEntryFoundLength(Entry, (guint32)length16);
return;
}
else
// not coexist in a Data Set and Data Sets nested within it".]
// Length is on 4 bytes.
- FixHeaderEntryFoundLength(Entry, ReadInt32());
+ FixDocEntryFoundLength(Entry, ReadInt32());
return;
}
}
* \brief Find the Value Representation of the current Dicom Element.
* @param Entry
*/
-void gdcmDocument::FindHeaderEntryVR( gdcmHeaderEntry *Entry)
+void gdcmDocument::FindDocEntryVR( gdcmDocEntry *Entry)
{
- if (filetype != ExplicitVR)
+ if (filetype != gdcmExplicitVR)
return;
char VR[3];
(void)fread (&VR, (size_t)2,(size_t)1, fp);
VR[2]=0;
- if(!CheckHeaderEntryVR(Entry,VR))
+ if(!CheckDocEntryVR(Entry,VR))
{
fseek(fp, PositionOnEntry, SEEK_SET);
// When this element is known in the dictionary we shall use, e.g. for
* @return false if the VR is incorrect of if the VR isn't referenced
* otherwise, it returns true
*/
-bool gdcmDocument::CheckHeaderEntryVR(gdcmHeaderEntry *Entry, VRKey vr)
+bool gdcmDocument::CheckDocEntryVR(gdcmDocEntry *Entry, VRKey vr)
{
char msg[100]; // for sprintf
bool RealExplicit = true;
* @param Entry
* @return Transformed entry value
*/
-std::string gdcmDocument::GetHeaderEntryValue(gdcmHeaderEntry *Entry)
+std::string gdcmDocument::GetDocEntryValue(gdcmDocEntry *Entry)
{
- if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
+ if ( (IsDocEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
{
- std::string val=Entry->GetValue();
+ std::string val=((gdcmValEntry *)Entry)->GetValue();
std::string vr=Entry->GetVR();
guint32 length = Entry->GetLength();
std::ostringstream s;
return(s.str());
}
- return(Entry->GetValue());
+ return(((gdcmValEntry *)Entry)->GetValue());
}
/**
* @param Entry
* @return Reverse transformed entry value
*/
-std::string gdcmDocument::GetHeaderEntryUnvalue(gdcmHeaderEntry *Entry)
+std::string gdcmDocument::GetDocEntryUnvalue(gdcmDocEntry *Entry)
{
- if ( (IsHeaderEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
+ if ( (IsDocEntryAnInteger(Entry)) && (Entry->IsImplicitVR()) )
{
std::string vr=Entry->GetVR();
std::ostringstream s;
guint16 NewInt16;
tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
- Tokenize (Entry->GetValue(), tokens, "\\");
+ Tokenize (((gdcmValEntry *)Entry)->GetValue(), tokens, "\\");
for (unsigned int i=0; i<tokens.size();i++)
{
NewInt16 = atoi(tokens[i].c_str());
guint32 NewInt32;
tokens.erase(tokens.begin(),tokens.end()); // clean any previous value
- Tokenize (Entry->GetValue(), tokens, "\\");
+ Tokenize (((gdcmValEntry *)Entry)->GetValue(), tokens, "\\");
for (unsigned int i=0; i<tokens.size();i++)
{
NewInt32 = atoi(tokens[i].c_str());
return(s.str());
}
- return(Entry->GetValue());
+ return(((gdcmValEntry *)Entry)->GetValue());
}
/**
* \warning NOT end user intended method !
* @param entry
*/
-void gdcmDocument::SkipHeaderEntry(gdcmHeaderEntry *entry)
+void gdcmDocument::SkipDocEntry(gdcmDocEntry *entry)
{
- SkipBytes(entry->GetLength());
+ SkipBytes(entry->GetLength());
}
+/**
+ * \brief Skips to the begining of the next Header Entry
+ * \warning NOT end user intended method !
+ * @param entry
+ */
+void gdcmDocument::SkipToNextDocEntry(gdcmDocEntry *entry)
+{
+ (void)fseek(fp, (long)(entry->GetOffset()), SEEK_SET);
+ (void)fseek(fp, (long)(entry->GetReadLength()), SEEK_CUR);
+}
+
+/**
+ * \brief Loads the value for a a given VLEntry
+ * \warning NOT end user intended method !
+ * @param entry
+ */
+void gdcmDocument::LoadVLEntry(gdcmDocEntry *entry)
+{
+ //SkipBytes(entry->GetLength());
+ LoadDocEntry(entry);
+}
/**
* \brief When the length of an element value is obviously wrong (because
* the parser went Jabberwocky) one can hope improving things by
* applying this heuristic.
*/
-void gdcmDocument::FixHeaderEntryFoundLength(gdcmHeaderEntry *Entry, guint32 FoundLength)
+void gdcmDocument::FixDocEntryFoundLength(gdcmDocEntry *Entry, guint32 FoundLength)
{
Entry->SetReadLength(FoundLength); // will be updated only if a bug is found
if ( FoundLength == 0xffffffff) {
* @param Entry The element value on which to apply the predicate.
* @return The result of the heuristical predicate.
*/
-bool gdcmDocument::IsHeaderEntryAnInteger(gdcmHeaderEntry *Entry) {
+bool gdcmDocument::IsDocEntryAnInteger(gdcmDocEntry *Entry) {
guint16 element = Entry->GetElement();
guint16 group = Entry->GetGroup();
std::string vr = Entry->GetVR();
// instead of giving up with an error message
//std::cout << s.str().c_str() << std::endl;
- // dbg.Error("gdcmDocument::IsHeaderEntryAnInteger",
+ // dbg.Error("gdcmDocument::IsDocEntryAnInteger",
// s.str().c_str());
}
}
* @return
*/
- guint32 gdcmDocument::FindHeaderEntryLengthOB(void) {
+ guint32 gdcmDocument::FindDocEntryLengthOB(void) {
// See PS 3.5-2001, section A.4 p. 49 on encapsulation of encoded pixel data.
guint16 g;
guint16 n;
// Use gdcmDocument::dicom_vr to test all the possibilities
// instead of just checking for UL, OB and UI !? group 0000
{
- filetype = ExplicitVR;
+ filetype = gdcmExplicitVR;
dbg.Verbose(1, "gdcmDocument::CheckSwap:",
"explicit Value Representation");
}
else
{
- filetype = ImplicitVR;
+ filetype = gdcmImplicitVR;
dbg.Verbose(1, "gdcmDocument::CheckSwap:",
"not an explicit Value Representation");
}
switch (s32) {
case 0x00040000 :
sw = 3412;
- filetype = ACR;
+ filetype = gdcmACR;
return true;
case 0x04000000 :
sw = 4321;
- filetype = ACR;
+ filetype = gdcmACR;
return true;
case 0x00000400 :
sw = 2143;
- filetype = ACR;
+ filetype = gdcmACR;
return true;
case 0x00000004 :
sw = 0;
- filetype = ACR;
+ filetype = gdcmACR;
return true;
default :
case 0x0004 :
case 0x0008 :
sw = 0;
- filetype = ACR;
+ filetype = gdcmACR;
return true;
case 0x0200 :
case 0x0400 :
case 0x0800 :
sw = 4321;
- filetype = ACR;
+ filetype = gdcmACR;
return true;
default :
dbg.Verbose(0, "gdcmDocument::CheckSwap:",
"ACR/NEMA unfound swap info (Really hopeless !)");
- filetype = Unknown;
+ filetype = gdcmUnknown;
return false;
}
MaxSizePrintEntry = NewSize;
}
-/**
- * \brief Searches both the public and the shadow dictionary (when they
- * exist) for the presence of the DictEntry with given name.
- * The public dictionary has precedence on the shadow one.
- * @param Name name of the searched DictEntry
- * @return Corresponding DictEntry when it exists, NULL otherwise.
- */
-gdcmDictEntry *gdcmDocument::GetDictEntryByName(std::string Name)
-{
- gdcmDictEntry *found = (gdcmDictEntry *)0;
- if (!RefPubDict && !RefShaDict)
- {
- dbg.Verbose(0, "gdcmDocument::GetDictEntry",
- "we SHOULD have a default dictionary");
- }
- if (RefPubDict)
- {
- found = RefPubDict->GetDictEntryByName(Name);
- if (found)
- return found;
- }
- if (RefShaDict)
- {
- found = RefShaDict->GetDictEntryByName(Name);
- if (found)
- return found;
- }
- return found;
-}
-/**
- * \brief Searches both the public and the shadow dictionary (when they
- * exist) for the presence of the DictEntry with given
- * group and element. The public dictionary has precedence on the
- * shadow one.
- * @param group group of the searched DictEntry
- * @param element element of the searched DictEntry
- * @return Corresponding DictEntry when it exists, NULL otherwise.
- */
-gdcmDictEntry *gdcmDocument::GetDictEntryByNumber(guint16 group,guint16 element)
-{
- gdcmDictEntry *found = (gdcmDictEntry *)0;
- if (!RefPubDict && !RefShaDict)
- {
- dbg.Verbose(0, "gdcmDocument::GetDictEntry",
- "we SHOULD have a default dictionary");
- }
- if (RefPubDict)
- {
- found = RefPubDict->GetDictEntryByNumber(group, element);
- if (found)
- return found;
- }
- if (RefShaDict)
- {
- found = RefShaDict->GetDictEntryByNumber(group, element);
- if (found)
- return found;
- }
- return found;
-}
/**
* \brief Read the next tag but WITHOUT loading it's value
- * @return On succes the newly created HeaderEntry, NULL on failure.
+ * (read the 'Group Number', the 'Element Number',
+ * gets the Dict Entry
+ * gets the VR, gets the length, gets the offset value)
+ * @return On succes the newly created DocEntry, NULL on failure.
*/
-gdcmHeaderEntry *gdcmDocument::ReadNextHeaderEntry(void) {
+gdcmDocEntry *gdcmDocument::ReadNextDocEntry(void) {
guint16 g,n;
- gdcmHeaderEntry *NewEntry;
+ gdcmDocEntry *NewEntry;
g = ReadInt16();
n = ReadInt16();
if (errno == 1)
// We reached the EOF (or an error occured) therefore
// header parsing has to be considered as finished.
- return (gdcmHeaderEntry *)0;
+ return (gdcmDocEntry *)0;
-// Pb : how to propagate the element length (used in SkipHeaderEntry)
+// Pb : how to propagate the element length (used in SkipDocEntry)
// direct call to SkipBytes ?
// if (ignoreShadow == 1 && g%2 ==1)
// if user wants to skip shadow groups
// and current element *is* a shadow element
// we don't create anything
-// return (gdcmHeaderEntry *)1; // to tell caller it's NOT finished
+// return (gdcmDocEntry *)1; // to tell caller it's NOT finished
- NewEntry = NewHeaderEntryByNumber(g, n);
- FindHeaderEntryVR(NewEntry);
- FindHeaderEntryLength(NewEntry);
+ NewEntry = NewDocEntryByNumber(g, n);
+ FindDocEntryVR(NewEntry);
+ FindDocEntryLength(NewEntry);
if (errno == 1) {
// Call it quits
+ delete NewEntry;
return NULL;
}
NewEntry->SetOffset(ftell(fp));
* a default one when absent.
* @param Name Name of the underlying DictEntry
*/
-gdcmHeaderEntry *gdcmDocument::NewHeaderEntryByName(std::string Name)
+gdcmDocEntry *gdcmDocument::NewDocEntryByName(std::string Name)
{
gdcmDictEntry *NewTag = GetDictEntryByName(Name);
if (!NewTag)
NewTag = NewVirtualDictEntry(0xffff, 0xffff, "LO", "unkn", Name);
- gdcmHeaderEntry* NewEntry = new gdcmHeaderEntry(NewTag);
+ gdcmDocEntry* NewEntry = new gdcmDocEntry(NewTag);
if (!NewEntry)
{
- dbg.Verbose(1, "gdcmDocument::ObtainHeaderEntryByName",
- "failed to allocate gdcmHeaderEntry");
- return (gdcmHeaderEntry *)0;
+ dbg.Verbose(1, "gdcmDocument::ObtainDocEntryByName",
+ "failed to allocate gdcmDocEntry");
+ return (gdcmDocEntry *)0;
}
return NewEntry;
}
/**
* \brief Request a new virtual dict entry to the dict set
- * @param group group of the underlying DictEntry
- * @param element element of the underlying DictEntry
+ * @param group group number of the underlying DictEntry
+ * @param element element number of the underlying DictEntry
* @param vr VR of the underlying DictEntry
* @param fourth owner group
* @param name english name
* \brief Build a new Element Value from all the low level arguments.
* Check for existence of dictionary entry, and build
* a default one when absent.
- * @param Group group of the underlying DictEntry
- * @param Elem element of the underlying DictEntry
+ * @param Group group number of the underlying DictEntry
+ * @param Elem element number of the underlying DictEntry
*/
-gdcmHeaderEntry *gdcmDocument::NewHeaderEntryByNumber(guint16 Group, guint16 Elem)
+gdcmDocEntry *gdcmDocument::NewDocEntryByNumber(guint16 Group, guint16 Elem)
{
// Find out if the tag we encountered is in the dictionaries:
gdcmDictEntry *DictEntry = GetDictEntryByNumber(Group, Elem);
if (!DictEntry)
DictEntry = NewVirtualDictEntry(Group, Elem);
- gdcmHeaderEntry *NewEntry = new gdcmHeaderEntry(DictEntry);
+ gdcmDocEntry *NewEntry = new gdcmDocEntry(DictEntry);
if (!NewEntry)
{
- dbg.Verbose(1, "gdcmDocument::NewHeaderEntryByNumber",
- "failed to allocate gdcmHeaderEntry");
+ dbg.Verbose(1, "gdcmDocument::NewDocEntryByNumber",
+ "failed to allocate gdcmDocEntry");
return NULL;
}
return NewEntry;
/// \todo Never used; commented out, waiting for removal.
/**
* \brief Small utility function that creates a new manually crafted
- * (as opposed as read from the file) gdcmHeaderEntry with user
+ * (as opposed as read from the file) gdcmDocEntry with user
* specified name and adds it to the public tag hash table.
* \note A fake TagKey is generated so the PubDict can keep it's coherence.
* @param NewTagName The name to be given to this new tag.
* @param VR The Value Representation to be given to this new tag.
* @return The newly hand crafted Element Value.
*/
-//gdcmHeaderEntry *gdcmDocument::NewManualHeaderEntryToPubDict(std::string NewTagName,
+//gdcmDocEntry *gdcmDocument::NewManualDocEntryToPubDict(std::string NewTagName,
// std::string VR)
//{
-// gdcmHeaderEntry *NewEntry = NULL;
+// gdcmDocEntry *NewEntry = NULL;
// guint32 StuffGroup = 0xffff; // Group to be stuffed with additional info
// guint32 FreeElem = 0;
// gdcmDictEntry *DictEntry = NULL;
// FreeElem = GenerateFreeTagKeyInGroup(StuffGroup);
// if (FreeElem == UINT32_MAX)
// {
-// dbg.Verbose(1, "gdcmHeader::NewManualHeaderEntryToPubDict",
+// dbg.Verbose(1, "gdcmHeader::NewManualDocEntryToPubDict",
// "Group 0xffff in Public Dict is full");
// return NULL;
// }
//
// DictEntry = NewVirtualDictEntry(StuffGroup, FreeElem,
// VR, "GDCM", NewTagName);
-// NewEntry = new gdcmHeaderEntry(DictEntry);
-// AddHeaderEntry(NewEntry);
+// NewEntry = new gdcmDocEntry(DictEntry);
+// AddEntry(NewEntry);
// return NewEntry;
//}
return UINT32_MAX;
}
+
+/**
+ * \brief Searches both the public and the shadow dictionary (when they
+ * exist) for the presence of the DictEntry with given name.
+ * The public dictionary has precedence on the shadow one.
+ * @param Name name of the searched DictEntry
+ * @return Corresponding DictEntry when it exists, NULL otherwise.
+ */
+gdcmDictEntry *gdcmDocument::GetDictEntryByName(std::string Name)
+{
+ gdcmDictEntry *found = (gdcmDictEntry *)0;
+ if (!RefPubDict && !RefShaDict)
+ {
+ dbg.Verbose(0, "gdcmDocument::GetDictEntry",
+ "we SHOULD have a default dictionary");
+ }
+ if (RefPubDict)
+ {
+ found = RefPubDict->GetDictEntryByName(Name);
+ if (found)
+ return found;
+ }
+ if (RefShaDict)
+ {
+ found = RefShaDict->GetDictEntryByName(Name);
+ if (found)
+ return found;
+ }
+ return found;
+}
+
+/**
+ * \brief Searches both the public and the shadow dictionary (when they
+ * exist) for the presence of the DictEntry with given
+ * group and element. The public dictionary has precedence on the
+ * shadow one.
+ * @param group group of the searched DictEntry
+ * @param element element of the searched DictEntry
+ * @return Corresponding DictEntry when it exists, NULL otherwise.
+ */
+gdcmDictEntry *gdcmDocument::GetDictEntryByNumber(guint16 group,guint16 element)
+{
+ gdcmDictEntry *found = (gdcmDictEntry *)0;
+ if (!RefPubDict && !RefShaDict)
+ {
+ dbg.Verbose(0, "gdcmDocument::GetDictEntry",
+ "we SHOULD have a default dictionary");
+ }
+ if (RefPubDict)
+ {
+ found = RefPubDict->GetDictEntryByNumber(group, element);
+ if (found)
+ return found;
+ }
+ if (RefShaDict)
+ {
+ found = RefShaDict->GetDictEntryByNumber(group, element);
+ if (found)
+ return found;
+ }
+ return found;
+}
+
+
+/**
+ * \ingroup gdcmDocument
+ * \brief Parse pixel data from disk for multi-fragment Jpeg/Rle files
+ * \ No other way so 'skip' the Data
+ *
+ */
+void gdcmDocument::Parse7FE0 (void) {
+
+ gdcmDocEntry* Element = GetDocEntryByNumber(0x0002, 0x0010);
+ if ( !Element )
+ return;
+
+ std::string Transfer = ((gdcmValEntry *)Element)->GetValue();
+ if (Transfer == UI1_2_840_10008_1_2 )
+ return;
+ if ( Transfer == UI1_2_840_10008_1_2_1 )
+ return;
+ if ( Transfer == UI1_2_840_10008_1_2_2 ) //1.2.2 ??? A verifier !
+ return;
+ if ( Transfer == UI1_2_840_10008_1_2_1_99 )
+ return;
+
+ int nb;
+ std::string str_nb=GetEntryByNumber(0x0028,0x0100);
+ if (str_nb == GDCM_UNFOUND ) {
+ nb = 16;
+ } else {
+ nb = atoi(str_nb.c_str() );
+ if (nb == 12) nb =16;
+ }
+
+ guint16 ItemTagGr,ItemTagEl;
+ int ln;
+ long ftellRes;
+
+ // -------------------- for Parsing : Position on begining of Jpeg/RLE Pixels
+
+ if ( Transfer != UI1_1_2_840_10008_1_2_5 ) { // !RLELossLessTransferSyntax
+ // JPEG Image
+ ftellRes=ftell(fp);
+ fread(&ItemTagGr,2,1,fp); //Reading (fffe):Basic Offset Table Item Tag Gr
+ fread(&ItemTagEl,2,1,fp); //Reading (e000):Basic Offset Table Item Tag El
+ if(GetSwapCode()) {
+ ItemTagGr=SwapShort(ItemTagGr);
+ ItemTagEl=SwapShort(ItemTagEl);
+ }
+ printf ("at %x : ItemTag (should be fffe,e000): %04x,%04x\n",
+ (unsigned)ftellRes,ItemTagGr,ItemTagEl );
+ ftellRes=ftell(fp);
+ fread(&ln,4,1,fp);
+ if(GetSwapCode())
+ ln=SwapLong(ln); // Basic Offset Table Item Length
+ printf("at %x : Basic Offset Table Item Length (\?\?) %d x(%08x)\n",
+ (unsigned)ftellRes,ln,ln);
+ if (ln != 0) {
+ // What is it used for ??
+ char * BasicOffsetTableItemValue= new char[ln+1];
+ fread(BasicOffsetTableItemValue,ln,1,fp);
+ guint32 a;
+ for (int i=0;i<ln;i+=4){
+ a=str2num(&BasicOffsetTableItemValue[i],guint32);
+ printf(" x(%08x) %d\n",a,a);
+ }
+ }
+
+ ftellRes=ftell(fp);
+ fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
+ fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
+ if(GetSwapCode()) {
+ ItemTagGr=SwapShort(ItemTagGr);
+ ItemTagEl=SwapShort(ItemTagEl);
+ }
+ printf ("at %x : ItemTag (should be fffe,e000 or e0dd): %04x,%04x\n",
+ (unsigned)ftellRes,ItemTagGr,ItemTagEl );
+
+ while ( ( ItemTagGr==0xfffe) && (ItemTagEl!=0xe0dd) ) { // Parse fragments
+
+ ftellRes=ftell(fp);
+ fread(&ln,4,1,fp);
+ if(GetSwapCode())
+ ln=SwapLong(ln); // length
+ printf(" at %x : fragment length %d x(%08x)\n",
+ (unsigned)ftellRes, ln,ln);
+
+ // ------------------------
+ fseek(fp,ln,SEEK_CUR); // skipping (not reading) fragment pixels
+ // ------------------------
+
+ ftellRes=ftell(fp);
+ fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
+ fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
+ if(GetSwapCode()) {
+ ItemTagGr=SwapShort(ItemTagGr);
+ ItemTagEl=SwapShort(ItemTagEl);
+ }
+ printf ("at %x : ItemTag (should be fffe,e000 or e0dd): %04x,%04x\n",
+ (unsigned)ftellRes,ItemTagGr,ItemTagEl );
+ }
+
+ } else {
+
+ // RLE Image
+ long RleSegmentLength[15],fragmentLength;
+ guint32 nbRleSegments;
+ guint32 RleSegmentOffsetTable[15];
+ ftellRes=ftell(fp);
+ // Basic Offset Table with Item Value
+ // Item Tag
+ fread(&ItemTagGr,2,1,fp); //Reading (fffe):Basic Offset Table Item Tag Gr
+ fread(&ItemTagEl,2,1,fp); //Reading (e000):Basic Offset Table Item Tag El
+ if(GetSwapCode()) {
+ ItemTagGr=SwapShort(ItemTagGr);
+ ItemTagEl=SwapShort(ItemTagEl);
+ }
+ printf ("at %x : ItemTag (should be fffe,e000): %04x,%04x\n",
+ (unsigned)ftellRes,ItemTagGr,ItemTagEl );
+ // Item Length
+ ftellRes=ftell(fp);
+ fread(&ln,4,1,fp);
+ if(GetSwapCode())
+ ln=SwapLong(ln); // Basic Offset Table Item Length
+ printf("at %x : Basic Offset Table Item Length (\?\?) %d x(%08x)\n",
+ (unsigned)ftellRes,ln,ln);
+ if (ln != 0) {
+ // What is it used for ??
+ char * BasicOffsetTableItemValue= new char[ln+1];
+ fread(BasicOffsetTableItemValue,ln,1,fp);
+ guint32 a;
+ for (int i=0;i<ln;i+=4){
+ a=str2num(&BasicOffsetTableItemValue[i],guint32);
+ printf(" x(%08x) %d\n",a,a);
+ }
+ }
+
+ ftellRes=ftell(fp);
+ fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
+ fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
+ if(GetSwapCode()) {
+ ItemTagGr=SwapShort(ItemTagGr);
+ ItemTagEl=SwapShort(ItemTagEl);
+ }
+ printf ("at %x : ItemTag (should be fffe,e000 or e0dd): %04x,%04x\n",
+ (unsigned)ftellRes,ItemTagGr,ItemTagEl );
+
+ // while 'Sequence Delimiter Item' (fffe,e0dd) not found
+ while ( ( ItemTagGr == 0xfffe) && (ItemTagEl != 0xe0dd) ) {
+ // Parse fragments of the current Fragment (Frame)
+ ftellRes=ftell(fp);
+ fread(&fragmentLength,4,1,fp);
+ if(GetSwapCode())
+ fragmentLength=SwapLong(fragmentLength); // length
+ printf(" at %x : 'fragment' length %d x(%08x)\n",
+ (unsigned)ftellRes, (unsigned)fragmentLength,(unsigned)fragmentLength);
+
+ //------------------ scanning (not reading) fragment pixels
+
+ fread(&nbRleSegments,4,1,fp); // Reading : Number of RLE Segments
+ if(GetSwapCode())
+ nbRleSegments=SwapLong(nbRleSegments);
+ printf(" Nb of RLE Segments : %d\n",nbRleSegments);
+
+ for(int k=1; k<=15; k++) { // Reading RLE Segments Offset Table
+ ftellRes=ftell(fp);
+ fread(&RleSegmentOffsetTable[k],4,1,fp);
+ if(GetSwapCode())
+ RleSegmentOffsetTable[k]=SwapLong(RleSegmentOffsetTable[k]);
+ printf(" at : %x Offset Segment %d : %d (%x)\n",
+ (unsigned)ftellRes,k,RleSegmentOffsetTable[k],
+ RleSegmentOffsetTable[k]);
+ }
+
+ if (nbRleSegments>1) { // skipping (not reading) RLE Segments
+ for(unsigned int k=1; k<=nbRleSegments-1; k++) {
+ RleSegmentLength[k]= RleSegmentOffsetTable[k+1]
+ - RleSegmentOffsetTable[k];
+ ftellRes=ftell(fp);
+ printf (" Segment %d : Length = %d x(%x) Start at %x\n",
+ k,(unsigned)RleSegmentLength[k],(unsigned)RleSegmentLength[k], (unsigned)ftellRes);
+ fseek(fp,RleSegmentLength[k],SEEK_CUR);
+ }
+ }
+ RleSegmentLength[nbRleSegments]= fragmentLength
+ - RleSegmentOffsetTable[nbRleSegments];
+ ftellRes=ftell(fp);
+ printf (" Segment %d : Length = %d x(%x) Start at %x\n",
+ nbRleSegments,(unsigned)RleSegmentLength[nbRleSegments],
+ (unsigned)RleSegmentLength[nbRleSegments],(unsigned)ftellRes);
+
+ fseek(fp,RleSegmentLength[nbRleSegments],SEEK_CUR);
+
+ // ------------------ end of scanning fragment pixels
+
+ ftellRes=ftell(fp);
+ fread(&ItemTagGr,2,1,fp); // Reading (fffe) : Item Tag Gr
+ fread(&ItemTagEl,2,1,fp); // Reading (e000) : Item Tag El
+ if(GetSwapCode()) {
+ ItemTagGr=SwapShort(ItemTagGr);
+ ItemTagEl=SwapShort(ItemTagEl);
+ }
+ printf ("at %x : ItemTag (should be fffe,e000 or e0dd): %04x,%04x\n",
+ (unsigned)ftellRes,ItemTagGr,ItemTagEl );
+ }
+ }
+ return;
+}
+
+
+
//-----------------------------------------------------------------------------