Program: gdcm
Module: $RCSfile: gdcmDocument.cxx,v $
Language: C++
- Date: $Date: 2005/01/08 15:03:59 $
- Version: $Revision: 1.168 $
+ Date: $Date: 2005/01/11 23:06:35 $
+ Version: $Revision: 1.180 $
Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
l'Image). All rights reserved. See Doc/License.txt or
namespace gdcm
{
-//-----------------------------------------------------------------------------
-static const char *TransferSyntaxStrings[] = {
- // Implicit VR Little Endian
- "1.2.840.10008.1.2",
- // Implicit VR Big Endian DLX G.E?
- "1.2.840.113619.5.2",
- // Explicit VR Little Endian
- "1.2.840.10008.1.2.1",
- // Deflated Explicit VR Little Endian
- "1.2.840.10008.1.2.1.99",
- // Explicit VR Big Endian
- "1.2.840.10008.1.2.2",
- // JPEG Baseline (Process 1)
- "1.2.840.10008.1.2.4.50",
- // JPEG Extended (Process 2 & 4)
- "1.2.840.10008.1.2.4.51",
- // JPEG Extended (Process 3 & 5)
- "1.2.840.10008.1.2.4.52",
- // JPEG Spectral Selection, Non-Hierarchical (Process 6 & 8)
- "1.2.840.10008.1.2.4.53",
- // JPEG Full Progression, Non-Hierarchical (Process 10 & 12)
- "1.2.840.10008.1.2.4.55",
- // JPEG Lossless, Non-Hierarchical (Process 14)
- "1.2.840.10008.1.2.4.57",
- // JPEG Lossless, Hierarchical, First-Order Prediction (Process 14, [Selection Value 1])
- "1.2.840.10008.1.2.4.70",
- // JPEG 2000 Lossless
- "1.2.840.10008.1.2.4.90",
- // JPEG 2000
- "1.2.840.10008.1.2.4.91",
- // RLE Lossless
- "1.2.840.10008.1.2.5",
- // Unknown
- "Unknown Transfer Syntax"
-};
//-----------------------------------------------------------------------------
// Refer to Document::CheckSwap()
return;
}
+ Group0002Parsed = false;
+
gdcmVerboseMacro( "Starting parsing of file: " << Filename.c_str());
- Fp->seekg( 0, std::ios::beg);
+ // Fp->seekg( 0, std::ios::beg);
Fp->seekg(0, std::ios::end);
long lgt = Fp->tellg();
SetMaxSizeLoadEntry(MAX_SIZE_LOAD_ELEMENT_VALUE);
Initialise();
- SwapCode = 0;
+ SwapCode = 1234;
Filetype = ExplicitVR;
+ Group0002Parsed = false;
}
/**
* value from disk when only parsing occured).
* @return The encountered Transfer Syntax of the current document.
*/
-TransferSyntaxType Document::GetTransferSyntax()
+std::string Document::GetTransferSyntax()
{
DocEntry *entry = GetDocEntry(0x0002, 0x0010);
if ( !entry )
{
- return UnknownTS;
+ return GDCM_UNKNOWN;
}
// The entry might be present but not loaded (parsing and loading
if ( transfer.length() == 0 )
{
// for brain damaged headers
- return UnknownTS;
+ return GDCM_UNKNOWN;
}
while ( !isdigit((unsigned char)transfer[transfer.length()-1]) )
{
transfer.erase(transfer.length()-1, 1);
}
- for (int i = 0; TransferSyntaxStrings[i] != NULL; i++)
- {
- if ( TransferSyntaxStrings[i] == transfer )
- {
- return TransferSyntaxType(i);
- }
- }
+ return transfer;
}
- return UnknownTS;
-}
-
-bool Document::IsJPEGLossless()
-{
- TransferSyntaxType r = GetTransferSyntax();
- return r == JPEGFullProgressionProcess10_12
- || r == JPEGLosslessProcess14
- || r == JPEGLosslessProcess14_1;
-}
-
-/**
- * \brief Determines if the Transfer Syntax was already encountered
- * and if it corresponds to a JPEG2000 one
- * @return True when JPEG2000 (Lossly or LossLess) found. False in all
- * other cases.
- */
-bool Document::IsJPEG2000()
-{
- TransferSyntaxType r = GetTransferSyntax();
- return r == JPEG2000Lossless || r == JPEG2000;
-}
-
-/**
- * \brief Determines if the Transfer Syntax corresponds to any form
- * of Jpeg encoded Pixel data.
- * @return True when any form of JPEG found. False otherwise.
- */
-bool Document::IsJPEG()
-{
- TransferSyntaxType r = GetTransferSyntax();
- return r == JPEGBaselineProcess1
- || r == JPEGExtendedProcess2_4
- || r == JPEGExtendedProcess3_5
- || r == JPEGSpectralSelectionProcess6_8
- || IsJPEGLossless()
- || IsJPEG2000();
-}
-
-/**
- * \brief Determines if the Transfer Syntax corresponds to encapsulated
- * of encoded Pixel Data (as opposed to native).
- * @return True when encapsulated. False when native.
- */
-bool Document::IsEncapsulate()
-{
- TransferSyntaxType r = GetTransferSyntax();
- return IsJPEG() || r == RLELossless;
+ return GDCM_UNKNOWN;
}
/**
*/
bool Document::IsDicomV3()
{
- // Checking if Transfert Syntax exists is enough
+ // Checking if Transfer Syntax exists is enough
// Anyway, it's to late check if the 'Preamble' was found ...
// And ... would it be a rich idea to check ?
// (some 'no Preamble' DICOM images exist !)
*/
std::ifstream *Document::OpenFile()
{
+
+ HasDCMPreamble = false;
if (Filename.length() == 0)
{
return 0;
if(Fp)
{
- gdcmVerboseMacro( "Is already opened when opening: " << Filename.c_str());
+ gdcmVerboseMacro( "File already open: " << Filename.c_str());
}
Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 ||
zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 )
{
+ std::string msg
+ = Util::Format("ACR/DICOM with no preamble: (%04x)\n", zero);
+ gdcmVerboseMacro( msg.c_str() );
return Fp;
}
}
if( memcmp(dicm, "DICM", 4) == 0 )
{
+ HasDCMPreamble = true;
return Fp;
}
return true;
}
-std::string Document::GetTransferSyntaxValue(TransferSyntaxType type)
-{
- return TransferSyntaxStrings[type];
-}
-
//-----------------------------------------------------------------------------
// Protected
/// \todo check the result
Fp->read((char*)a, l);
- if( Fp->fail() || Fp->eof()) //Fp->gcount() == 1
+ if( Fp->fail() || Fp->eof())
{
delete[] a;
return;
{
switch (SwapCode)
{
- case 0 :
+ case 1234 :
break;
case 4321 :
a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) |
a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) );
break;
default :
- //std::cout << "swapCode= " << SwapCode << std::endl;
- gdcmErrorMacro( "Unset swap code");
+ gdcmErrorMacro( "Unset swap code:" << SwapCode );
a = 0;
}
return a;
if ( ( newDocEntry->GetGroup() == 0x7fe0 )
&& ( newDocEntry->GetElement() == 0x0010 ) )
{
- TransferSyntaxType ts = GetTransferSyntax();
- if ( ts == RLELossless )
+ std::string ts = GetTransferSyntax();
+ if ( Global::GetTS()->IsRLELossless(ts) )
{
long positionOnEntry = Fp->tellg();
Fp->seekg( newDocEntry->GetOffset(), std::ios::beg );
ComputeRLEInfo();
Fp->seekg( positionOnEntry, std::ios::beg );
}
- else if ( IsJPEG() )
+ else if ( Global::GetTS()->IsJPEG(ts) )
{
long positionOnEntry = Fp->tellg();
Fp->seekg( newDocEntry->GetOffset(), std::ios::beg );
else
{
// fusible
- std::cout<< "MaxSizeLoadEntry exceeded, neither a BinEntry "
- << "nor a ValEntry ?! Should never print that !" << std::endl;
+ gdcmErrorMacro( "MaxSizeLoadEntry exceeded, neither a BinEntry "
+ << "nor a ValEntry ?! Should never print that !" );
}
// to be sure we are at the end of the value ...
if( length % 2 )
{
newValue = Util::DicomString(str, length+1);
- gdcmVerboseMacro("Warning: bad length: " << length );
- gdcmVerboseMacro("For string :" << newValue.c_str());
+ gdcmVerboseMacro("Warning: bad length: " << length <<
+ ",For string :" << newValue.c_str());
// Since we change the length of string update it length
//entry->SetReadLength(length+1);
}
if ( ValEntry *valEntry = dynamic_cast<ValEntry* >(entry) )
{
- if ( Fp->fail() || Fp->eof())//Fp->gcount() == 1
+ if ( Fp->fail() || Fp->eof())
{
- gdcmVerboseMacro( "Unread element value");
+ gdcmVerboseMacro("Unread element value");
valEntry->SetValue(GDCM_UNREAD);
return;
}
// big endian and proceed...
if ( element == 0x0000 && length16 == 0x0400 )
{
- TransferSyntaxType ts = GetTransferSyntax();
- if ( ts != ExplicitVRBigEndian )
+ std::string ts = GetTransferSyntax();
+ if ( Global::GetTS()->GetSpecialTransferSyntax(ts)
+ != TS::ExplicitVRBigEndian )
{
throw FormatError( "Document::FindDocEntryLength()",
" not explicit VR." );
return;
}
length16 = 4;
- SwitchSwapToBigEndian();
+ SwitchByteSwapCode();
// Restore the unproperly loaded values i.e. the group, the element
// and the dictionary entry depending on them.
uint16_t correctGroup = SwapShort( entry->GetGroup() );
uint16_t correctElem = SwapShort( entry->GetElement() );
- DictEntry *newTag = GetDictEntry( correctGroup,
- correctElem );
+ DictEntry *newTag = GetDictEntry( correctGroup, correctElem );
if ( !newTag )
{
// This correct tag is not in the dictionary. Create a new one.
std::string Document::FindDocEntryVR()
{
if ( Filetype != ExplicitVR )
- return(GDCM_UNKNOWN);
+ return GDCM_UNKNOWN;
long positionOnEntry = Fp->tellg();
// Warning: we believe this is explicit VR (Value Representation) because
if( !CheckDocEntryVR(vr) )
{
Fp->seekg(positionOnEntry, std::ios::beg);
- return(GDCM_UNKNOWN);
+ return GDCM_UNKNOWN;
}
- return(vr);
+ return vr;
}
/**
/**
* \brief Skips to the begining of the next Header Entry
* \warning NOT end user intended method !
- * @param offset start of skipping
- * @param readLgth length to skip
-
+ * @param currentDocEntry entry to skip
*/
-void Document::SkipToNextDocEntry(DocEntry *newDocEntry)
+void Document::SkipToNextDocEntry(DocEntry *currentDocEntry)
{
- Fp->seekg((long)(newDocEntry->GetOffset()), std::ios::beg);
- Fp->seekg( (long)(newDocEntry->GetReadLength()),std::ios::cur);
+ Fp->seekg((long)(currentDocEntry->GetOffset()), std::ios::beg);
+ Fp->seekg( (long)(currentDocEntry->GetReadLength()),std::ios::cur);
}
/**
* the parser went Jabberwocky) one can hope improving things by
* applying some heuristics.
* @param entry entry to check
- * @param foundLength fist assumption about length
+ * @param foundLength first assumption about length
*/
void Document::FixDocEntryFoundLength(DocEntry *entry,
uint32_t foundLength)
*/
bool Document::IsDocEntryAnInteger(DocEntry *entry)
{
- uint16_t element = entry->GetElement();
+ uint16_t elem = entry->GetElement();
uint16_t group = entry->GetGroup();
const std::string &vr = entry->GetVR();
uint32_t length = entry->GetLength();
// When we have some semantics on the element we just read, and if we
// a priori know we are dealing with an integer, then we shall be
// able to swap it's element value properly.
- if ( element == 0 ) // This is the group length of the group
+ if ( elem == 0 ) // This is the group length of the group
{
if ( length == 4 )
{
// message and proceed on parsing (while crossing fingers).
long filePosition = Fp->tellg();
gdcmVerboseMacro( "Erroneous Group Length element length on : ("
- << std::hex << group << " , " << element
+ << std::hex << group << " , " << elem
<< ") -before- position x(" << filePosition << ")"
<< "lgt : " << length );
}
}
catch ( FormatError )
{
- throw FormatError("Document::FindDocEntryLengthOBOrOW()",
- " group or element not present.");
+ throw FormatError("Unexpected end of file encountered during ",
+ "Document::FindDocEntryLengthOBOrOW()");
}
// We have to decount the group and element we just read
if ( group != 0xfffe || ( ( elem != 0xe0dd ) && ( elem != 0xe000 ) ) )
{
- gdcmVerboseMacro( "Neither an Item tag nor a Sequence delimiter tag.");
+ long filePosition = Fp->tellg();
+ gdcmVerboseMacro( "Neither an Item tag nor a Sequence delimiter tag on :"
+ << std::hex << group << " , " << elem
+ << ") -before- position x(" << filePosition << ")" );
+
Fp->seekg(positionOnEntry, std::ios::beg);
throw FormatUnexpected( "Neither an Item tag nor a Sequence delimiter tag.");
}
// FIXME : FIXME:
// Sometimes (see : gdcmData/icone.dcm) group 0x0002 *is* Explicit VR,
- // but elem 0002,0010 (Transfert Syntax) tells us the file is
+ // but elem 0002,0010 (Transfer Syntax) tells us the file is
// *Implicit* VR. -and it is !-
if( memcmp(entCur, "UL", (size_t)2) == 0 ||
}
else
{
- SwapCode = 0;
+ SwapCode = 1234;
gdcmVerboseMacro( "HostByteOrder = NetworkByteOrder");
}
Filetype = ACR;
return true;
case 0x00000004 :
- SwapCode = 0;
+ SwapCode = 1234;
Filetype = ACR;
return true;
default :
case 0x0006 :
case 0x0007 :
case 0x0008 :
- SwapCode = 0;
+ SwapCode = 1234;
Filetype = ACR;
return true;
case 0x0100 :
}
// Then the only info we have is the net2host one.
//if (! net2host )
- // SwapCode = 0;
+ // SwapCode = 1234;
//else
// SwapCode = 4321;
//return;
/**
- * \brief Restore the unproperly loaded values i.e. the group, the element
- * and the dictionary entry depending on them.
+ * \brief Change the Byte Swap code.
*/
-void Document::SwitchSwapToBigEndian()
+void Document::SwitchByteSwapCode()
{
- gdcmVerboseMacro( "Switching to BigEndian mode.");
- if ( SwapCode == 0 )
+ gdcmVerboseMacro( "Switching Byte Swap code.");
+ if ( SwapCode == 1234 )
{
SwapCode = 4321;
}
else if ( SwapCode == 4321 )
{
- SwapCode = 0;
+ SwapCode = 1234;
}
else if ( SwapCode == 3412 )
{
* apparent reason
* @return no return
*/
-void Document::HandleBrokenEndian(uint16_t group, uint16_t elem)
+void Document::HandleBrokenEndian(uint16_t &group, uint16_t &elem)
{
// Endian reversion. Some files contain groups of tags with reversed endianess.
static int reversedEndian = 0;
{
// start endian swap mark for group found
reversedEndian++;
- SwitchSwapToBigEndian();
+ SwitchByteSwapCode();
// fix the tag
group = 0xfffe;
elem = 0xe000;
}
- else if ((group == 0xfffe) && (elem == 0xe00d) && reversedEndian)
+ else if (group == 0xfffe && elem == 0xe00d && reversedEndian)
{
// end of reversed endian group
reversedEndian--;
- SwitchSwapToBigEndian();
+ SwitchByteSwapCode();
+ }
+}
+
+/**
+ * \brief Accesses the info from 0002,0010 : Transfer Syntax and TS
+ * else 1.
+ * @return The full Transfer Syntax Name (as opposed to Transfer Syntax UID)
+ */
+std::string Document::GetTransferSyntaxName()
+{
+ // use the TS (TS : Transfer Syntax)
+ std::string transferSyntax = GetEntry(0x0002,0x0010);
+
+ if ( transferSyntax == GDCM_NOTLOADED )
+ {
+ gdcmVerboseMacro( "Transfer Syntax not loaded. " << std::endl
+ << "Better you increase MAX_SIZE_LOAD_ELEMENT_VALUE" );
+ return "Uncompressed ACR-NEMA";
+ }
+ if ( transferSyntax == GDCM_UNFOUND )
+ {
+ gdcmVerboseMacro( "Unfound Transfer Syntax (0002,0010)");
+ return "Uncompressed ACR-NEMA";
+ }
+
+ while ( ! isdigit((unsigned char)transferSyntax[transferSyntax.length()-1]) )
+ {
+ transferSyntax.erase(transferSyntax.length()-1, 1);
+ }
+ // we do it only when we need it
+ TS* ts = Global::GetTS();
+ std::string tsName = ts->GetValue( transferSyntax );
+
+ // Global::GetTS() is a global static you shall never try to delete it!
+ return tsName;
+}
+
+/**
+ * \brief Group 0002 is always coded Little Endian
+ * whatever Transfer Syntax is
+ * @return no return
+ */
+void Document::HandleOutOfGroup0002(uint16_t group)
+{
+ // Endian reversion. Some files contain groups of tags with reversed endianess.
+ if ( !Group0002Parsed && group != 0x0002)
+ {
+ Group0002Parsed = true;
+ // we just came out of group 0002
+ // if Transfer syntax is Big Endian we have to change CheckSwap
+
+ std::string ts = GetTransferSyntaxName();
+ if ( !Global::GetTS()->IsTransferSyntax(ts) )
+ {
+ gdcmVerboseMacro("True DICOM File, with NO Tansfer Syntax: " << ts );
+ return;
+ }
+
+ // FIXME Strangely, this works with
+ //'Implicit VR Transfer Syntax (GE Private)
+ if ( Global::GetTS()->GetSpecialTransferSyntax(ts) == TS::ExplicitVRBigEndian )
+ {
+ gdcmVerboseMacro("Tansfer Syntax = Explicit VR - Big Endian");
+ SwitchByteSwapCode();
+ }
}
}
/**
* \brief Read the next tag but WITHOUT loading it's value
* (read the 'Group Number', the 'Element Number',
- * gets the Dict Entry
+ * gets the Dict Entry
* gets the VR, gets the length, gets the offset value)
* @return On succes the newly created DocEntry, NULL on failure.
*/
return 0;
}
+ // Sometimes file contains groups of tags with reversed endianess.
HandleBrokenEndian(group, elem);
+
+// In 'true DICOM' files Group 0002 is allways little endian
+ if ( HasDCMPreamble )
+ HandleOutOfGroup0002(group);
+
std::string vr = FindDocEntryVR();
std::string realVR = vr;
<< std::hex << testGroup << "," << testElement << ")" << std::endl
<< " but instead we encountered tag ("
<< std::hex << itemTagGroup << "," << itemTagElement << ")"
- << std::endl
- << " at address: " << (unsigned int)currentPosition );
+ << " at address: " << " 0x(" << (unsigned int)currentPosition << ")"
+ ) ;
Fp->seekg(positionOnEntry, std::ios::beg);
return false;
{
gdcmVerboseMacro( "Basic Item Length is: "
<< itemLength << std::endl
- << " at address: " << (unsigned int)currentPosition);
+ << " at address: " << std::hex << (unsigned int)currentPosition);
}
return itemLength;
}
*/
void Document::ComputeRLEInfo()
{
- TransferSyntaxType ts = GetTransferSyntax();
- if ( ts != RLELossless )
+ std::string ts = GetTransferSyntax();
+ if ( !Global::GetTS()->IsRLELossless(ts) )
{
return;
}
void Document::ComputeJPEGFragmentInfo()
{
// If you need to, look for comments of ComputeRLEInfo().
- if ( ! IsJPEG() )
+ std::string ts = GetTransferSyntax();
+ if ( ! Global::GetTS()->IsJPEG(ts) )
{
return;
}