+ * \brief Swaps back the bytes of 4-byte long integer accordingly to
+ * processor order.
+ * @return The properly swaped 32 bits integer.
+ */
+uint32_t Document::SwapLong(uint32_t a)
+{
+ switch (SwapCode)
+ {
+ case 1234 :
+ break;
+ case 4321 :
+// a=( ((a<<24) & 0xff000000) | ((a<<8) & 0x00ff0000) |
+// ((a>>8) & 0x0000ff00) | ((a>>24) & 0x000000ff) );
+// save CPU time
+ a=( ( a<<24) | ((a<<8) & 0x00ff0000) |
+ ((a>>8) & 0x0000ff00) | (a>>24) );
+ break;
+ case 3412 :
+// a=( ((a<<16) & 0xffff0000) | ((a>>16) & 0x0000ffff) );
+ a=( (a<<16) | (a>>16) );
+ break;
+ case 2143 :
+ a=( ((a<< 8) & 0xff00ff00) | ((a>>8) & 0x00ff00ff) );
+ break;
+ default :
+ gdcmErrorMacro( "Unexpected swap code:" << SwapCode );
+ a = 0;
+ }
+ return a;
+}
+
+/**
+ * \brief Swaps back the bytes of 8-byte long 'double' accordingly to
+ * processor order.
+ * @return The properly swaped 64 bits double.
+ */
+double Document::SwapDouble(double a)
+{
+ switch (SwapCode)
+ {
+ // There were no 'double' at ACR-NEMA time.
+ // We just have to deal with 'straight Little Endian' and
+ // 'straight Big Endian'
+ case 1234 :
+ break;
+ case 4321 :
+ {
+ char *beg = (char *)&a;
+ char *end = beg + 7;
+ char t;
+ for (unsigned int i = 0; i<7; i++)
+ {
+ t = *beg;
+ *beg = *end;
+ *end = t;
+ beg++,
+ end--;
+ }
+ }
+ break;
+ default :
+ gdcmErrorMacro( "Unexpected swap code:" << SwapCode );
+ a = 0.;
+ }
+ return a;
+}
+
+//
+// -----------------File I/O ---------------
+/**
+ * \brief Tries to open the file \ref Document::Filename and
+ * checks the preamble when existing,
+ * or if the file starts with an ACR-NEMA look-like element.
+ * @return The FILE pointer on success, 0 on failure.
+ */
+std::ifstream *Document::OpenFile()
+{
+ HasDCMPreamble = false;
+ if (Filename.length() == 0)
+ {
+ return 0;
+ }
+
+ if ( Fp )
+ {
+ gdcmDebugMacro( "File already open: " << Filename.c_str());
+ CloseFile();
+ }
+
+ Fp = new std::ifstream(Filename.c_str(), std::ios::in | std::ios::binary);
+ if ( ! *Fp )
+ {
+ // Don't user gdcmErrorMacro :
+ // a spurious message will appear when you use, for instance
+ // gdcm::FileHelper *fh = new gdcm::FileHelper( outputFileName );
+ // to create outputFileName.
+
+ // FIXME : if the upper comment is still usefull
+ // --> the constructor is not so good ...
+
+ gdcmWarningMacro( "Cannot open file: " << Filename.c_str());
+ delete Fp;
+ Fp = 0;
+ return 0;
+ //exit(1); // No function is allowed to leave the application instead
+ // of warning the caller
+ }
+
+ uint16_t zero = 0;
+ Fp->read((char*)&zero, (size_t)2);
+ if ( Fp->eof() )
+ {
+ CloseFile();
+ return 0;
+ }
+
+ //-- DICOM --
+ Fp->seekg(126L, std::ios::cur); // Once per Document
+ char dicm[4]; // = {' ',' ',' ',' '};
+ Fp->read(dicm, (size_t)4);
+ if ( Fp->eof() )
+ {
+ CloseFile();
+ return 0;
+ }
+
+ if ( memcmp(dicm, "DICM", 4) == 0 )
+ {
+ HasDCMPreamble = true;
+ return Fp;
+ }
+
+ //-- Broken ACR or DICOM (?) with no Preamble; may start with a Shadow Group --
+ // FIXME : We cannot be sure the preable is only zeroes..
+ // (see ACUSON-24-YBR_FULL-RLE.dcm )
+ if (
+ zero == 0x0001 || zero == 0x0100 || zero == 0x0002 || zero == 0x0200 ||
+ zero == 0x0003 || zero == 0x0300 || zero == 0x0004 || zero == 0x0400 ||
+ zero == 0x0005 || zero == 0x0500 || zero == 0x0006 || zero == 0x0600 ||
+ zero == 0x0007 || zero == 0x0700 || zero == 0x0008 || zero == 0x0800 ||
+ zero == 0x0028 || 0x2800 // worse : some ACR-NEMA like files
+ // start 00028 group ?!?
+ )
+ {
+ std::string msg = Util::Format(
+ "ACR/DICOM starting by 0x(%04x) at the beginning of the file\n", zero);
+ // FIXME : is it a Warning message, or a Debug message?
+ gdcmWarningMacro( msg.c_str() );
+ return Fp;
+ }
+
+ // -- Neither ACR/No Preamble Dicom nor DICOMV3 file
+ CloseFile();
+ // Don't user Warning nor Error, not to pollute the output
+ // while directory recursive parsing ...
+ gdcmDebugMacro( "Neither ACR/No Preamble Dicom nor DICOMV3 file: "
+ << Filename.c_str());
+ return 0;
+}
+
+/**
+ * \brief closes the file
+ * @return TRUE if the close was successfull
+ */
+bool Document::CloseFile()
+{
+ if ( Fp )
+ {
+ Fp->close();
+ delete Fp;
+ Fp = 0;
+ }
+ return true;
+}
+
+/**
+ * \brief Writes in a file all the Entries (Dicom Elements)
+ * @param fp file pointer on an already open file (actually: Output File Stream)
+ * @param filetype Type of the File to be written
+ * (ACR-NEMA, ExplicitVR, ImplicitVR)
+ */
+void Document::WriteContent(std::ofstream *fp, FileType filetype)
+{
+ // Skip if user wants to write an ACR-NEMA file
+
+ if ( filetype == ImplicitVR || filetype == ExplicitVR ||
+ filetype == JPEG || filetype == JPEG2000 )
+ {
+ // writing Dicom File Preamble
+ char filePreamble[128];
+ memset(filePreamble, 0, 128);
+ fp->write(filePreamble, 128);
+ fp->write("DICM", 4);
+ }
+ /*
+ * \todo rewrite later, if really usefull
+ * - 'Group Length' element is optional in DICOM
+ * - but un-updated odd groups lengthes can causes pb
+ * (xmedcon breaker)
+ *
+ * if ( (filetype == ImplicitVR) || (filetype == ExplicitVR) )
+ * UpdateGroupLength(false,filetype);
+ * if ( filetype == ACR)
+ * UpdateGroupLength(true,ACR);
+ *
+ * --> Computing group length for groups with embeded Sequences
+ * --> was too much tricky / we were [in a hurry / too lazy]
+ * --> We don't write the element 0x0000 (group length)
+ */
+
+ ElementSet::WriteContent(fp, filetype); // This one is recursive
+}
+
+// -----------------------------------------
+// Content entries
+/**
+ * \brief Loads (from disk) the element content