--- ParaView3.orig/Servers/ServerManager/Resources/readers.xml 2007-10-20 15:05:53.381000000 +0900 +++ ParaView3/Servers/ServerManager/Resources/readers.xml 2007-10-20 13:31:17.732000000 +0900 @@ -3412,63 +3412,122 @@ - - - - - Set the file name for the OpenFOAM reader. - - - - - - - - - - - - - Select which cell-centered arrays to read. - - - - - - - - - - - - - Set the current timestep. - - - - - + + + + + + + + + + Cache the OpenFOAM mesh between GUI selection changes. + + + + + + + Read point/face/cell-Zones? + + + + + + + Accumulate patches into selection list across time-steps even if they stop existing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + --- ParaView3.orig/VTK/IO/vtkOpenFOAMReader.cxx 2007-11-07 21:51:56.000000000 +0100 +++ ParaView3/VTK/IO/vtkOpenFOAMReader.cxx 2007-10-23 12:37:05.000000000 +0200 @@ -16,11 +16,21 @@ // Technology Laboratory who developed this class. // Please address all comments to Terry Jordan (terry.jordan@sa.netl.doe.gov) // +// Token-based FoamFile format lexer/parser, performance enhancements, +// gzipped file and lagrangian field support by Takuya Oshima +// (oshima@eng.niigata-u.ac.jp) +// +// * GUI Based selection of mesh regions and fields available in the case +// * Minor bug fixes / Strict memory allocation checks +// * Minor performance enhancements +// by Philippose Rajan (sarith@rocketmail.com) + #include "vtkOpenFOAMReader.h" +#include #include #include -#include +#include #include "vtkInformation.h" #include "vtkInformationVector.h" @@ -28,10 +38,12 @@ #include "vtkDataArraySelection.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkCellArray.h" +#include "vtkCallbackCommand.h" #include "vtkDataArraySelection.h" #include "vtkIntArray.h" -#include "vtkFloatArray.h" #include "vtkDoubleArray.h" +#include "vtkStringArray.h" +#include "vtkSortDataArray.h" #include "vtkPoints.h" #include "vtkCellData.h" #include "vtkHexahedron.h" @@ -48,43 +60,2104 @@ #include "vtkUnstructuredGridAlgorithm.h" #include "vtkObjectFactory.h" #include "vtkDirectory.h" +#include "vtkPolyData.h" +#include "vtkPointData.h" +#include "vtkPVConfig.h" // for PARAVIEW_VERSION_MAJOR #include #include +#if 0 #ifdef VTK_USE_ANSI_STDLIB #define VTK_IOS_NOCREATE #else #define VTK_IOS_NOCREATE | ios::nocreate #endif +#endif + +// The input buffer size in bytes. The purpose of the buffering is to +// reduce the number of costly gzread() calls so the buffer size +// doesn't have to be large. +#define VTK_FOAMFILE_BUFSIZE (2048) + +// If the macro is set to 1 fast (but inaccurate) string to floating +// point number conversion routine is used instead of the system +// strtod(). This affects about 15% in performance for ascii cases. +#define VTK_FOAMFILE_FAST_STRTOD 1 -vtkCxxRevisionMacro(vtkOpenFOAMReader, "$Revision: 1.10 $"); +vtkCxxRevisionMacro(vtkOpenFOAMReader, "$Revision: 1.7.2.2 $"); vtkStandardNewMacro(vtkOpenFOAMReader); -struct stdString +struct stringVector { - vtkstd::string value; + vtkstd::vector< vtkStdString > value; }; -struct stringVector +struct intVector +{ + vtkstd::vector< int > value; +}; + +struct doubleVector +{ + vtkstd::vector value; +}; + +struct intVectorVector +{ + vtkstd::vector< vtkstd::vector< int > > value; +}; + +struct faceVectorVector +{ + vtkstd::vector< vtkstd::vector< face > > value; +}; + +struct unstructuredGridVector +{ + vtkstd::vector value; +}; + +struct vtkOpenFOAMReader::vtkFoamError +{ +private: + vtkStdString str_; +public: + vtkFoamError(): str_() {} + vtkFoamError(vtkFoamError& e): str_(e.str()) {} + const vtkStdString str() const { return str_; } + // a super-easy way to make use of operator<<()'s defined in + // vtkstd::ostringstream class + template vtkFoamError& operator<<(const T& t) + { vtkstd::ostringstream os; os << t; str_ += os.str(); return *this; } +}; + +// token class +// based on src/OpenFOAM/db/IOstreams/token/{token|tokenI}.H +// a word token is treated as a string token. +struct vtkOpenFOAMReader::vtkFoamToken { - vtkstd::vector< vtkstd::string > value; +public: + enum tokenType { UNDEFINED, PUNCTUATION, STRING, LABEL, SCALAR, ERROR }; +private: + tokenType type_; + + vtkFoamToken(const vtkFoamToken&); + void clear() { if(type_ == STRING) delete stringTokenPtr_; } + +public: + union + { + char punctuationToken_; vtkStdString* stringTokenPtr_; int labelToken_; + double scalarToken_; + }; + + vtkFoamToken(): type_(UNDEFINED) {} + ~vtkFoamToken() { clear(); } + void setBad() { clear(); type_ = ERROR; } + tokenType type() const { return type_; } + bool isNumber() const { return type_ == LABEL || type_ == SCALAR; } + + char punctuationToken() const { return punctuationToken_; } + int labelToken() const { return labelToken_; } + double number() const + { if(type_ == LABEL) return labelToken_; else return scalarToken_; } + const vtkStdString& stringToken() const + { return *stringTokenPtr_; } + + void operator=(const char c) + { clear(); type_ = PUNCTUATION; punctuationToken_ = c; } + void operator=(const char *s) + { clear(); type_ = STRING; stringTokenPtr_ = new vtkStdString(s); } + void operator=(const vtkStdString& s) + { clear(); type_ = STRING; stringTokenPtr_ = new vtkStdString(s); } + void operator=(const int l) + { clear(); type_ = LABEL; labelToken_ = l; } + void operator=(const double d) + { clear(); type_ = SCALAR; scalarToken_ = d; } + bool operator==(const char c) const + { return type_ == PUNCTUATION && punctuationToken_ == c; } + bool operator==(const int i) const + { return type_ == LABEL && labelToken_ == i; } + bool operator==(const vtkStdString& str) const + { return type_ == STRING && *stringTokenPtr_ == str; } + bool operator!=(const vtkStdString& str) const + { return type_ != STRING || *stringTokenPtr_ != str; } + bool operator!=(const char c) const { return !operator==(c); } + + friend vtkstd::ostringstream& operator<<(vtkstd::ostringstream& str, + const vtkFoamToken& t) + { + if(t.type() == PUNCTUATION) + { + str << t.punctuationToken_; + } + else if(t.type() == STRING) + { + str << *t.stringTokenPtr_; + } + else if(t.type() == LABEL) + { + str << t.labelToken_; + } + else if(t.type() == SCALAR) + { + str << t.scalarToken_; + } + else if(t.type() == ERROR) + { + str << "badToken (an unexpected EOF?)"; + } + return str; + } }; -struct intVector +// read and tokenize the input +// line number counting is based on +// src/OpenFOAM/db/IOstreams/Sstreams/ISstreamI.H +struct vtkOpenFOAMReader::vtkFoamFile +{ +private: + gzFile file_; + bool putBack_; + int putBackC_; + int lineNumber_; + + // buffer pointers. using raw pointers for performance reason. + unsigned char *buf_; + unsigned char *bufPtr_; + unsigned char *bufEndPtr_; + + // declare and define as private + void putBack(const int c) + { + if(putBack_) + { + throw vtkFoamError() << "Attempted duplicated putBack()"; + } + else + { + if(c == '\n') + { + lineNumber_--; + } + *--bufPtr_ = c; + putBack_ = true; + } + } + + // get a character + int getc() + { + putBack_ = false; + if(bufPtr_ == bufEndPtr_) + { + bufPtr_ = buf_ + 1; // reserve the first byte for getback char + const int readSize = gzread(file_, bufPtr_, VTK_FOAMFILE_BUFSIZE - 1); + if(readSize <= 0) // 0 byte read or EOF + { + // set the current location to the end of the buffer so that + // getc() returns EOF again when called next time + bufPtr_ = bufEndPtr_; + return EOF; + } + bufEndPtr_ = bufPtr_ + readSize; + } + const int c = *bufPtr_++; + if(c == '\n') + { + lineNumber_++; + } + return c; + } + + // get next semantically valid character + // based on src/OpenFOAM/db/IOstreams/Sstream/ISnextValid.C + int nextValid() + { + int c; + for(;;) + { + if((c = getc()) != EOF && isspace(c)) + { + while((c = getc()) != EOF && isspace(c)); + } + if(c == '/') + { + if((c = getc()) == EOF) + { + return '/'; + } + if(c == '/') // one-line comment + { + while(EOF != (c = getc()) && c != '\n' && c != '\r'); + } + else if(c == '*') // multi-line comment + { + for(;;) + { + if((c = getc()) == '*') + { + if((c = getc()) == '/') + { + break; + } + else if(c == EOF) + { + return EOF; + } + else + { + putBack(c); + } + } + else if(c == EOF) + { + return EOF; + } + } + } + else + { + putBack(c); + return '/'; + } + } + else // a valid character or an EOF + { + return c; + } + } + } + + // valid as a character that constitutes a word or not + // based on src/OpenFOAM/primitives/strings/word/wordI.H + bool valid(const int c) const + { + return (!isspace(c) && c != '"' && c != '/' && c != ';' && c != '{' + && c != '}'); + } + +public: + vtkFoamFile(): file_(NULL), putBack_(false), putBackC_(0), lineNumber_(0), + buf_(NULL) {} + ~vtkFoamFile() { close(); } + + void open(const vtkStdString& path) + { + lineNumber_ = 0; + + buf_ = new unsigned char[VTK_FOAMFILE_BUFSIZE]; + bufPtr_ = buf_; + bufEndPtr_ = buf_; + + if(file_ != NULL) + { + throw vtkFoamError() << "File already opened"; + } + if((file_ = gzopen(path.c_str(), "rb")) == NULL) + { + throw vtkFoamError() << "Can't open"; + } + + lineNumber_ = 1; + } + + void close() + { + if(buf_ != NULL) + { + delete [] buf_; + buf_ = NULL; + } + putBack_ = false; + putBackC_ = 0; + if(file_ != NULL) + { + gzclose(file_); + file_ = NULL; + } + // don't reset the line number so that the last line number is + // retained after close + // lineNumber_ = 0; + } + + int lineNumber() const { return lineNumber_; } + + // gzread with buffering handling + int read(char *buf, const int len) + { + int readlen; + const int buflen = bufEndPtr_ - bufPtr_; + if(len > buflen) + { + memcpy(buf, bufPtr_, buflen); + readlen = gzread(file_, buf + buflen, len - buflen); + if(readlen >= 0) + { + readlen += buflen; + } + else + { + if(buflen == 0) // return EOF + { + readlen = -1; + } + else + { + readlen = buflen; + } + } + bufPtr_ = bufEndPtr_; + } + else + { + memcpy(buf, bufPtr_, len); + bufPtr_ += len; + readlen = len; + } + for(int i = 0; i < readlen; i++) + { + if(buf[i] == '\n') + { + lineNumber_++; + } + } + return readlen; + } + + // the tokenizer + // based on src/OpenFOAM/db/IOstreams/Sstreams/{ISreadToken|ISread}.C + // returns true if success, false if encountered EOF + bool read(vtkFoamToken& token) + { + int c = nextValid(); + if(c == EOF) + { + token.setBad(); + return false; + } + switch(c) + { + case ';': case '(': case ')': case '{': case '}': case '[': case ']': + case ':': case ',': case '=': case '+': case '*': case '/': + // punctuation token + token = (char)c; + return true; + case '-': case '.': case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + // number token + { + const int MAX_NUM = 100; + static char numberBuffer[MAX_NUM]; + bool isScalar = false; + if(c == '.') + { + isScalar = true; + } + int i = 0, isDigit; + numberBuffer[i++] = c; + while(EOF != (c = getc()) && i < MAX_NUM && ((isDigit = isdigit(c)) + || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-')) + { + numberBuffer[i++] = c; + if(!isDigit) + { + isScalar = true; + } + } + if(i == MAX_NUM) + { + if(c != EOF) + { + putBack(c); + } + numberBuffer[MAX_NUM - 1] = '\0'; + token.setBad(); + throw vtkFoamError() << "Reached the maximum allowed number length"; + } + numberBuffer[i] = '\0'; + if(c != EOF) + { + putBack(c); + if(i == 1 && numberBuffer[0] == '-') + { + token = '-'; + } + else if(isScalar) + { + token = strtod(numberBuffer, NULL); + } + else + { + token = static_cast(strtol(numberBuffer, NULL, 10)); + } + return true; + } + else + { + throw vtkFoamError() << "Encountered EOF while tokenizing a number"; + } + } + case '"': + // string token + { + const int MAX_STR = 1024; + static char stringBuffer[MAX_STR]; + int i = 0; + bool escape = false; + while((c = getc()) != EOF) + { + if(c == '"' && !escape) + { + stringBuffer[i] = '\0'; + token = stringBuffer; + return true; + } + if((c == '\n' || c == '\r') && !escape) + { + stringBuffer[i] = '\0'; + token = stringBuffer; + throw vtkFoamError() << "Found a newline while reading string \"" + << stringBuffer << "\""; + } + if(c == '\\') + { + escape = true; + } + else + { + escape = false; + stringBuffer[i] = c; + if(++i == MAX_STR) + { + stringBuffer[MAX_STR - 1] = '\0'; + token = stringBuffer; + throw vtkFoamError() + << "Reached the maximum allowed string length"; + } + } + } + stringBuffer[i] = '\0'; + token = stringBuffer; + throw vtkFoamError() << "Encountered EOF while reading string"; + } + default: + // parses as a word token, but gives the STRING type for simplicity + { + putBack(c); + const int MAX_WORD = 1024; + static char wordBuffer[MAX_WORD]; + int i = 0; + int bc = 0; + while((EOF != (c = getc())) && valid(c)) + { + if(i >= MAX_WORD) + { + wordBuffer[MAX_WORD - 1] = '\0'; + token = wordBuffer; + throw vtkFoamError() << "Reached the maximum allowed word length."; + } + if(c == '(') + { + bc++; + } + else if(c == ')') + { + bc--; + if(bc == -1) + { + break; + } + } + wordBuffer[i++] = c; + } + if(i == 0) + { + token.setBad(); + throw vtkFoamError() << "Invalid first character as a token"; + } + wordBuffer[i] = '\0'; + token = wordBuffer; + if(c != EOF) + { + putBack(c); + } + return true; + } + } + } + + void readExpecting(const char c) + { + vtkFoamToken t; + if(!read(t)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(t != c) + { + throw vtkFoamError() << "Expected punctuation token " << c << ", found " + << t; + } + } + + void readExpecting(const char* str) + { + vtkFoamToken t; + if(!read(t)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(t != str) + { + throw vtkFoamError() << "Expected string \"" << str << "\", found " << t; + } + } + + // specialized for reading an integer value. + // not using the standard strtol() for speed reason. + int readLabel() + { + int c = nextValid(); + + bool negative = false; + if(c == '-') + { + negative = true; + c = getc(); + } + + if(!isdigit(c)) + { + throw vtkFoamError() + << "Expected an integer, found a non-digit character" << (char)c; + } + + int num = c - '0'; + while(EOF != (c = getc()) && isdigit(c)) + { + num = 10 * num + c - '0'; + } + + if(c == EOF) + { + throw vtkFoamError() << "Encountered EOF while reading integer"; + } + putBack(c); + + return negative ? -num : num; + } + +#if VTK_FOAMFILE_FAST_STRTOD + // extreamely simplified high-performing string to floating point + // conversion code based on + // ParaView3/VTK/Utilities/vtksqlite/vtk_sqlite3.c + double readNumber() + { + int c = nextValid(); + + // determine sign + bool negative = false; + if(c == '-') + { + negative = true; + c = getc(); + } + + if(c == EOF || (!isdigit(c) && c != '.' && c != 'e' && c != 'E')) + { + throw vtkFoamError() + << "Expected a number, found a non-digit character" << (char)c; + } + + // read integer part + long double num = 0.0; + while(c != EOF && isdigit(c)) + { + num = num * 10.0 + (c - '0'); + c = getc(); + } + + // read decimal part + if(c == '.') + { + long double divisor = 1.0; + + c = getc(); + while(c != EOF && isdigit(c)) + { + num = num * 10.0 + (c - '0'); + divisor *= 10.0; + c = getc(); + } + num /= divisor; + } + + // read exponent part + if(c == 'e' || c == 'E') + { + int esign = 1; + int eval = 0; + long double scale = 1.0; + + c = getc(); + if(c == '-') + { + esign = -1; + c = getc(); + } + else if(c == '+') + { + c = getc(); + } + + while(c != EOF && isdigit(c)) + { + eval = eval * 10 + c - '0'; + c = getc(); + } + + // fast exponent multiplication! + while(eval >= 64) + { + scale *= 1.0e+64; + eval -= 64; + } + while(eval >= 16) + { + scale *= 1.0e+16; + eval -= 16; + } + while(eval >= 4) + { + scale *= 1.0e+4; + eval -= 4; + } + while(eval >= 1) + { + scale *= 1.0e+1; + eval -= 1; + } + + if(esign < 0) + { + num /= scale; + } + else + { + num *= scale; + } + } + + if(c == EOF) + { + throw vtkFoamError() << "Unexpected EOF"; + } + putBack(c); + + return static_cast(negative ? -num : num); + } +#else + // specialized for reading a scalar value + double readNumber() + { + int c = nextValid(); + if(c == EOF || (!isdigit(c) && c != '-' && c != '.')) + { + if(c == EOF) + { + throw vtkFoamError() << "Unexpected EOF"; + } + else + { + throw vtkFoamError() << "Expected a number, found " << (char)c; + } + } + + const int MAX_NUM = 100; + static char numberBuffer[MAX_NUM]; + int i = 0; + numberBuffer[i++] = c; + if(EOF != (c = getc()) && i < MAX_NUM && (isdigit(c) + || c == '.' || c == 'e' || c == 'E')) // signs do not come as a 2nd char + { + numberBuffer[i++] = c; + while(EOF != (c = getc()) && i < MAX_NUM && (isdigit(c) + || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-')) + { + numberBuffer[i++] = c; + } + } + if(i == MAX_NUM) + { + throw vtkFoamError() << "Reached the maximum allowed number length"; + } + numberBuffer[i] = '\0'; + if(c == EOF) + { + throw vtkFoamError() << "Unexpected EOF"; + } + else + { + putBack(c); + if(i == 1 && numberBuffer[0] == '-') + { + throw vtkFoamError() << "Expected a number, found a minus sign"; + } + } + return strtod(numberBuffer, NULL); + } +#endif +}; + +// IOobject class +// holds file handle, file format, name of the object the file holds and +// type of the object. +struct vtkOpenFOAMReader::vtkFoamIOobject: public vtkFoamFile +{ +public: + enum fileFormat { UNDEFINED, ASCII, BINARY }; + +private: + vtkStdString fileName_; + fileFormat format_; + vtkStdString objectName_; + vtkStdString headerClassName_; + vtkFoamError* e_; + + void readHeader(); // defined later +public: + vtkFoamIOobject(): vtkFoamFile(), format_(UNDEFINED), e_(NULL) {} + ~vtkFoamIOobject() { close(); } + + bool open(const vtkStdString& file) + { + fileName_ = file; + try + { + vtkFoamFile::open(file); + } + catch(vtkFoamError& e) + { + e_ = new vtkFoamError(e); + return false; + } + + try + { + readHeader(); + } + catch(vtkFoamError& e) + { + vtkFoamFile::close(); + e_ = new vtkFoamError(e); + return false; + } + e_ = NULL; + return true; + } + + void close() + { + vtkFoamFile::close(); + format_ = UNDEFINED; + objectName_.erase(); + headerClassName_.erase(); + if(e_ != NULL) + { + delete e_; + } + } + const vtkStdString& fileName() { return fileName_; } + const fileFormat format() const { return format_; } + const vtkStdString& className() const { return headerClassName_; } + const vtkStdString& objectName() const { return objectName_; } + const vtkFoamError& error() const { return *e_; } + void setError(vtkFoamError& e) + { if(e_ != NULL) delete e_; e_ = new vtkFoamError(e); } +}; + +// a class that represents a value of a dictionary entry that corresponds to +// its keyword. note that an entry can have more than one value. +struct vtkOpenFOAMReader::vtkFoamEntryValue +{ +public: + enum entryValueType + { + UNDEFINED, PUNCTUATION, STRING, LABEL, SCALAR, STRINGLIST, LABELLIST, + LABELLISTLIST, SCALARLIST, VECTORLIST, ENTRYVALUELIST, EMPTYLIST, + DICTIONARY, ERROR + }; + +private: + entryValueType type_; + bool isUniform_; + bool managed_; + + // don't pack them into a union + vtkFoamToken t_; + vtkstd::vector entryValuePtrs_; + + union + { + intVector *labelListPtr_; vtkDoubleArray *scalarListPtr_, *vectorListPtr_; + stringVector *stringListPtr_; intVectorVector *labelListListPtr_; + vtkFoamDict *dictPtr_; + }; + + void clear(); + void readList(vtkFoamIOobject& io); + +public: + vtkFoamEntryValue(): type_(UNDEFINED), isUniform_(false), managed_(true), + labelListPtr_(NULL) {} + ~vtkFoamEntryValue() { clear(); } + + entryValueType type() const { return type_; } + void setEmptyList() { clear(); isUniform_ = false; type_ = EMPTYLIST; } + bool isUniform() const { return isUniform_; } + void read(vtkFoamIOobject& io); + void readDictionary(vtkFoamIOobject& io, + const vtkStdString& firstKeyword = ""); + const vtkFoamToken& token() const { return t_; } + vtkFoamToken& token() { return t_; } + const vtkstd::vector& labelList() const + { return labelListPtr_->value; } + const vtkstd::vector >& labelListList() const + { return labelListListPtr_->value; } + vtkDoubleArray& scalarList() + { return *scalarListPtr_; } + vtkDoubleArray& vectorList() + { return *vectorListPtr_; } + vtkFoamDict& dictionary() + { return *dictPtr_; } + bool operator==(const char c) const + { return type_ == PUNCTUATION && t_ == c; } + bool operator!=(const char c) const + { return type_ != PUNCTUATION || t_ != c; } + bool operator==(const int i) const + { return type_ == LABEL && t_ == i; } + + void *ptr() + { + managed_ = false; // the returned pointer will not be deleted by the d'tor + return (void *)labelListPtr_; // all list pointers are in a single union + } + + // the following two are for an exceptional expression of + // `LABEL{LABELorSCALAR}' without type prefix (e. g. `2{-0}' in + // mixedRhoE B.C. in rhopSonicFoam/shockTube) + void makeLabelList(const int labelValue, const int size) + { + labelListPtr_ = new intVector; + type_ = LABELLIST; + vtkstd::vector& ll = labelListPtr_->value; + ll.resize(size); + for(int i = 0; i < size; i++) + { + ll[i] = labelValue; + } + } + void makeScalarList(const double scalarValue, const int size) + { + scalarListPtr_ = vtkDoubleArray::New(); + type_ = SCALARLIST; + vtkDoubleArray& sl = *scalarListPtr_; + sl.SetNumberOfValues(size); + for(vtkIdType i = 0; i < size; i++) + { + sl.SetValue(i, scalarValue); + } + } + + // read a labelList + void readLabelList(vtkFoamIOobject& io) + { + vtkFoamToken currToken; + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + labelListPtr_ = new intVector; + type_ = LABELLIST; + if(currToken.type() == vtkFoamToken::LABEL) + { + const int size = currToken.labelToken(); + labelListPtr_->value.resize(size); + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + vtkstd::vector& ll = labelListPtr_->value; + // some objects have lists with only one element enclosed by {} + // e. g. simpleFoam/pitzDaily3Blocks/constant/polyMesh/faceZones + if(currToken == '{') + { + int labelValue = io.readLabel(); + for(int i = 0; i < size; i++) + { + ll[i] = labelValue; + } + io.readExpecting('}'); + return; + } + if(currToken != '(') + { + throw vtkFoamError() << "Expected (, found " << currToken; + } + if(io.format() == vtkFoamIOobject::ASCII) + { + for(int i = 0; i < size; i++) + { + ll[i] = io.readLabel(); + } + } + else + { + if(size > 0) // avoid invalid access to ll.at(0) + { + io.read(reinterpret_cast(&ll.at(0)), size * sizeof(int)); + } + } + io.readExpecting(')'); + } + else if(currToken == '(') + { + while(io.read(currToken) && currToken != ')') + { + if(currToken.type() != vtkFoamToken::LABEL) + { + throw vtkFoamError() << "Expected an integer or a (, found " + << currToken; + } + labelListPtr_->value.push_back(currToken.labelToken()); + } + } + else + { + throw vtkFoamError() << "Expected integer or (, found " << currToken; + } + } + + // reads a list of labelLists. requires size prefix of the listList + // to be present. size of the list must be present in the stream if + // the format is binary. + void readLabelListList(vtkFoamIOobject& io) + { + vtkFoamToken currToken; + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(currToken.type() == vtkFoamToken::LABEL) + { + labelListListPtr_ = new intVectorVector; + type_ = LABELLISTLIST; + + const int sizeI = currToken.labelToken(); + labelListListPtr_->value.resize(sizeI); + io.readExpecting('('); + for(int i = 0; i < sizeI; i++) + { + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(currToken.type() == vtkFoamToken::LABEL) + { + const int sizeJ = currToken.labelToken(); + labelListListPtr_->value[i].resize(sizeJ); + io.readExpecting('('); + vtkstd::vector& labelListI = labelListListPtr_->value[i]; + if(io.format() == vtkFoamIOobject::ASCII) + { + for(int j = 0; j < sizeJ; j++) + { + labelListI[j] = io.readLabel(); + } + } + else + { + if(sizeJ > 0) // avoid invalid reference to labelListI.at(0) + { + io.read(reinterpret_cast(&labelListI.at(0)), + sizeJ * sizeof(int)); + } + } + io.readExpecting(')'); + } + else if(currToken == '(') + { + while(io.read(currToken) && currToken != ')') + { + if(currToken.type() != vtkFoamToken::LABEL) + { + throw vtkFoamError() << "Expected an integer, found " + << currToken; + } + labelListListPtr_->value[i].push_back(currToken.labelToken()); + } + } + else + { + throw vtkFoamError() << "Expected integer or (, found " << currToken; + } + } + io.readExpecting(')'); + } + else + { + throw vtkFoamError() << "Expected integer, found " << currToken; + } + } + + // reads a scalarList. requires size prefix of the list to be + // present in the stream if the format is binary. + void readScalarList(vtkFoamIOobject& io) + { + vtkFoamToken currToken; + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + scalarListPtr_ = vtkDoubleArray::New(); + type_ = SCALARLIST; + if(currToken.type() == vtkFoamToken::LABEL) + { + const vtkIdType size = currToken.labelToken(); + scalarListPtr_->SetNumberOfValues(size); + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + vtkDoubleArray& sl = *scalarListPtr_; + // some objects have lists with only one element enclosed by {} + // to represent a field with an uniform value + if(currToken == '{') + { + double scalarValue = io.readNumber(); + for(vtkIdType i = 0; i < size; i++) + { + sl.SetValue(i, scalarValue); + } + io.readExpecting('}'); + return; + } + if(currToken != '(') + { + throw vtkFoamError() << "Expected (, found " << currToken; + } + if(io.format() == vtkFoamIOobject::ASCII) + { + for(vtkIdType i = 0; i < size; i++) + { + sl.SetValue(i, io.readNumber()); + } + } + else + { + if(size > 0) // avoid invalid access to GetPointer(0) + { + io.read(reinterpret_cast(sl.GetPointer(0)), + size * sizeof(double)); + } + } + io.readExpecting(')'); + } + else if(currToken == '(') + { + while(io.read(currToken) && currToken != ')') + { + if(!io.read(currToken) || !currToken.isNumber()) + { + throw vtkFoamError() << "Expected an integer or a (, found " + << currToken; + } + scalarListPtr_->InsertNextValue(currToken.number()); + } + scalarListPtr_->Squeeze(); + } + else + { + throw vtkFoamError() << "Expected integer or (, found " << currToken; + } + } + + // reads a vectorList. requires size prefix of the list to be + // present in the stream if the format is binary. + // if isPositions is true read Cloud type of data as particle positions + // based on src/lagrangian/basic/particle/particleIO.C + void readVectorList(vtkFoamIOobject& io, const bool isPositions) + { + vtkFoamToken currToken; + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + vectorListPtr_ = vtkDoubleArray::New(); + vectorListPtr_->SetNumberOfComponents(3); + type_ = VECTORLIST; + if(currToken.type() == vtkFoamToken::LABEL) + { + const int size = currToken.labelToken(); + vectorListPtr_->SetNumberOfTuples(size); + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + // some objects may have a vector list with one element enclosed by {} + if(currToken == '{') + { + io.readExpecting('('); + double vectorValue[3]; + vectorValue[0] = io.readNumber(); + vectorValue[1] = io.readNumber(); + vectorValue[2] = io.readNumber(); + for(int i = 0; i < size; i++) + { + vectorListPtr_->SetTuple(i, vectorValue); + } + io.readExpecting(')'); + if(isPositions) + { + // skip label celli + io.readLabel(); + } + io.readExpecting('}'); + return; + } + + if(currToken != '(') + { + throw vtkFoamError() << "Expected (, found " << currToken; + } + if(io.format() == vtkFoamIOobject::ASCII) + { + if(size > 0) // avoid invalid access to GetPointer(0) + { + double* vectorComponentI = vectorListPtr_->GetPointer(0); + for(int i = 0; i < size; i++) + { + io.readExpecting('('); + *vectorComponentI++ = io.readNumber(); + *vectorComponentI++ = io.readNumber(); + *vectorComponentI++ = io.readNumber(); + io.readExpecting(')'); + if(isPositions) + { + // skip label celli + io.readLabel(); + } + } + } + } + else // binary + { + if(isPositions) // lagrangian/positions (class Cloud) + { + if(size > 0) // avoid invalid access to GetPointer() + { + for(int i = 0, index = 0; i < size; i++, index += 3) + { + io.readExpecting('('); + io.read(reinterpret_cast(vectorListPtr_ + ->GetPointer(index)), sizeof(double) * 3); + + // skip label celli, label facei and scalar stepFraction + const int dummySize = 2 * sizeof(int) + sizeof(double); + char dummyBuf[dummySize]; + io.read(dummyBuf, dummySize); + io.readExpecting(')'); + } + } + } + else // regular vectorField + { + if(size > 0) // avoid invalid access to GetPointer() + { + io.read(reinterpret_cast(vectorListPtr_->GetPointer(0)), + size * sizeof(double) * 3); + } + } + } + io.readExpecting(')'); + } + else if(currToken == '(') + { + while(io.read(currToken) && currToken != ')') + { + if(currToken != '(') + { + throw vtkFoamError() << "Expected (, found " << currToken; + } + double v[3]; + v[0] = io.readNumber(); + v[1] = io.readNumber(); + v[2] = io.readNumber(); + vectorListPtr_->InsertNextTuple(v); + io.readExpecting(')'); + } + vectorListPtr_->Squeeze(); + } + else + { + throw vtkFoamError() << "Expected integer or (, found " << currToken; + } + } + + const vtkFoamEntryValue& operator>>(vtkStdString& str) const + { + if(type_ == STRING) + { + str = vtkStdString(t_.stringToken()); + } + else + { + //vtkErrorMacro("token type does not match"); + str = ""; + } + return *this; + } + + const vtkFoamEntryValue& operator>>(double& d) const + { + if(type_ == SCALAR || type_ == LABEL) + { + d = t_.number(); + } + else + { + //vtkErrorMacro("token type does not match"); + d = 0.0; + } + return *this; + } + + const vtkFoamEntryValue& operator>>(int& i) const + { + if(type_ == LABEL) + { + i = t_.labelToken(); + } + else + { + //vtkErrorMacro("token type does not match"); + i = 0; + } + return *this; + } +}; + +// a class that represents an entry of a dictionary. note that an +// entry can have more than one value. +struct vtkOpenFOAMReader::vtkFoamEntry +{ +private: + vtkStdString keyword_; + vtkstd::vector valuePtrs_; + +public: + vtkFoamEntry() {} + ~vtkFoamEntry() + { + for(size_t i = 0; i < valuePtrs_.size(); i++) + { + delete valuePtrs_[i]; + } + } + + vtkStdString& keyword() { return keyword_; } + size_t size() const { return valuePtrs_.size(); } + // returns false if the number of the values is 0 to simplify things + bool found() const { return valuePtrs_.size() > 0; } + vtkFoamEntryValue& firstValue() const { return *valuePtrs_[0]; } + const vtkstd::vector& labelList() const + { return firstValue().labelList(); } + const vtkstd::vector >& labelListList() const + { return firstValue().labelListList(); } + vtkDoubleArray& scalarList() + { return firstValue().scalarList(); } + vtkDoubleArray& vectorList() + { return firstValue().vectorList(); } + vtkFoamDict& dictionary() // not using firstValue() for breaking constness + { return valuePtrs_[0]->dictionary(); } + void *ptr() { return firstValue().ptr(); } + + void readDictionary(vtkFoamIOobject& io) + { + valuePtrs_.push_back(new vtkFoamEntryValue); + valuePtrs_.back()->readDictionary(io); + } + + // read values of an entry + void read(vtkFoamIOobject& io); + + const vtkFoamEntry& operator>>(vtkStdString& str) const + { + if(!found() || valuePtrs_[0]->type() != vtkFoamEntryValue::STRING) + { + str = ""; + } + else + { + valuePtrs_[0]->operator>>(str); + } + return *this; + } + + const vtkFoamEntry& operator>>(double& d) const + { + if(!found() || (valuePtrs_[0]->type() != vtkFoamEntryValue::SCALAR + && valuePtrs_[0]->type() != vtkFoamEntryValue::LABEL)) + { + d = 0.0; + } + else + { + valuePtrs_[0]->operator>>(d); + } + return *this; + } + + const vtkFoamEntry& operator>>(int& i) const + { + if(!found() || valuePtrs_[0]->type() != vtkFoamEntryValue::LABEL) + { + i = 0; + } + else + { + valuePtrs_[0]->operator>>(i); + } + return *this; + } +}; + +// a class that holds a FoamFile data structure +struct vtkOpenFOAMReader::vtkFoamDict: public vtkFoamEntryValue +{ +public: + enum dictType + { UNDEFINED, DICTIONARY, SCALARLIST, VECTORLIST, LABELLIST, LABELLISTLIST, + UNIFORMLABELLIST, UNIFORMSCALARLIST }; + +private: + dictType type_; + vtkstd::vector entryPtrs_; + vtkFoamEntry* dummyEntryPtr_; + + vtkFoamDict(const vtkFoamDict &); + +public: + vtkFoamDict(): vtkFoamEntryValue(), type_(UNDEFINED), dummyEntryPtr_(NULL) {} + ~vtkFoamDict() + { + if(type_ == DICTIONARY) + { + for(size_t i = 0; i < entryPtrs_.size(); i++) + { + delete entryPtrs_[i]; + } + } + if(dummyEntryPtr_ != NULL) + { + delete dummyEntryPtr_; + } + } + + dictType type() const { return type_; } + size_t size() const { return entryPtrs_.size(); } + vtkFoamEntry& entry(const int i) { return *entryPtrs_[i]; } + vtkFoamEntry& lookup(const vtkStdString& keyword) + { + if(type_ == DICTIONARY) + { + for(size_t i = 0; i < entryPtrs_.size(); i++) + { + if(entryPtrs_[i]->keyword() == keyword) // found + { + return *entryPtrs_[i]; + } + } + } + + // not found + if(dummyEntryPtr_ == NULL) + { + dummyEntryPtr_ = new vtkFoamEntry; + } + return *dummyEntryPtr_; + } + + // reads a FoamFile or a subdictionary. if the stream to be read is + // a subdictionary the preceding '{' is assumed to have already been + // thrown away. + bool read(vtkFoamIOobject& io, const bool isSubDictionary = false, + const vtkStdString& firstKeyword = "") + { + try + { + vtkFoamToken currToken; + if(firstKeyword == "") + { + if(!isSubDictionary) + { + // polyMesh/points, lagrangian vectors + if(io.className() == "vectorField") + { + readVectorList(io, false); + type_ = VECTORLIST; + return true; + } + else if(io.className() == "scalarField") // lagrangian scalars + { + readScalarList(io); + type_ = SCALARLIST; + return true; + } + else if(io.className() == "Cloud") // lagrangian/positions + { + readVectorList(io, true); + type_ = VECTORLIST; + return true; + } + else if(io.className() == "faceList") // polyMesh/faces + { + readLabelListList(io); + type_ = LABELLISTLIST; + return true; + } + else if(io.className() == "labelList") // polyMesh/{owner|neighbour} + { + readLabelList(io); + type_ = LABELLIST; + return true; + } + } + + // read the first token + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + + // list of dictionaries is read as a usual dictionary + // polyMesh/boundary, point/face/cell-Zones + if(!isSubDictionary && currToken.type() == vtkFoamToken::LABEL) + { + io.readExpecting('('); + if(currToken.labelToken() > 0) + { + if(!io.read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + // continue to read as a usual dictionary + } + else // return as empty dictionary + { + io.readExpecting(')'); + type_ = DICTIONARY; + return true; + } + } + // some boundary files does not have the number of boundary + // patches (e.g. settlingFoam/tank3D). in this case we need to + // explicitly read the file as a dictionary. + else if(!isSubDictionary && currToken == '(' + && io.className() == "polyBoundaryMesh") // polyMesh/boundary + { + if(!io.read(currToken)) // read the first keyword + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(currToken == ')') // return as empty dictionary + { + type_ = DICTIONARY; + return true; + } + } + // the following two else-if clauses are for an exceptional + // expression of `LABEL{LABELorSCALAR}' without type prefix + // (e. g. `2{-0}' in mixedRhoE B.C. in + // rhopSonicFoam/shockTube) + else if(isSubDictionary && currToken.type() == vtkFoamToken::LABEL) + { + token() = currToken.labelToken(); + type_ = UNIFORMLABELLIST; + io.readExpecting('}'); + return true; + } + else if(isSubDictionary && currToken.type() == vtkFoamToken::SCALAR) + { + token() = currToken.number(); + type_ = UNIFORMSCALARLIST; + io.readExpecting('}'); + return true; + } + // return as empty dictionary + else if(isSubDictionary && currToken == '}') + { + type_ = DICTIONARY; + return true; + } + } + // if firstKeyword is set read the following stream as subdictionary + else + { + entryPtrs_.push_back(new vtkFoamEntry); + entryPtrs_.back()->keyword() = firstKeyword; + entryPtrs_.back()->readDictionary(io); + if(!io.read(currToken) || currToken == '}' || currToken == ')') + { + type_ = DICTIONARY; + return true; + } + } + + if(currToken.type() == vtkFoamToken::STRING) // general dictionary + { + // based on src/OpenFOAM/db/dictionary/dictionaryIO.C + do + { + if(currToken != ';') // ignore empty entry + { + entryPtrs_.push_back(new vtkFoamEntry); + entryPtrs_.back()->keyword() = currToken.stringToken(); + entryPtrs_.back()->read(io); + if(currToken == "FoamFile") + { + // delete the FoamFile header subdictionary entry + delete entryPtrs_.back(); + entryPtrs_.pop_back(); + } + } + } while(io.read(currToken) + && (currToken.type() == vtkFoamToken::STRING || currToken == ';')); + + if(currToken.type() == vtkFoamToken::ERROR || currToken == '}' + || currToken == ')') + { + type_ = DICTIONARY; + return true; + } + throw vtkFoamError() + << "Expected keyword, closing brace, ; or EOF, found " << currToken; + } + throw vtkFoamError() << "Bad first keyword for dictionary " << currToken; + } + catch(vtkFoamError& e) + { + if(isSubDictionary) + { + throw; + } + else + { + io.setError(e); + return false; + } + } + } +}; + +void vtkOpenFOAMReader::vtkFoamIOobject::readHeader() +{ + vtkFoamToken firstToken; + + readExpecting("FoamFile"); + readExpecting('{'); + + vtkFoamDict headerDict; + headerDict.read(*this, true); // throw exception in case of error + + vtkFoamEntry& formatEntry = headerDict.lookup("format"); + if(!formatEntry.found()) + { + throw vtkFoamError() + << "the format entry (binary/ascii) not found in FoamFile header"; + } + vtkStdString format; + formatEntry >> format; + // case does matter (e. g. "BINARY" is treated as ascii) + // see src/OpenFOAM/db/IOstreams/IOstreams/IOstream.C + if(format == "binary") + { + format_ = BINARY; + } + else + { + format_ = ASCII; + } + + vtkFoamEntry& classEntry = headerDict.lookup("class"); + if(!classEntry.found()) + { + throw vtkFoamError() << "class name not found in FoamFile header"; + } + classEntry >> headerClassName_; + + vtkFoamEntry& objectEntry = headerDict.lookup("object"); + if(!objectEntry.found()) + { + throw vtkFoamError() << "object name not found in FoamFile header"; + } + objectEntry >> objectName_; +} + +void vtkOpenFOAMReader::vtkFoamEntryValue::clear() +{ + if(managed_) + { + if(type_ == LABELLIST) + { + delete labelListPtr_; + } + else if(type_ == LABELLISTLIST) + { + delete labelListListPtr_; + } + else if(type_ == SCALARLIST) + { + scalarListPtr_->Delete(); + } + else if(type_ == VECTORLIST) + { + vectorListPtr_->Delete(); + } + else if(type_ == STRINGLIST) + { + delete stringListPtr_; + } + else if(type_ == ENTRYVALUELIST) + { + for(size_t i = 0; i < entryValuePtrs_.size() ; i++) + { + delete entryValuePtrs_[i]; + } + } + else if(type_ == DICTIONARY) + { + delete dictPtr_; + } + } +} + +// general-purpose list reader - guess the type of the list and read +// it. only supports ascii format and assumes the preceding '(' has +// already been thrown away. the reader supports nested list with +// variable lengths (e. g. `((token token) (token token token)).' +// also supports compound of tokens and lists (e. g. `((token token) +// token)') only if a list comes as the first value. +void vtkOpenFOAMReader::vtkFoamEntryValue::readList(vtkFoamIOobject& io) +{ + io.read(t_); + + // initial guess of the list type + if(t_.type() == vtkFoamToken::LABEL) + { + // if the first token is of type LABEL it might be either an element of + // a labelList or the size of a sublist so proceed to the next token + vtkFoamToken nextToken; + if(!io.read(nextToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(nextToken.type() == vtkFoamToken::LABEL) + { + labelListPtr_ = new intVector; + labelListPtr_->value.push_back(t_.labelToken()); + labelListPtr_->value.push_back(nextToken.labelToken()); + type_ = LABELLIST; + } + else if(nextToken.type() == vtkFoamToken::SCALAR) + { + scalarListPtr_ = vtkDoubleArray::New(); + scalarListPtr_->InsertNextValue(t_.number()); + scalarListPtr_->InsertNextValue(nextToken.number()); + type_ = SCALARLIST; + } + else if(nextToken == '(') // list of list: read recursively + { + entryValuePtrs_.push_back(new vtkFoamEntryValue); + entryValuePtrs_.back()->readList(io); + type_ = ENTRYVALUELIST; + } + else if(nextToken == ')') // list with only one label element + { + labelListPtr_ = new intVector; + labelListPtr_->value.push_back(t_.labelToken()); + type_ = LABELLIST; + return; + } + else + { + throw vtkFoamError() << "Expected number, ( or ), found " << nextToken; + } + } + else if(t_.type() == vtkFoamToken::SCALAR) + { + scalarListPtr_ = vtkDoubleArray::New(); + scalarListPtr_->InsertNextValue(t_.number()); + type_ = SCALARLIST; + } + // if the first word is a string we have to read another token to determine + // if the first word is a keyword for the following dictionary + else if(t_.type() == vtkFoamToken::STRING) + { + vtkFoamToken nextToken; + if(!io.read(nextToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if(nextToken.type() == vtkFoamToken::STRING) // list of strings + { + stringListPtr_ = new stringVector; + stringListPtr_->value.push_back(t_.stringToken()); + stringListPtr_->value.push_back(nextToken.stringToken()); + type_ = STRINGLIST; + } + // dictionary with the already read stringToken as the first keyword + else if(nextToken == '{') + { + if(t_.stringToken() == "") + { + throw "Empty string is invalid as a keyword for dictionary entry"; + } + readDictionary(io, t_.stringToken()); + // the dictionary read as list has the entry terminator ';' so + // we have to skip it + return; + } + else if(nextToken == ')') // list with only one string element + { + stringListPtr_ = new stringVector; + stringListPtr_->value.push_back(t_.stringToken()); + type_ = STRINGLIST; + return; + } + else + { + throw vtkFoamError() << "Expected string, { or ), found " << nextToken; + } + } + else if(t_ == '(') // list of lists: read recursively + { + entryValuePtrs_.push_back(new vtkFoamEntryValue); + entryValuePtrs_.back()->readList(io); + // read all the following values as arbitrary entryValues + // the alphaContactAngle b.c. in multiphaseInterFoam/damBreak4phase + // reaquires this treatment (reading by readList() is not enough) + do + { + entryValuePtrs_.push_back(new vtkFoamEntryValue); + entryValuePtrs_.back()->read(io); + } + while(*entryValuePtrs_.back() != ')' && *entryValuePtrs_.back() != '}' + && *entryValuePtrs_.back() != ';'); + + if(*entryValuePtrs_.back() != ')') + { + throw vtkFoamError() << "Expected ) before " + << entryValuePtrs_.back()->token(); + } + + // delete ')' + delete entryValuePtrs_.back(); + entryValuePtrs_.pop_back(); + type_ = ENTRYVALUELIST; + return; + } + else if(t_ == ')') // empty list + { + type_ = EMPTYLIST; + return; + } + + while(io.read(t_) && t_ != ')') + { + if(type_ == LABELLIST) + { + if(t_.type() == vtkFoamToken::SCALAR) // switch to scalarList + { + // labelListPtr_ and scalarListPtr_ are packed into a single union so + // we need a temprary pointer + vtkDoubleArray* slPtr = vtkDoubleArray::New(); + const vtkIdType size = labelListPtr_->value.size(); + slPtr->SetNumberOfValues(size); + for(vtkIdType i = 0; i < size; i++) + { + slPtr->SetValue(i, double(labelListPtr_->value[i])); + } + delete labelListPtr_; + slPtr->InsertNextValue(t_.number()); + scalarListPtr_ = slPtr; // copy after labelListPtr_ is deleted + type_ = SCALARLIST; + } + else if(t_.type() == vtkFoamToken::LABEL) + { + labelListPtr_->value.push_back(t_.labelToken()); + } + else + { + throw vtkFoamError() << "Expected a number, found " << t_; + } + } + else if(type_ == SCALARLIST) + { + if(t_.isNumber()) + { + scalarListPtr_->InsertNextValue(t_.number()); + } + else + { + throw vtkFoamError() << "Expected a number, found " << t_; + } + } + else if(type_ == STRINGLIST) + { + if(t_.type() == vtkFoamToken::STRING) + { + stringListPtr_->value.push_back(t_.stringToken()); + } + else + { + throw vtkFoamError() << "Expected a string, found " << t_; + } + } + else if(type_ == ENTRYVALUELIST) + { + if(t_.type() == vtkFoamToken::LABEL) + { + // skip the number of elements to make things simple + if(!io.read(t_)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + } + if(t_ != '(') + { + throw vtkFoamError() << "Expected (, found " << t_; + } + entryValuePtrs_.push_back(new vtkFoamEntryValue); + entryValuePtrs_.back()->readList(io); + } + else + { + throw vtkFoamError() << "Unexpected token " << t_; + } + } + + if(type_ == SCALARLIST) + { + scalarListPtr_->Squeeze(); + } +} + +// a list of dictionaries is actually read as a dictionary +void vtkOpenFOAMReader::vtkFoamEntryValue::readDictionary(vtkFoamIOobject& io, + const vtkStdString& firstKeyword) +{ + dictPtr_ = new vtkFoamDict; + type_ = DICTIONARY; + dictPtr_->read(io, true, firstKeyword); +} + +// guess the type of the given entry value and read it +void vtkOpenFOAMReader::vtkFoamEntryValue::read(vtkFoamIOobject& io) +{ + if(!io.read(t_)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + + if(t_ == '{') + { + readDictionary(io); + return; + } + // for reading sublist from vtkFoamEntryValue::readList() or there + // are cases where lists without the (non)uniform keyword appear + // (e. g. coodles/pitsDaily/0/U, Hrv's uniformFixedValue b.c.) + else if(t_ == '(') + { + readList(io); + return; + } + else if(t_ == "uniform") + { + if(!io.read(t_)) + { + throw vtkFoamError() + << "Expected a uniform value or a list, found unexpected EOF"; + } + if(t_ == '(') + { + readList(io); + } + else if(t_.type() == vtkFoamToken::LABEL) + { + type_ = LABEL; + } + else if(t_.type() == vtkFoamToken::SCALAR) + { + type_ = SCALAR; + } + else if(t_.type() == vtkFoamToken::STRING) + { + type_ = STRING; + } + else // unexpected punctuation token + { + throw vtkFoamError() << "Expected number, string or (, found " << t_; + } + isUniform_ = true; + } + else if(t_ == "nonuniform") + { + if(!io.read(t_)) + { + throw vtkFoamError() << "Expected list type specifier, found EOF"; + } + if(t_ == "List") + { + isUniform_ = false; + readVectorList(io, false); + } + else if(t_ == "List") + { + isUniform_ = false; + readScalarList(io); + } + // List is read as List