int ReadRST::DoubleRecord(double *buf, int len) { int ret = len; if (mmap_flag_) { memcpy(buf, (char *)mmap_ini_ + actual_off_, len * sizeof(double)); } else { ret = fread(buf, sizeof(double), len, rfp_); if (ret != len) return ret; } int item; for (item = 0; item < len; ++item) { buf[item] = SwitchEndian(buf[item]); } return ret; }
// ----------------------------------------------- // OpenFile // ----------------------------------------------- // Oeffnet den Ergebnisfile, liest den header und setzt // den Read-File-Pointer rfp; // Rueckgabe: // 0 : alles OK // 1 : File not found // 2 : could not read header // 3 : Read Error Nodal equivalence // 4 : Read Error Element equivalence // 5 : Read Error Time table int ReadRST::OpenFile(const std::string &filename) { if (rfp_ && nodeindex_ && rstheader_.numsets_ != 0) return 0; if ((rfp_ = fopen(filename.c_str(), "rb")) == NULL) { return (1); } file_des_ = fileno(rfp_); if (get_file_size() != 0) { Covise::sendError("Could not get file size"); return (1); } // File offen und OK // erst mal zwei INTs lesen (lead-in): // int 1 ergibt die Laenge des folgenden Records in bytes // int 2 ergibt den Typ des Records (z.B. 0x64==Integer) /****************************************************************************/ /* Notes: */ /* */ /* ANSYS binary files are written in Fortran which means that data is written */ /* blockwise. Each block or record is delimited by markers, namely a header */ /* and trailer, both of them being identical and usually 4 bytes long. These */ /* markers indicate the size of the record. ANSYS uses particularly variable- */ /* length records, however it has been observed that the format of the */ /* binary files varies depending on the ANSYS version. */ /* */ /* In older versions of ANSYS (i.e. V5.6) the size of the records is denoted */ /* in BYTES while the second integer after the record header corresponds to */ /* the size of the Standard ANSYS File Header which is 100 or 0x64 integers */ /* long. This value is followed by the actual 100 values (integers) or items */ /* contained in the ANSYS File Header. */ /* */ /* In newer versions (i.e. V11.0) it has been observed that the size of the */ /* records is expressed in INTs, that is 0x64 items. The second integer has */ /* the value 2147483648 or 0x80000000 which may be a reference to the */ /* data type of the elements contained in the ANSYS File Header, namely */ /* integers (signed int ?). Nevertheless it seems this integer is not counted */ /* in the record size. For more information refer to "Programmer's */ /* Manual for Mechanical APDL" (ANSYS Release 12.1) */ /***************************************************************************/ int *buf = new int[1024]; char version[150]; // Reading the first 4 bytes of the binary file size_t iret = fread(buf, sizeof(int), 1, rfp_); if (iret != 1) { Covise::sendInfo("Error reading rtp_"); } int header_offset = 0; if (buf[0] == 100 || buf[0] == 1677721600) // 100 and 1677721600 to recognize offset in little endian and big endian { header_offset = 1; } // Reading the header if (fread(buf + 1 + header_offset, sizeof(int), 102, rfp_) != 102) { return (2); } int subversion; version[4] = 0; memcpy(version, &buf[11 + header_offset], 4); SwitchEndian(version, 4); int ret = sscanf(version, "%d.%d", &header_.version_, &subversion); if (ret != 2) { header_.version_ = 9; } Covise::sendInfo("File generated by ANSYS V%d.%d", header_.version_, subversion); // alle INT-Elemente umdrehen header_.filenum_ = SwitchEndian(buf[2]); header_.format_ = SwitchEndian(buf[3]); header_.time_ = SwitchEndian(buf[4]); header_.date_ = SwitchEndian(buf[5]); header_.unit_ = SwitchEndian(buf[10]); header_.ansysdate_ = SwitchEndian(buf[12]); memcpy(header_.machine_, &buf[13], 3 * sizeof(int)); header_.machine_[12] = '\0'; SwitchEndian(header_.machine_, 12); memcpy(header_.jobname_, &buf[16], 2 * sizeof(int)); header_.jobname_[8] = '\0'; SwitchEndian(header_.jobname_, 8); memcpy(header_.product_, &buf[18], 2 * sizeof(int)); header_.product_[8] = '\0'; SwitchEndian(header_.product_, 8); memcpy(header_.label_, &buf[20], 1 * sizeof(int)); header_.label_[4] = '\0'; SwitchEndian(header_.label_, 4); memcpy(header_.user_, &buf[21], 3 * sizeof(int)); header_.user_[12] = '\0'; SwitchEndian(header_.user_, 12); memcpy(header_.machine2_, &buf[24], 3 * sizeof(int)); header_.machine2_[12] = '\0'; SwitchEndian(header_.machine2_, 12); header_.recordsize_ = SwitchEndian(buf[27]); header_.maxfilelen_ = SwitchEndian(buf[28]); header_.maxrecnum_ = SwitchEndian(buf[29]); header_.cpus_ = SwitchEndian(buf[30]); memcpy(header_.title_, &buf[42], 20 * sizeof(int)); header_.title_[80] = '\0'; SwitchEndian(header_.title_, 80); memcpy(header_.subtitle_, &buf[62], 20 * sizeof(int)); header_.subtitle_[80] = '\0'; SwitchEndian(header_.subtitle_, 80); // File Pointer steht jetzt auf Position (100+3)*4=412 Bytes Covise::sendInfo("Machine: %s Jobname: %s", header_.machine_, header_.jobname_); Covise::sendInfo("Product: %s Label: %s", header_.product_, header_.label_); Covise::sendInfo("Title: %s Subtitle: %s", header_.title_, header_.subtitle_); // jetzt den RST-File Header reinbasteln if (fread(buf, sizeof(int), 43, rfp_) != 43) { return (2); } if (SwitchEndian(buf[2]) != 12) { ChangeSwitch(); if (SwitchEndian(buf[2]) == 12) { // file can be read using byteswap, prepare to try again delete[] buf; fclose(rfp_); // try again Covise::sendInfo("File is byteswapped, trying again ..."); return OpenFile(filename); } else { // file cannot be read at all Covise::sendError("Cannot correctly read file header length"); return 2; } } // Werte zuweisen rstheader_.fun12_ = SwitchEndian(buf[2]); rstheader_.maxnodes_ = SwitchEndian(buf[3]); rstheader_.usednodes_ = SwitchEndian(buf[4]); rstheader_.maxres_ = SwitchEndian(buf[5]); rstheader_.numdofs_ = SwitchEndian(buf[6]); rstheader_.maxelement_ = SwitchEndian(buf[7]); rstheader_.numelement_ = SwitchEndian(buf[8]); rstheader_.analysis_ = SwitchEndian(buf[9]); rstheader_.numsets_ = SwitchEndian(buf[10]); rstheader_.ptr_eof_ = SwitchEndian(buf[11]); rstheader_.ptr_dsi_ = SwitchEndian(buf[12]); rstheader_.ptr_time_ = SwitchEndian(buf[13]); rstheader_.ptr_load_ = SwitchEndian(buf[14]); rstheader_.ptr_elm_ = SwitchEndian(buf[15]); rstheader_.ptr_node_ = SwitchEndian(buf[16]); rstheader_.ptr_geo_ = SwitchEndian(buf[17]); rstheader_.units_ = SwitchEndian(buf[21]); rstheader_.numsectors_ = SwitchEndian(buf[22]); rstheader_.ptr_end_ = 0; if (SwitchEndian_ == DO_NOT_SWITCH) { rstheader_.ptr_end_ = (long long)(buf[23]) << 32 | buf[24]; } else { rstheader_.ptr_end_ = (long long)(SwitchEndian(buf[24])) << 32 | SwitchEndian(buf[23]); } delete[] buf; // Header fertig gelesen // Jetzt noch die Indextabellen laden int true_used_nodes; if (header_.version_ < 10) { int offset = rstheader_.ptr_node_ * sizeof(int); int buf[2]; fseek(rfp_, offset, SEEK_SET); IntRecord(buf, 2); true_used_nodes = buf[1]; if (true_used_nodes > rstheader_.usednodes_) { true_used_nodes = rstheader_.usednodes_; } } else { true_used_nodes = rstheader_.usednodes_; } int offset = (rstheader_.ptr_node_ + 2) * sizeof(int); fseek(rfp_, offset, SEEK_SET); nodeindex_ = new int[true_used_nodes /* rstheader_.usednodes_ */]; // NEW // if(IntRecord(nodeindex_,rstheader_.usednodes_) != rstheader_.usednodes_){ if (IntRecord(nodeindex_, true_used_nodes) != true_used_nodes) { return (3); } // das selbe für die Elemente offset = (rstheader_.ptr_elm_ + 2) * sizeof(int); fseek(rfp_, offset, SEEK_SET); elemindex_ = new int[rstheader_.numelement_]; if (IntRecord(elemindex_, rstheader_.numelement_) != rstheader_.numelement_) { return (3); } // Timetable lesen timetable_ = new double[rstheader_.maxres_]; offset = (rstheader_.ptr_time_ + 2) * sizeof(int); fseek(rfp_, offset, SEEK_SET); if (DoubleRecord(timetable_, rstheader_.maxres_) != rstheader_.maxres_) { return (6); } // That's all folks return (0); }
static BOOL OrgLoadImplicitLittleEndian(DICOMDataObject* pDDO, FILE* fp, unsigned int iVrSizeLimit) { DICOMDataObject* pNewDDO; VR* pVR; char Buf[2 + 2 + 4]; while (fread(Buf, 1, sizeof(Buf), fp) == sizeof(Buf)) { /* Group, Element and Size could be read */ pVR = new VR; if (!pVR) return FALSE; #if NATIVE_ENDIAN == LITTLE_ENDIAN //Little Endian pVR->Group = *((unsigned short*) Buf); pVR->Element = *((unsigned short*)(Buf + 2)); pVR->Length = *((unsigned int*) (Buf + 2 + 2)); #else //Big Endian like Apple power pc pVR->Group = SwitchEndian( *((UINT16*) Buf)); pVR->Element = SwitchEndian( *((UINT16*)(Buf + 2))); pVR->Length = SwitchEndian( *((UINT32*) (Buf + 2 + 2))); #endif //Big Endian if (pVR->Group == 0xfffe) { /* A deliminator */ if ((pVR->Element == 0xe0dd) || (pVR->Element == 0xe00d)) { delete pVR; return TRUE; } if (pVR->Length == 0xffffffff) { /* Implicit length... Go until deliminator */ pVR->Length = 0; delete pVR; pNewDDO = new DICOMDataObject; if (OrgLoadImplicitLittleEndian(pNewDDO, fp, iVrSizeLimit)) { pDDO->Push(pNewDDO); continue; } else { delete pNewDDO; return FALSE; } } if (pVR->Element == 0xe000) { /* Sequence begin ? */ pVR->Length = 0; delete pVR; pNewDDO = new DICOMDataObject; if (OrgLoadImplicitLittleEndian(pNewDDO, fp, iVrSizeLimit)) { pDDO->Push(pNewDDO); continue; } else { delete pNewDDO; return FALSE; } } } if (pVR->Length == 0xffffffff) { pVR->Length = 0; pDDO->Push(pVR); if (!OrgLoadImplicitLittleEndian(pDDO, fp, iVrSizeLimit)) return FALSE; continue; } /* Check whether the current VR has to be read. NKI DicomNodes can restrict what has to be read Following code assumes that reading is finished when pixeldata are encountered. (Maybe a problem here!!!) */ if (pVR->Length > iVrSizeLimit) { if (((pVR->Group == 0x7fdf) || (pVR->Group == 0x7fe0)) && (pVR->Element == 0x0010)) { /* Ready !? */ pVR->Length = 0; delete pVR; return TRUE; } else { /* Read it, throw it away and continue */ // pVR->Data = new char [pVR->Length]; pVR->ReAlloc(pVR->Length); if (!pVR->Data) return FALSE; fread(pVR->Data, 1, pVR->Length, fp); delete pVR; continue; } } if (pVR->Length) { // pVR->Data = new char [pVR->Length]; pVR->ReAlloc(pVR->Length); if (!pVR->Data) return FALSE; fread(pVR->Data, 1, pVR->Length, fp); /* if ((pVR->Group == 0x7fdf) && (pVR->Element == 0x0010)) { VR* v; signed char *CompressedData = ((signed char *)(pVR->Data)); int UncompressedLength = get_nki_private_decompressed_length(CompressedData); v = new VR(0x7fe0, 0x0010, UncompressedLength, TRUE); nki_private_decompress((short *)(v->Data), CompressedData); delete pVR; pVR = v; } */ } else pVR->Data = NULL; pDDO->Push(pVR); } return TRUE; }
static BOOL LoadImplicitLittleEndian(DICOMDataObject* pDDO, CBufferedIO* pBufferedIO, int handle, unsigned int iVrSizeLimit) { DICOMDataObject* pNewDDO; VR* pVR; char Buf[2 + 2 + 4]; while (pBufferedIO->read(handle, Buf, sizeof(Buf)) == sizeof(Buf)) { /* Group, Element and Size could be read */ pVR = new VR; if (!pVR) return FALSE; #if NATIVE_ENDIAN == LITTLE_ENDIAN //Little Endian pVR->Group = *((unsigned short*) Buf); pVR->Element = *((unsigned short*)(Buf + 2)); pVR->Length = *((unsigned int*) (Buf + 2 + 2)); #else //Big Endian like Apple power pc pVR->Group = SwitchEndian( *((UINT16*) Buf)); pVR->Element = SwitchEndian( *((UINT16*)(Buf + 2))); pVR->Length = SwitchEndian( *((UINT32*) (Buf + 2 + 2))); #endif //Big Endian if (pVR->Group == 0xfffe) { /* A deliminator */ if ((pVR->Element == 0xe0dd) || (pVR->Element == 0xe00d)) { delete pVR; return TRUE; } if (pVR->Length == 0xffffffff) { /* Implicit length... Go until deliminator */ pVR->Length = 0; delete pVR; pNewDDO = new DICOMDataObject; if (LoadImplicitLittleEndian(pNewDDO, pBufferedIO, handle, iVrSizeLimit)) { pDDO->Push(pNewDDO); continue; } else { delete pNewDDO; return FALSE; } } if (pVR->Element == 0xe000) { /* Sequence begin ? */ pVR->Length = 0; delete pVR; pNewDDO = new DICOMDataObject; if (LoadImplicitLittleEndian(pNewDDO, pBufferedIO, handle, iVrSizeLimit)) { pDDO->Push(pNewDDO); continue; } else { delete pNewDDO; return FALSE; } } } if (pVR->Length == 0xffffffff) { pVR->Length = 0; pDDO->Push(pVR); if (!LoadImplicitLittleEndian(pDDO, pBufferedIO, handle, iVrSizeLimit)) return FALSE; continue; } /* Check whether the current VR has to be read. NKI DicomNodes can restrict what has to be read Following code assumes that reading is finished when pixeldata are encountered. (Maybe a problem here!!!) */ if (pVR->Length > iVrSizeLimit) { if (((pVR->Group == 0x7fdf) || (pVR->Group == 0x7fe0)) && (pVR->Element == 0x0010)) { /* Ready !? */ pVR->Length = 0; delete pVR; return TRUE; } else { /* Read it, throw it away and continue */ // pVR->Data = new char [pVR->Length]; pVR->ReAlloc(pVR->Length); if (!pVR->Data) return FALSE; pBufferedIO->read(handle, pVR->Data, pVR->Length); delete pVR; continue; } } if (pVR->Length) { // pVR->Data = new char [pVR->Length]; pVR->ReAlloc(pVR->Length); if (!pVR->Data) return FALSE; pBufferedIO->read(handle, pVR->Data, pVR->Length); } else pVR->Data = NULL; pDDO->Push(pVR); } return TRUE; }
static BOOL SaveDDO(DICOMDataObject* DDOPtr, FILE* fp, int FileCompressMode) { VR *TempVR; #if NATIVE_ENDIAN == BIG_ENDIAN //Big Endian like Apple power pc UINT16 beGroup, beElement; UINT32 beLength; #endif //Big Endian while(TempVR = DDOPtr->Pop()) { if(TempVR->Group==0x7fe0 && TempVR->Element==0x0010 && FileCompressMode) { int DataLength; short CompressedGroup = 0x7fdf, CompressedElement = 0x0010; signed char *CompressedData; CompressedData = new signed char [(TempVR->Length/2) * 3 + 10]; DataLength = nki_private_compress(CompressedData, (short int *)(TempVR->Data), TempVR->Length/2, FileCompressMode); if (!CompressedData) { OperatorConsole.printf("***Out of memory NKI-compress"); return FALSE; } if (DataLength&1) CompressedData[DataLength++] = 0; #if NATIVE_ENDIAN == LITTLE_ENDIAN //Little Endian fwrite(&CompressedGroup, 1, 2, fp); fwrite(&CompressedElement, 1, 2, fp); fwrite(&DataLength, 1, 4, fp); #else //Big Endian like Apple power pc beGroup = SwitchEndian((UINT16) CompressedGroup); beElement = SwitchEndian((UINT16) CompressedElement); beLength = SwitchEndian((UINT32) DataLength); fwrite(&beGroup, 1, 2, fp); fwrite(&beElement, 1, 2, fp); fwrite(&beLength, 1, 4, fp); #endif //Big Endian if (fwrite(CompressedData, 1, DataLength, fp) != (unsigned int)DataLength) { free(CompressedData); OperatorConsole.printf("***Failed to save compressed pixel data (disk full?)"); return FALSE; } delete [] CompressedData; } else { #if NATIVE_ENDIAN == LITTLE_ENDIAN //Little Endian fwrite(&TempVR->Group, 1, 2, fp); fwrite(&TempVR->Element, 1, 2, fp); fwrite(&TempVR->Length, 1, 4, fp); #else //Big Endian like Apple power pc beGroup = SwitchEndian((UINT16) TempVR->Group); beElement = SwitchEndian((UINT16) TempVR->Element); beLength = SwitchEndian((UINT32) TempVR->Length); fwrite(&beGroup, 1, 2, fp); fwrite(&beElement, 1, 2, fp); fwrite(&beLength, 1, 4, fp); #endif //Big Endian if(TempVR->Length) { if(!TempVR->Data) { OperatorConsole.printf("***Missing data in VR (0x%04x,0x%04x)", TempVR->Group, TempVR->Element); return FALSE; } fwrite(TempVR->Data, 1, TempVR->Length, fp); } } delete TempVR; } return TRUE; }