From 017f7c128e977bc60c54558d01d3ce1382a729fb Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Fri, 19 Mar 2021 18:12:08 +0100 Subject: [PATCH] openfoam: restructure read-helpers - move heavier parts from vtkFoamEntryValue into vtkFoamRead struct. Move list readers out of line for easier maintenance. - Ensure old (extra data) lagrangian/positions properly skips unneed elements in ASCII as well. --- IO/Geometry/vtkOpenFOAMReader.cxx | 751 ++++++++++++++++-------------- 1 file changed, 404 insertions(+), 347 deletions(-) diff --git a/IO/Geometry/vtkOpenFOAMReader.cxx b/IO/Geometry/vtkOpenFOAMReader.cxx index 5fcb7cdd28c..b73fe246522 100644 --- a/IO/Geometry/vtkOpenFOAMReader.cxx +++ b/IO/Geometry/vtkOpenFOAMReader.cxx @@ -1797,6 +1797,9 @@ public: } }; +//------------------------------------------------------------------------------ +// Specializations for vtkFoamToken + template <> inline bool vtkFoamToken::Is<vtkTypeInt8>() const { @@ -3420,38 +3423,13 @@ inline double vtkFoamReadValue<double>::ReadValue(vtkFoamIOobject& io) } //------------------------------------------------------------------------------ -// class vtkFoamEntryValue -// 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 vtkFoamEntryValue : public vtkFoamToken -{ -private: - typedef vtkFoamToken Superclass; - - bool IsUniformEntry; - bool Managed; - const vtkFoamEntry* UpperEntryPtr; - - vtkFoamEntryValue() = delete; - vtkObjectBase* ToVTKObject() { return this->Superclass::VtkObjectPtr; } - void Clear(); - void ReadList(vtkFoamIOobject& io); - -public: - // Construct empty value with given parent - explicit vtkFoamEntryValue(const vtkFoamEntry* parent) - : IsUniformEntry(false) - , Managed(true) - , UpperEntryPtr(parent) - { - } - // Copy construct - vtkFoamEntryValue(vtkFoamEntryValue& val, const vtkFoamEntry* parent); - ~vtkFoamEntryValue() { this->Clear(); } +// struct vtkFoamRead for reading primitives, lists etc. - // Helper Classes +struct vtkFoamRead +{ + // -------------------------------------------------------------------------- + // Reading lists of primitives (int/float/...) - // Reads primitive int/float lists template <typename listT, typename primitiveT> class listTraits { @@ -3468,9 +3446,18 @@ public: // Get the contained pointer listT* GetPointer() const noexcept { return this->Ptr; } - // Deference pointer for operation + // De-reference pointer for operation listT* operator->() const noexcept { return this->Ptr; } + void ReadValue(vtkFoamIOobject&, const vtkFoamToken& currToken) + { + if (!currToken.Is<primitiveT>()) + { + throw vtkFoamError() << "Expected an integer or a (, found " << currToken; + } + this->Ptr->InsertNextValue(currToken.To<primitiveT>()); + } + void ReadUniformValues(vtkFoamIOobject& io) { primitiveT value = vtkFoamReadValue<primitiveT>::ReadValue(io); @@ -3506,17 +3493,9 @@ public: fileData->Delete(); } } - - void ReadValue(vtkFoamIOobject&, vtkFoamToken& currToken) - { - if (!currToken.Is<primitiveT>()) - { - throw vtkFoamError() << "Expected an integer or a (, found " << currToken; - } - this->Ptr->InsertNextValue(currToken.To<primitiveT>()); - } }; + // -------------------------------------------------------------------------- // Reads rank 1 lists of types vector, sphericalTensor, symmTensor and tensor. // If isPositions is true it reads Cloud type of data as // particle positions. cf. (the positions format) @@ -3526,6 +3505,20 @@ public: { listT* Ptr; + // Items to skip for lagrangian/positions (class Cloud) after the x/y/z values. + // xyz (3*scalar) + celli (label) + // in OpenFOAM 1.4 -> 2.4 also had facei (label) and stepFraction (scalar) + // ASCII only + static void LagrangianPositionsSkip(vtkFoamIOobject& io) + { + (void)io.ReadIntegerValue(); // Skip celli (label) + if (io.GetLagrangianPositionsExtraData()) + { + (void)io.ReadIntegerValue(); // Skip facei (label) + (void)io.ReadDoubleValue(); // Skip stepFraction (scalar) + } + } + public: using ValueType = typename listT::ValueType; @@ -3538,9 +3531,25 @@ public: // Get the contained pointer listT* GetPointer() const noexcept { return this->Ptr; } - // Deference pointer for operation + // De-reference pointer for operation listT* operator->() const noexcept { return this->Ptr; } + void ReadValue(vtkFoamIOobject& io, const vtkFoamToken& currToken) + { + if (currToken != '(') + { + throw vtkFoamError() << "Expected '(', found " << currToken; + } + primitiveT tuple[nComponents]; + for (int cmpt = 0; cmpt < nComponents; ++cmpt) + { + tuple[cmpt] = vtkFoamReadValue<primitiveT>::ReadValue(io); + } + ::remapFoamTuple<nComponents == 6>(tuple); // For symmTensor + io.ReadExpecting(')'); + this->Ptr->InsertNextTuple(tuple); + } + void ReadUniformValues(vtkFoamIOobject& io) { const vtkIdType nTuples = this->Ptr->GetNumberOfTuples(); @@ -3555,9 +3564,8 @@ public: io.ReadExpecting(')'); if (isPositions) { - (void)io.ReadIntegerValue(); // Skip label celli + this->LagrangianPositionsSkip(io); } - for (vtkIdType i = 0; i < nTuples; ++i) { this->Ptr->SetTuple(i, tuple); @@ -3580,7 +3588,7 @@ public: io.ReadExpecting(')'); if (isPositions) { - (void)io.ReadIntegerValue(); // Skip label celli + this->LagrangianPositionsSkip(io); } } } @@ -3635,23 +3643,40 @@ public: } } } - - void ReadValue(vtkFoamIOobject& io, vtkFoamToken& currToken) - { - if (currToken != '(') - { - throw vtkFoamError() << "Expected '(', found " << currToken; - } - primitiveT tuple[nComponents]; - for (int cmpt = 0; cmpt < nComponents; ++cmpt) - { - tuple[cmpt] = vtkFoamReadValue<primitiveT>::ReadValue(io); - } - ::remapFoamTuple<nComponents == 6>(tuple); // For symmTensor - io.ReadExpecting(')'); - this->Ptr->InsertNextTuple(tuple); - } }; +}; + +//------------------------------------------------------------------------------ +// class vtkFoamEntryValue +// 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 vtkFoamEntryValue : public vtkFoamToken +{ +private: + typedef vtkFoamToken Superclass; + + bool IsUniformEntry; + bool Managed; + const vtkFoamEntry* UpperEntryPtr; + + vtkFoamEntryValue() = delete; + vtkObjectBase* ToVTKObject() { return this->Superclass::VtkObjectPtr; } + + // Delete if managed + void Clear(); + void ReadList(vtkFoamIOobject& io); + +public: + // Construct empty value with given parent + explicit vtkFoamEntryValue(const vtkFoamEntry* parent) + : IsUniformEntry(false) + , Managed(true) + , UpperEntryPtr(parent) + { + } + // Copy construct + vtkFoamEntryValue(vtkFoamEntryValue& val, const vtkFoamEntry* parent); + ~vtkFoamEntryValue() { this->Clear(); } // Member Functions @@ -3736,70 +3761,6 @@ public: this->Superclass::ScalarListPtr->FillValue(val); } - // Read dimensions set (always ASCII). The leading '[' has already been removed before calling. - // - can be integer or floating point - // - user-generated files may have only the first five dimensions. - // Note - // - may even have "human-readable" values such as [kg m^-1 s^-2] but they are very rare - // and we silently skip these - void ReadDimensionSet(vtkFoamIOobject& io) - { - const int nDimensions = 7; // There are 7 base dimensions - this->MakeScalarList(nDimensions, 0.0); - vtkFloatArray& dims = *(this->Superclass::ScalarListPtr); - - // Read using tokenizer to handle scalar/label, variable lengths, and ignore human-readable - vtkFoamToken tok; - char expectEnding = ']'; - bool goodInput = true; - - for (int ndims = 0; ndims < nDimensions && goodInput && expectEnding; ++ndims) - { - if (!io.Read(tok)) - { - goodInput = false; - } - else if (tok.IsNumeric()) - { - dims.SetValue(ndims, tok.ToFloat()); - } - else if (tok.IsPunctuation()) - { - if (tok == expectEnding) - { - expectEnding = '\0'; // Already got the closing ']' - } - else - { - goodInput = false; - } - } - else - { - // Some unknown token type (eg, encountered human-readable units) - // - skip until ']' - while ((goodInput = io.Read(tok)) == true) - { - if (tok.IsPunctuation() && (tok == expectEnding)) - { - expectEnding = '\0'; // Already got the closing ']' - break; - } - } - break; - } - } - - if (!goodInput) - { - io.ThrowStackTrace("Unexpected input while parsing dimensions array"); - } - else if (expectEnding) - { - io.ReadExpecting(expectEnding); - } - } - template <vtkFoamToken::tokenType listType, typename traitsT> void ReadNonUniformList(vtkFoamIOobject& io); @@ -3807,201 +3768,23 @@ public: // Return false if could not be dispatched bool ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::dataType fieldDataType); - // reads a list of labelLists. requires size prefix of the listList + bool ReadField(vtkFoamIOobject& io); + + // Read a list of labelLists. requires size prefix of the listList // to be present. size of each sublist must also be present in the // stream if the format is binary. - void ReadLabelListList(vtkFoamIOobject& io) - { - // NOTE: - // when OpenFOAM writes a "faceCompactList" it automatically switches to ASCII - // if it detects that the offsets will overflow 32bits. - // - // We risk the same overflow potential when constructing a compact labelListList. - // Thus assume the worst and use 64bit sizing when reading ASCII. - - const bool use64BitLabels = (io.IsLabel64() || io.IsAsciiFormat()); - - vtkFoamToken currToken; - currToken.SetStreamOption(io); - if (!io.Read(currToken)) - { - throw vtkFoamError() << "Unexpected EOF"; - } - if (currToken.IsLabel()) - { - const vtkTypeInt64 listLen = currToken.To<vtkTypeInt64>(); - if (listLen < 0) - { - throw vtkFoamError() << "Illegal negative list length: " << listLen; - } - if (use64BitLabels) - { - this->LabelListListPtr = new vtkFoamLabelListList64; - } - else - { - this->LabelListListPtr = new vtkFoamLabelListList32; - } - // Initial guess for list length - this->LabelListListPtr->ResizeExact(listLen, 4 * listLen); - - this->Superclass::Type = vtkFoamToken::LABELLISTLIST; - io.ReadExpecting('('); - vtkIdType nTotalElems = 0; - for (vtkTypeInt64 idx = 0; idx < listLen; ++idx) - { - if (!io.Read(currToken)) - { - throw vtkFoamError() << "Unexpected EOF"; - } - if (currToken.IsLabel()) - { - const vtkTypeInt64 sublistLen = currToken.To<vtkTypeInt64>(); - if (sublistLen < 0) - { - throw vtkFoamError() << "Illegal negative list length: " << sublistLen; - } - - // LabelListListPtr->SetOffset(idx, nTotalElems); - void* sublist = this->LabelListListPtr->WritePointer(idx, nTotalElems, sublistLen); - - if (io.IsAsciiFormat()) - { - io.ReadExpecting('('); - for (vtkTypeInt64 subIdx = 0; subIdx < sublistLen; ++subIdx) - { - vtkTypeInt64 value(vtkFoamReadValue<vtkTypeInt64>::ReadValue(io)); - this->LabelListListPtr->SetValue(idx, subIdx, value); - } - io.ReadExpecting(')'); - } - else if (sublistLen > 0) - { - // Non-empty (binary) list - only read parentheses only when size > 0 - const size_t nbytes = - static_cast<size_t>(sublistLen * this->LabelListListPtr->GetLabelSize()); - - io.ReadExpecting('('); - io.Read(reinterpret_cast<unsigned char*>(sublist), nbytes); - io.ReadExpecting(')'); - } - nTotalElems += sublistLen; - } - else if (currToken == '(') - { - this->Superclass::LabelListListPtr->SetOffset(idx, nTotalElems); - while (io.Read(currToken) && currToken != ')') - { - if (!currToken.IsLabel()) - { - throw vtkFoamError() << "Expected an integer, found " << currToken; - } - this->Superclass::LabelListListPtr->InsertValue(nTotalElems++, currToken.To<int>()); - ++nTotalElems; - } - } - else - { - throw vtkFoamError() << "Expected integer or '(', found " << currToken; - } - } - - // Set the final offset - this->Superclass::LabelListListPtr->SetOffset(listLen, nTotalElems); - - // Shrink to the actually used size - this->Superclass::LabelListListPtr->ResizeData(nTotalElems); - io.ReadExpecting(')'); - } - else - { - throw vtkFoamError() << "Expected integer, found " << currToken; - } - } + void ReadLabelListList(vtkFoamIOobject& io); // Read compact labelListList which has offsets and data - void ReadCompactLabelListList(vtkFoamIOobject& io) - { - if (io.IsAsciiFormat()) - { - this->ReadLabelListList(io); - return; - } - - this->SetStreamOption(io); - const bool use64BitLabels = io.IsLabel64(); - - if (use64BitLabels) - { - this->LabelListListPtr = new vtkFoamLabelListList64; - } - else - { - this->LabelListListPtr = new vtkFoamLabelListList32; - } - this->Superclass::Type = vtkFoamToken::LABELLISTLIST; - for (int arrayI = 0; arrayI < 2; arrayI++) - { - vtkFoamToken currToken; - currToken.SetStreamOption(io); - if (!io.Read(currToken)) - { - throw vtkFoamError() << "Unexpected EOF"; - } - if (currToken.IsLabel()) - { - vtkTypeInt64 listLen = currToken.To<vtkTypeInt64>(); - if (listLen < 0) - { - throw vtkFoamError() << "Illegal negative list length: " << listLen; - } - - vtkDataArray* array = (arrayI == 0 ? this->Superclass::LabelListListPtr->GetOffsetsArray() - : this->Superclass::LabelListListPtr->GetDataArray()); - array->SetNumberOfValues(static_cast<vtkIdType>(listLen)); - - if (listLen > 0) - { - // Non-empty (binary) list - only read parentheses only when size > 0 - - io.ReadExpecting('('); // Begin list - io.Read(reinterpret_cast<unsigned char*>(array->GetVoidPointer(0)), - static_cast<vtkTypeInt64>(listLen * array->GetDataTypeSize())); - io.ReadExpecting(')'); // End list - } - } - else - { - throw vtkFoamError() << "Expected integer, found " << currToken; - } - } - } - - bool ReadField(vtkFoamIOobject& io) - { - this->SetStreamOption(io); - - // Basic field types: "boolField", "labelField", "scalarField" ... - vtkFoamTypes::dataType listDataType(vtkFoamTypes::FieldToEnum(io.GetClassName())); + void ReadCompactLabelListList(vtkFoamIOobject& io); - try - { - if (vtkFoamTypes::IsGood(listDataType)) - { - this->ReadNonUniformList(io, listDataType); - } - else - { - throw vtkFoamError() << "Unsupported field type " << io.GetClassName(); - } - } - catch (const vtkFoamError& err) - { - io.SetError(err); - return false; - } - return true; - } + // Read dimensions set (always ASCII). The leading '[' has already been removed before calling. + // - can be integer or floating point + // - user-generated files may have only the first five dimensions. + // Note + // - may even have "human-readable" values such as [kg m^-1 s^-2] but they are very rare + // and we silently skip these + void ReadDimensionSet(vtkFoamIOobject& io); }; //------------------------------------------------------------------------------ @@ -4087,7 +3870,9 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { // List<bool> is read as a list of bytes (binary) or ints (ascii) // - primary location is the flipMap entry in faceZones - this->ReadNonUniformList<BOOLLIST, listTraits<vtkTypeInt8Array, vtkTypeInt8>>(io); + + this->ReadNonUniformList<BOOLLIST, // + vtkFoamRead::listTraits<vtkTypeInt8Array, vtkTypeInt8>>(io); break; } @@ -4095,11 +3880,13 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { if (io.IsLabel64()) { - this->ReadNonUniformList<LABELLIST, listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); + this->ReadNonUniformList<LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); } else { - this->ReadNonUniformList<LABELLIST, listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); + this->ReadNonUniformList<LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); } break; } @@ -4108,11 +3895,13 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { if (io.IsFloat64()) { - this->ReadNonUniformList<SCALARLIST, listTraits<vtkFloatArray, double>>(io); + this->ReadNonUniformList<SCALARLIST, // + vtkFoamRead::listTraits<vtkFloatArray, double>>(io); } else { - this->ReadNonUniformList<SCALARLIST, listTraits<vtkFloatArray, float>>(io); + this->ReadNonUniformList<SCALARLIST, // + vtkFoamRead::listTraits<vtkFloatArray, float>>(io); } break; } @@ -4121,11 +3910,13 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { if (io.IsFloat64()) { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, double, 1>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, double, 1>>(io); } else { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, float, 1>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, float, 1>>(io); } break; } @@ -4134,11 +3925,13 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { if (io.IsFloat64()) { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, double, 3>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, double, 3>>(io); } else { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, float, 3>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, float, 3>>(io); } break; } @@ -4147,11 +3940,13 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { if (io.IsFloat64()) { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, double, 6>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, double, 6>>(io); } else { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, float, 6>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, float, 6>>(io); } break; } @@ -4160,11 +3955,13 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da { if (io.IsFloat64()) { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, double, 9>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, double, 9>>(io); } else { - this->ReadNonUniformList<VECTORLIST, vectorListTraits<vtkFloatArray, float, 9>>(io); + this->ReadNonUniformList<VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, float, 9>>(io); } break; } @@ -4178,6 +3975,266 @@ bool vtkFoamEntryValue::ReadNonUniformList(vtkFoamIOobject& io, vtkFoamTypes::da return handled; } +bool vtkFoamEntryValue::ReadField(vtkFoamIOobject& io) +{ + this->SetStreamOption(io); + + // Basic field types: "boolField", "labelField", "scalarField" ... + vtkFoamTypes::dataType listDataType(vtkFoamTypes::FieldToEnum(io.GetClassName())); + + try + { + if (vtkFoamTypes::IsGood(listDataType)) + { + this->ReadNonUniformList(io, listDataType); + } + else + { + throw vtkFoamError() << "Unsupported field type " << io.GetClassName(); + } + } + catch (const vtkFoamError& err) + { + io.SetError(err); + return false; + } + return true; +} + +// Read a list of labelLists. requires size prefix of the listList +// to be present. size of each sublist must also be present in the +// stream if the format is binary. +void vtkFoamEntryValue::ReadLabelListList(vtkFoamIOobject& io) +{ + // NOTE: + // when OpenFOAM writes a "faceCompactList" it automatically switches to ASCII + // if it detects that the offsets will overflow 32bits. + // + // We risk the same overflow potential when constructing a compact labelListList. + // Thus assume the worst and use 64bit sizing when reading ASCII. + + const bool use64BitLabels = (io.IsLabel64() || io.IsAsciiFormat()); + + vtkFoamToken currToken; + currToken.SetStreamOption(io); + if (!io.Read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if (currToken.IsLabel()) + { + const vtkTypeInt64 listLen = currToken.To<vtkTypeInt64>(); + if (listLen < 0) + { + throw vtkFoamError() << "Illegal negative list length: " << listLen; + } + if (use64BitLabels) + { + this->LabelListListPtr = new vtkFoamLabelListList64; + } + else + { + this->LabelListListPtr = new vtkFoamLabelListList32; + } + // Initial guess for list length + this->LabelListListPtr->ResizeExact(listLen, 4 * listLen); + + this->Superclass::Type = vtkFoamToken::LABELLISTLIST; + io.ReadExpecting('('); + vtkIdType nTotalElems = 0; + for (vtkTypeInt64 idx = 0; idx < listLen; ++idx) + { + if (!io.Read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if (currToken.IsLabel()) + { + const vtkTypeInt64 sublistLen = currToken.To<vtkTypeInt64>(); + if (sublistLen < 0) + { + throw vtkFoamError() << "Illegal negative list length: " << sublistLen; + } + + // LabelListListPtr->SetOffset(idx, nTotalElems); + void* sublist = this->LabelListListPtr->WritePointer(idx, nTotalElems, sublistLen); + + if (io.IsAsciiFormat()) + { + io.ReadExpecting('('); + for (vtkTypeInt64 subIdx = 0; subIdx < sublistLen; ++subIdx) + { + vtkTypeInt64 value(vtkFoamReadValue<vtkTypeInt64>::ReadValue(io)); + this->LabelListListPtr->SetValue(idx, subIdx, value); + } + io.ReadExpecting(')'); + } + else if (sublistLen > 0) + { + // Non-empty (binary) list - only read parentheses only when size > 0 + const size_t nbytes = + static_cast<size_t>(sublistLen * this->LabelListListPtr->GetLabelSize()); + + io.ReadExpecting('('); + io.Read(reinterpret_cast<unsigned char*>(sublist), nbytes); + io.ReadExpecting(')'); + } + nTotalElems += sublistLen; + } + else if (currToken == '(') + { + this->Superclass::LabelListListPtr->SetOffset(idx, nTotalElems); + while (io.Read(currToken) && currToken != ')') + { + if (!currToken.IsLabel()) + { + throw vtkFoamError() << "Expected an integer, found " << currToken; + } + this->Superclass::LabelListListPtr->InsertValue(nTotalElems++, currToken.To<int>()); + ++nTotalElems; + } + } + else + { + throw vtkFoamError() << "Expected integer or '(', found " << currToken; + } + } + + // Set the final offset + this->Superclass::LabelListListPtr->SetOffset(listLen, nTotalElems); + + // Shrink to the actually used size + this->Superclass::LabelListListPtr->ResizeData(nTotalElems); + io.ReadExpecting(')'); + } + else + { + throw vtkFoamError() << "Expected integer, found " << currToken; + } +} + +// Read compact labelListList which has offsets and data +void vtkFoamEntryValue::ReadCompactLabelListList(vtkFoamIOobject& io) +{ + if (io.IsAsciiFormat()) + { + this->ReadLabelListList(io); + return; + } + + this->SetStreamOption(io); + const bool use64BitLabels = io.IsLabel64(); + + if (use64BitLabels) + { + this->LabelListListPtr = new vtkFoamLabelListList64; + } + else + { + this->LabelListListPtr = new vtkFoamLabelListList32; + } + this->Superclass::Type = vtkFoamToken::LABELLISTLIST; + for (int arrayI = 0; arrayI < 2; arrayI++) + { + vtkFoamToken currToken; + currToken.SetStreamOption(io); + if (!io.Read(currToken)) + { + throw vtkFoamError() << "Unexpected EOF"; + } + if (currToken.IsLabel()) + { + vtkTypeInt64 listLen = currToken.To<vtkTypeInt64>(); + if (listLen < 0) + { + throw vtkFoamError() << "Illegal negative list length: " << listLen; + } + + vtkDataArray* array = (arrayI == 0 ? this->Superclass::LabelListListPtr->GetOffsetsArray() + : this->Superclass::LabelListListPtr->GetDataArray()); + array->SetNumberOfValues(static_cast<vtkIdType>(listLen)); + + if (listLen > 0) + { + // Non-empty (binary) list - only read parentheses only when size > 0 + + io.ReadExpecting('('); // Begin list + io.Read(reinterpret_cast<unsigned char*>(array->GetVoidPointer(0)), + static_cast<vtkTypeInt64>(listLen * array->GetDataTypeSize())); + io.ReadExpecting(')'); // End list + } + } + else + { + throw vtkFoamError() << "Expected integer, found " << currToken; + } + } +} + +// Read dimensions set (always ASCII). The leading '[' has already been removed before calling. +// - can be integer or floating point +// - user-generated files may have only the first five dimensions. +// Note +// - may even have "human-readable" values such as [kg m^-1 s^-2] but they are very rare +// and we silently skip these +void vtkFoamEntryValue::ReadDimensionSet(vtkFoamIOobject& io) +{ + const int nDimensions = 7; // There are 7 base dimensions + this->MakeScalarList(nDimensions, 0.0); + vtkFloatArray& dims = *(this->Superclass::ScalarListPtr); + + // Read using tokenizer to handle scalar/label, variable lengths, and ignore human-readable + vtkFoamToken tok; + char expectEnding = ']'; + bool goodInput = true; + + for (int ndims = 0; ndims < nDimensions && goodInput && expectEnding; ++ndims) + { + if (!io.Read(tok)) + { + goodInput = false; + } + else if (tok.IsNumeric()) + { + dims.SetValue(ndims, tok.ToFloat()); + } + else if (tok.IsPunctuation()) + { + if (tok == expectEnding) + { + expectEnding = '\0'; // Already got the closing ']' + } + else + { + goodInput = false; + } + } + else + { + // Some unknown token type (eg, encountered human-readable units) + // - skip until ']' + while ((goodInput = io.Read(tok)) == true) + { + if (tok.IsPunctuation() && (tok == expectEnding)) + { + expectEnding = '\0'; // Already got the closing ']' + break; + } + } + break; + } + } + + if (!goodInput) + { + io.ThrowStackTrace("Unexpected input while parsing dimensions array"); + } + else if (expectEnding) + { + io.ReadExpecting(expectEnding); + } +} + //------------------------------------------------------------------------------ // class vtkFoamEntry // a class that represents an entry of a dictionary. note that an @@ -6547,13 +6604,13 @@ vtkSmartPointer<vtkFloatArray> vtkOpenFOAMReaderPrivate::ReadPointsFile( if (io.IsFloat64()) { - dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, - vtkFoamEntryValue::vectorListTraits<vtkFloatArray, double, 3>>(io); + dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, double, 3>>(io); } else { - dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, - vtkFoamEntryValue::vectorListTraits<vtkFloatArray, float, 3>>(io); + dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, float, 3>>(io); } // Capture content as smart pointer @@ -6660,13 +6717,13 @@ bool vtkOpenFOAMReaderPrivate::ReadOwnerNeighbourFiles(const std::string& timeRe { if (use64BitLabels) { - ownerDict.ReadNonUniformList<vtkFoamToken::LABELLIST, - vtkFoamEntryValue::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); + ownerDict.ReadNonUniformList<vtkFoamToken::LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); } else { - ownerDict.ReadNonUniformList<vtkFoamToken::LABELLIST, - vtkFoamEntryValue::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); + ownerDict.ReadNonUniformList<vtkFoamToken::LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); } } catch (const vtkFoamError& err) @@ -6721,13 +6778,13 @@ bool vtkOpenFOAMReaderPrivate::ReadOwnerNeighbourFiles(const std::string& timeRe { if (use64BitLabels) { - neighDict.ReadNonUniformList<vtkFoamToken::LABELLIST, - vtkFoamEntryValue::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); + neighDict.ReadNonUniformList<vtkFoamToken::LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); } else { - neighDict.ReadNonUniformList<vtkFoamToken::LABELLIST, - vtkFoamEntryValue::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); + neighDict.ReadNonUniformList<vtkFoamToken::LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); } } catch (const vtkFoamError& err) @@ -9554,13 +9611,13 @@ vtkMultiBlockDataSet* vtkOpenFOAMReaderPrivate::MakeLagrangianMesh() { if (io.IsFloat64()) { - dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, - vtkFoamEntryValue::vectorListTraits<vtkFloatArray, double, 3, true>>(io); + dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, double, 3, true>>(io); } else { - dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, - vtkFoamEntryValue::vectorListTraits<vtkFloatArray, float, 3, true>>(io); + dict.ReadNonUniformList<vtkFoamToken::VECTORLIST, // + vtkFoamRead::vectorListTraits<vtkFloatArray, float, 3, true>>(io); } // Transfer float tuples to points @@ -10118,13 +10175,13 @@ bool vtkOpenFOAMReaderPrivate::GetAreaMesh( { if (use64BitLabels) { - dict.ReadNonUniformList<vtkFoamToken::LABELLIST, - vtkFoamEntryValue::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); + dict.ReadNonUniformList<vtkFoamToken::LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt64Array, vtkTypeInt64>>(io); } else { - dict.ReadNonUniformList<vtkFoamToken::LABELLIST, - vtkFoamEntryValue::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); + dict.ReadNonUniformList<vtkFoamToken::LABELLIST, // + vtkFoamRead::listTraits<vtkTypeInt32Array, vtkTypeInt32>>(io); } // Capture content as smart pointer -- GitLab