/*! Skips all fields in the stream, until the field end
    marker "" is encountered.
 */
void
OSBCommonElement::skipFields(void)
{
    BinaryReadHandler *rh = editRoot()->getReadHandler();

    while(true)
    {
        std::string fieldName;
        std::string fieldTypeName;
        UInt32      fieldSize;

        rh->getValue(fieldName);

        if(fieldName.empty())
        {
            OSG_OSB_LOG(("OSBCommonElement::skipFields: "
                    "Found field end marker.\n"      ));
            break;
        }

        rh->getValue(fieldTypeName);
        rh->getValue(fieldSize    );
        rh->skip    (fieldSize    );

        OSG_OSB_LOG(("OSBCommonElement::skipFields: fieldTypeName [%s] fieldSize [%u]\n",
                fieldTypeName.c_str(), fieldSize));
    }
}
void
OSBGeometryElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBGeometryElement::read: [%s]\n", typeName.c_str()));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    rh->getValue(_version);
    OSG_OSB_LOG(("OSBGeometryElement::read: version: [%u]\n", _version));

    if(_version >= OSGOSBHeaderVersion200)
    {
        if(_version > OSGOSBHeaderVersion200)
        {
            FINFO(("OSBGeometryElement::read: "
                   "Unknown version, trying to read as latest.\n"));
        }

        setContainer(GeometryUnrecPtr(Geometry::create()));
        readFields("", "");
    }
    else if(_version >= OSGOSBHeaderVersion100)
    {
        readV100();
    }
}
void
OSBNodeElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBNodeElement::read [%s]\n", typeName.c_str()));

    BinaryReadHandler *rh        = editRoot()->getReadHandler();
    UInt8              fcPtrType;
    UInt16             version;

    rh->getValue(fcPtrType);
    rh->getValue(version  );

    OSG_OSB_LOG(("OSBNodeElement::read: version: [%u]\n", version));

    if(fcPtrType != OSBCommonElement::FCPtrNode)
    {
        FFATAL(("OSBNodeElement::read: fcPtrType has unexpected value.\n"));

        skipFields();
        return;
    }

    NodeUnrecPtr node = Node::create();

    setContainer(node);
    readFields("'volume'", "");
}
/*! Reads a MFFieldContainerPtr (or a more specific pointer type) from the
    stream. It has the given \a fieldId in the container it belongs to.

    \param[in] fieldId Id of the field in the container it belongs to.
    \param[in] fieldSize field size
    \return Iterator that points to the PtrFieldInfo structure
    that was created for this field.
 */
OSBCommonElement::PtrFieldListIt
OSBCommonElement::readPtrMultiField(
    const UInt32 fieldId, const UInt32 fieldSize)
{
    OSG_OSB_LOG(("OSBCommonElement::readPtrMultiField: "
            "fieldId: [%u]\n", fieldId));

    UInt32             ptrId;
    UInt32             numElements;
    OSBRootElement    *root        = editRoot();
    BinaryReadHandler *rh          = editRoot()->getReadHandler();

    root->editPtrFieldList().push_back(PtrFieldInfo(getContainer(), fieldId));
    PtrFieldInfo &pfi = root->editPtrFieldList().back();

    rh->getValue(numElements);

    OSG_OSB_LOG(("OSBCommonElement::readPtrMultiField: ptrIds ["));

    for(UInt32 i = 0; i < numElements; ++i)
    {
        rh->getValue(ptrId);
        pfi.editIdStore().push_back(ptrId);

        OSG_OSB_PLOG(("%u ", ptrId));
    }

    OSG_OSB_PLOG(("]\n"));

    return --(root->editPtrFieldList().end());
}
/*! Reads the common part introducing a Field, but after the field name is
    already consumed from the input stream. This is mainly useful to continue
    reading after readFields stopped on a non empty endMarkers entry.
    The information from the field header is returned in \a fieldTypeName and
    \a fieldSize.

    By default reading would stop an a field name of "", by passing a string
    of type names in \a endMarkers additional stop conditions can be specified.

    The format of the \a endMarkers string is: "'name1' 'name2' 'name3'", the
    spaces between the "'" are mandatory.

    \param[in] endMarkers String of field names on which reading stops.
    \param[in] fieldName Name of the next field in the stream.
    \param[out] fieldTypeName Type of the next field in the stream - only valid
    if true is returned.
    \param[out] fieldSize Size in bytes of the next field in the stream -
    only valid if true is returned.

    \return False, if an endMarker (including the implicit "") is encountered,
    true otherwise.

    \sa OSG::OSBCommonElement::readFieldContent
    \sa OSG::OSBCommonElement::readFieldHeader
 */
bool
OSBCommonElement::readFieldHeaderContinue(
    const std::string &endMarkers,
    const std::string &fieldName,
          std::string &fieldTypeName,
          UInt32      &fieldSize     )
{
    OSG_OSB_LOG(("OSBCommonElement::readFieldHeaderContinue\n"));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    if(fieldName.empty() ||
       (!endMarkers.empty() &&
       (endMarkers.find("'" + fieldName + "'") != std::string::npos)))
    {
        OSG_OSB_LOG(("OSBCommonElement::readFieldHeaderContinue: "
                "Found field end marker.\n"));

        return false;
    }
    else
    {
        rh->getValue(fieldTypeName);
        rh->getValue(fieldSize    );

        OSG_OSB_LOG(("OSBCommonElement::readFieldHeaderContinue: "
                "[%s] [%s] [%u]\n",
                fieldName.c_str(), fieldTypeName.c_str(), fieldSize));

        return true;
    }
}
void
OSBGenericElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBGenericElement::read [%s]\n", typeName.c_str()));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    UInt8  ptrTypeTag;
    UInt16 version;

    rh->getValue(ptrTypeTag);
    rh->getValue(version   );

    OSG_OSB_LOG(("OSBGenericElement::read: version: [%u] ptrTypeTag [%u]\n",
                 version, ptrTypeTag));

    setContainer(FieldContainerUnrecPtr(
        FieldContainerFactory::the()->createContainer(typeName.c_str())));

    if(getContainer() == NULL)
    {
        FWARNING(("OSBGenericElement::read: Skipping unknown "
                  "FieldContainer [%s].\n", typeName.c_str()));

        skipFields();

        setContainer(FieldContainerUnrecPtr(createReplacementFC(ptrTypeTag)));
        return;
    }

    readFields("", "");
}
void
OSBNameElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBNameElement::read [%s]\n", typeName.c_str()));

    BinaryReadHandler *rh        = editRoot()->getReadHandler();
    UInt8              fcPtrType;
    UInt16             version;

    rh->getValue(fcPtrType);
    rh->getValue(version  );

    setContainer(NameUnrecPtr(Name::create()));
    readFields("", "");
}
/*! Reads the common part introducing a Field and returns the information
    in \a fieldName, \a fieldTypeName, and \a fieldSize.
    By default reading would stop an a field name of "", by passing a string
    of type names in \a endMarkers additional stop conditions can be specified.

    The format of the \a endMarkers string is: "'name1' 'name2' 'name3'", the
    spaces between the "'" are mandatory.

    \param[in] endMarkers String of field names on which reading stops.
    \param[out] fieldName Name of the next field in the stream.
    \param[out] fieldTypeName Type of the next field in the stream - only valid
    if true is returned.
    \param[out] fieldSize Size in bytes of the next field in the stream -
    only valid if true is returned.

    \return False, if an endMarker (including the implicit "") is encountered,
    true otherwise.

    \sa OSG::OSBCommonElement::readFieldContent
    \sa OSG::OSBCommonElement::readFieldHeaderContinue
 */
bool
OSBCommonElement::readFieldHeader(
    const std::string &endMarkers,
          std::string &fieldName,
          std::string &fieldTypeName,
          UInt32      &fieldSize     )
{
    OSG_OSB_LOG(("OSBCommonElement::readFieldHeader\n"));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    rh->getValue(fieldName);

    return readFieldHeaderContinue(endMarkers, fieldName,
                                   fieldTypeName, fieldSize);
}
void
OSBShaderParameterMIntElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBShaderParameterMIntElement::read: [%s]\n",
                 typeName.c_str()));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    UInt8  ptrTypeId;
    UInt16 version;

    rh->getValue(ptrTypeId);
    rh->getValue(version  );

    OSG_OSB_LOG(("OSBShaderParameterMIntElement::read: version: [%u]\n",
                 version));

    std::string    fieldName;
    std::string    fieldTypeName;
    UInt32         fieldSize;
    PtrFieldListIt ptrFieldIt;

    while(readFieldHeader("", fieldName, fieldTypeName, fieldSize))
    {
        if(fieldName == "name")
        {
            _name.copyFromBin(*rh);
        }
        else if(fieldName == "value")
        {
            _value.copyFromBin(*rh);
        }
        else
        {
            OSG_OSB_LOG(("Skipping [%d] bytes for field [%s]\n",
                         fieldSize, fieldName.c_str()));
            rh->skip(fieldSize);
        }
    }

    // no container is created for this element, which means the root does
    // not automatically insert it into the IdElemMap - do it manually
    editRoot()->editIdElemMap().insert(
        OSBRootElement::IdElemMap::value_type(getFCIdFile(), this));
}
void OSBChunkBlockElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBChunkBlockElement::read [%s]\n", typeName.c_str()));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    UInt8  ptrTypeId;
    UInt16 version;

    rh->getValue(ptrTypeId);
    rh->getValue(version  );

    OSG_OSB_LOG(("OSBChunkBlockElement::read: version: [%u]\n", version));

    std::string    fieldName;
    std::string    fieldTypeName;
    UInt32         fieldSize;
    PtrFieldListIt ptrFieldIt;

    ChunkBlockUnrecPtr pMat = dynamic_pointer_cast<ChunkBlock>(
        FieldContainerFactory::the()->createContainer(typeName.c_str()));

    setContainer(pMat);

    while(readFieldHeader("", fieldName, fieldTypeName, fieldSize))
    {
        if(fieldName == "chunks")
        {
            // keep an interator to the _mfChunks field contents
            readFieldContent(fieldName, fieldTypeName, fieldSize, "",
                             _chunksPtrFieldIt);

            _chunksPtrFieldItValid = true;
        }
        else
        {
            readFieldContent(fieldName, fieldTypeName, fieldSize, "",
                             ptrFieldIt);
        }
    }
}
/*! Reads the common part introducing a FieldContainer and returns
    the information in \a typeName and \a fcId.

    \param[out] typeName Type of the next container in the stream or "" if
    no more data is available.
    \param[out] fcId Id of the next container - only valid if true is returned.

    \return If another container is to be read, true is returned,
    otherwise false.
 */
bool
OSBCommonElement::readFieldContainerHeader(
    std::string &typeName,
    UInt32      &fcId     )
{
    OSG_OSB_LOG(("OSBCommonElement::readFieldContainerHeader\n"));

    BinaryReadHandler *rh = editRoot()->getReadHandler();

    rh->getValue(typeName);

    if(typeName.empty())
        return false;

    rh->getValue(fcId);

    OSG_OSB_LOG(("OSBCommonElement::readFieldContainerHeader: [%s] [%u]\n",
            typeName.c_str(), fcId));

    return true;
}
/*! Reads from the stream set by a preceding call to initialiseRead. Since the
    root element is the first one created it reads the file header and
    creates the elements to read the data following the header.

    \param[in] typeName The argument is ignored.
 */
void
OSBRootElement::read(const std::string &/*typeName*/)
{
    OSG_OSB_LOG(("OSBRootElement::read\n"));

    BinaryReadHandler *rh           = getReadHandler();
    std::string        headerMarker;

    rh->getValue(headerMarker);

    if(headerMarker == OSGOSB_HEADER_ID_1)
    {
        OSG_OSB_LOG(("OSBRootElement::read: Header version: [%u]\n",
                OSGOSBHeaderVersion100));
        setHeaderVersion(OSGOSBHeaderVersion100);
    }
    else if(headerMarker == OSGOSB_HEADER_ID_2)
    {
        OSG_OSB_LOG(("OSBRootElement::read: Header version: [%u]\n",
                OSGOSBHeaderVersion200));
        setHeaderVersion(OSGOSBHeaderVersion200);
    }
//     else if(headerMarker == OSGOSB_HEADER_ID_201)
//     {
//         OSG_OSB_LOG(("OSBRootElement::read: Header version: [%u]\n",
//                 OSGOSBHeaderVersion201));
//         setHeaderVersion(OSGOSBHeaderVersion201);
//     }
    else
    {
        FWARNING(("OSBRootElement::read: Unrecognized file header, could not "
                  "load file.\n"));
        return;
    }

    std::string headerName;
    rh->getValue(headerName);
    std::string headerOptions;
    rh->getValue(headerOptions);
    UInt64 fileSize;
    rh->getValue(fileSize);

    OSG_OSB_LOG(("OSBRootElement::read: headerName: [%s]\n",
            headerName.c_str()));
    OSG_OSB_LOG(("OSBRootElement::read: headerOptions: [%s]\n",
            headerOptions.c_str()));
    OSG_OSB_LOG(("OSBRootElement::read: fileSize: [%" PRISize "]\n",
            fileSize));

    std::string     fcTypeName;
    UInt32          fcIdFile;    // id used in the file
    UInt32          fcIdSystem;  // id used in the system
    OSBElementBase *elem;

    while(true)
    {
        if(!readFieldContainerHeader(fcTypeName, fcIdFile))
            break;

        OSG_OSB_LOG(("OSBRootElement::read: fcTypeName [%s] fcIdFile: [%u]\n",
                fcTypeName.c_str(), fcIdFile));

        elem = OSBElementFactory::the()->acquire(fcTypeName, this);
        elem->setFCIdFile(fcIdFile  );
        elem->read       (fcTypeName);

        if(elem->getContainer() != NULL)
        {
            fcIdSystem = elem->getContainer()->getId();

            OSG_OSB_LOG(("OSBRootElement::read: fcIdFile: [%u] fcIdSystem: [%u]\n",
                    fcIdFile, fcIdSystem));

            editIdMap().insert(
                FieldContainerIdMap::value_type(fcIdFile, fcIdSystem));

            if(getContainer() == NULL)
            {
                setContainer(elem->getContainer());
            }

            editElementList().push_back(elem                          );
            editIdElemMap  ().insert   (std::make_pair(fcIdFile, elem));
        }
    }
}
void
OSBTextureChunkElement::read(const std::string &typeName)
{
    OSG_OSB_LOG(("OSBTextureChunkElement::read: [%s]\n", typeName.c_str()));

    BinaryReadHandler *rh = editRoot()->getReadHandler();
    
    UInt8  ptrTypeId;
    UInt16 version;

    rh->getValue(ptrTypeId);
    rh->getValue(version  );

    OSG_OSB_LOG(("OSBTextureChunkElement::read: version: [%u]\n", version));
    
    // create the two replacement chunks
    _pTexObj = TextureObjChunk::create();
    _pTexEnv = TextureEnvChunk::create();
        
    std::string    fieldName;
    std::string    fieldTypeName;
    UInt32         fieldSize;
    PtrFieldListIt ptrFieldIt;
    
    while(readFieldHeader("", fieldName, fieldTypeName, fieldSize))
    {
        // some fields need to be duplicated for the two replacement chunks
        if(fieldName == "parents")
        {
            // parent fields are ignored
            rh->skip(fieldSize);
        }    
        else if(fieldName == "internal")
        {
            bool fieldValue;
            rh->getValue(fieldValue);
            
            _pTexObj->setInternal(fieldValue);
            _pTexEnv->setInternal(fieldValue);
        }
        else if(fieldName == "ignore")
        {
            bool fieldValue;
            rh->getValue(fieldValue);
            
            _pTexObj->setIgnore(fieldValue);
            _pTexEnv->setIgnore(fieldValue);
        }        
        else if(isTexObjField(fieldName))
        {
            // set TexObj as container for reading the field
            setContainer(_pTexObj);
            readFieldContent(fieldName, fieldTypeName, fieldSize, "", ptrFieldIt);
        }
        else if(isTexEnvField(fieldName))
        {
            // set TexEnv as container for reading the field
            setContainer(_pTexEnv);
            readFieldContent(fieldName, fieldTypeName, fieldSize, "", ptrFieldIt);
        }
        else
        {
            FWARNING(("OSBTextureChunkElement::read: Skipping unrecognized "
                      "field [%s].\n", fieldName.c_str()));
                      
            rh->skip(fieldSize);
        }
    }
    
    // set TexObj as "the" container
    setContainer(_pTexObj);
}
示例#14
0
void
OSBGeometryElement::readV100(void)
{
    OSG_OSB_LOG(("OSBGeometryElement::readV100:\n"));

    OSBRootElement    *root = editRoot();
    BinaryReadHandler *rh   = editRoot()->getReadHandler();
    OSBGeometryHelper  gh;

    GeometryUnrecPtr geo = Geometry::create();
    setContainer(geo);

    // The "properties" mfield can be thought of the unification of the
    // "positions", "normals", etc sfields of the 1.x Geometry.
    // For the conversion the PtrFieldInfo structure for the "properties"
    // mfield is filled with the corresponding ids of the sfields from the
    // file. The remapping after postRead will fill in the right pointers.

    FieldDescriptionBase *propFieldDesc =
        geo->getFieldDescription("properties");
    UInt32                propFieldId   = propFieldDesc->getFieldId();

    root->editPtrFieldList().push_back(PtrFieldInfo(geo, propFieldId));
    PtrFieldInfo &propFieldPFI = root->editPtrFieldList().back();

    propFieldPFI.editIdStore().resize(Geometry::MaxAttribs);

    while(true)
    {
        std::string    fieldName;
        std::string    fieldTypeName;
        UInt32         fieldSize;
        PtrFieldListIt ptrFieldIt;

        if(!readFieldHeader("", fieldName, fieldTypeName, fieldSize))
        {
            OSG_OSB_LOG(("OSBGeometryElement::readV100: "
                    "Reading stopped at field: [%s].\n", fieldName.c_str()));
            break;
        }

        if(fieldName == "indexMapping")
        {
            // read into temporary field
            MField<UInt16> indexMappingField;
            indexMappingField.copyFromBin(*rh);

            // copy to member for use in postRead
            indexMappingField.getValues().swap(_indexMapping);
        }
        else if(fieldName == "indices")
        {
            // read container id of indices property
            // postRead will handle the conversion of multi indices
            rh->getValue(_indicesId);
        }
        else if(fieldName == "positions")
        {
            UInt32 positionsId;
            rh->getValue(positionsId);
            propFieldPFI.editIdStore()[Geometry::PositionsIndex] = positionsId;
        }
        else if(fieldName == "normals")
        {
            UInt32 normalsId;
            rh->getValue(normalsId);
            propFieldPFI.editIdStore()[Geometry::NormalsIndex] = normalsId;
        }
        else if(fieldName == "colors")
        {
            UInt32 colorsId;
            rh->getValue(colorsId);
            propFieldPFI.editIdStore()[Geometry::ColorsIndex] = colorsId;
        }
        else if(fieldName == "secondaryColors")
        {
            UInt32 secondaryColorsId;
            rh->getValue(secondaryColorsId);
            propFieldPFI.editIdStore()[Geometry::SecondaryColorsIndex] =
                secondaryColorsId;
        }
        else if(fieldName == "texCoords")
        {
            UInt32 texCoordsId;
            rh->getValue(texCoordsId);
            propFieldPFI.editIdStore()[Geometry::TexCoordsIndex] =
                texCoordsId;
        }
        else if(fieldName == "texCoords1")
        {
            UInt32 texCoordsId1;
            rh->getValue(texCoordsId1);
            propFieldPFI.editIdStore()[Geometry::TexCoords1Index] =
                texCoordsId1;
        }
        else if(fieldName == "texCoords2")
        {
            UInt32 texCoordsId2;
            rh->getValue(texCoordsId2);
            propFieldPFI.editIdStore()[Geometry::TexCoords2Index] =
                texCoordsId2;
        }
        else if(fieldName == "texCoords3")
        {
            UInt32 texCoordsId3;
            rh->getValue(texCoordsId3);
            propFieldPFI.editIdStore()[Geometry::TexCoords3Index] =
                texCoordsId3;
        }
        else if(fieldName == "texCoords4")
        {
            UInt32 texCoordsId4;
            rh->getValue(texCoordsId4);
            propFieldPFI.editIdStore()[Geometry::TexCoords4Index] =
                texCoordsId4;
        }
        else if(fieldName == "texCoords5")
        {
            UInt32 texCoordsId5;
            rh->getValue(texCoordsId5);
            propFieldPFI.editIdStore()[Geometry::TexCoords5Index] =
                texCoordsId5;
        }
        else if(fieldName == "texCoords6")
        {
            UInt32 texCoordsId6;
            rh->getValue(texCoordsId6);
            propFieldPFI.editIdStore()[Geometry::TexCoords6Index] =
                texCoordsId6;
        }
        else if(fieldName == "texCoords7")
        {
            UInt32 texCoordsId7;
            rh->getValue(texCoordsId7);
            propFieldPFI.editIdStore()[Geometry::TexCoords7Index] =
                texCoordsId7;
        }
        else if(fieldName == "pindices")
        {
            UInt32 maxValue;
            UInt32 propSize;
            UInt32 byteSize;

            _indicesPacked = true;

            gh.readPackedIntegralPropertyHeader(rh, maxValue,
                                                propSize, byteSize);

            if(root->getOptions().unpack16BitIndices())
            {
                if(maxValue > TypeTraits<UInt16>::getMax())
                {
                    GeoUInt32PropertyUnrecPtr ui32Indices =
                        GeoUInt32Property::create();
                    gh.readPackedIntegralProperty(rh, ui32Indices, maxValue,
                                                  propSize, byteSize        );

                    _indices16Bit = false;
                    _indices      = ui32Indices;
                }
                else
                {
                    GeoUInt16PropertyUnrecPtr ui16Indices =
                        GeoUInt16Property::create();
                    gh.readPackedIntegralProperty(rh, ui16Indices, maxValue,
                                                  propSize, byteSize        );

                    _indices16Bit = true;
                    _indices      = ui16Indices;
                }
            }
            else
            {
                GeoUInt32PropertyUnrecPtr ui32Indices =
                    GeoUInt32Property::create();
                gh.readPackedIntegralProperty(rh, ui32Indices, maxValue,
                                              propSize, byteSize        );

                _indices16Bit = false;
                _indices      = ui32Indices;
            }
        }
        else if(fieldName == "qpositions")
        {
            // Quantized positions are stored inside the geometry object, not
            // in the geo-property. They are always of type Pnt3f.
            GeoPnt3fPropertyUnrecPtr propPos    = GeoPnt3fProperty::create();
            UInt8                    resolution;
            Real32                   minValue;
            Real32                   maxValue;
            UInt32                   propSize;

            gh.readQuantizedVectorPropertyHeader(rh, resolution, minValue,
                                                 maxValue, propSize       );
            gh.readQuantizedVectorProperty(rh, propPos, fieldSize, resolution,
                                           minValue, maxValue, propSize       );

            geo->setProperty(propPos, Geometry::PositionsIndex);
        }
        else if(fieldName == "qnormals")
        {
            // Quantized normals are stored inside the geometry object, not
            // in the geo-property. They are always of type Vec3f.
            GeoVec3fPropertyUnrecPtr propNorm   = GeoVec3fProperty::create();
            UInt8                    resolution;
            Real32                   minValue;
            Real32                   maxValue;
            UInt32                   propSize;

            gh.readQuantizedVectorPropertyHeader(
                rh, resolution, minValue, maxValue, propSize);
            gh.readQuantizedVectorProperty(
                rh, propNorm, fieldSize, resolution,
                minValue, maxValue, propSize        );

            geo->setProperty(propNorm, Geometry::NormalsIndex);
        }
        else if(fieldName == "qtexCoords")
        {
            // Quantized texCoords are stored inside the geometry object, not
            // in the geo-property. They are always of type Vec2f.
            GeoVec2fPropertyUnrecPtr propTexCoords = GeoVec2fProperty::create();
            UInt8                    resolution;
            Real32                   minValue;
            Real32                   maxValue;
            UInt32                   propSize;

            gh.readQuantizedVectorPropertyHeader(
                rh, resolution, minValue, maxValue, propSize);
            gh.readQuantizedVectorProperty(
                rh, propTexCoords, fieldSize, resolution,
                minValue, maxValue, propSize             );

            geo->setProperty(propTexCoords, Geometry::NormalsIndex);
        }
        else
        {
            // 1.x Geometry has _sfVbo, it can be skipped

            readFieldContent(fieldName, fieldTypeName, fieldSize,
                             "'vbo'", ptrFieldIt                      );
        }
    }
}
/*! Reads a SFFieldContainerAttachmentPtrMap from the stream. It has the
    given \a fieldId in the container it belongs to and size \a fieldSize.

    \param[in] fieldId Id of the field in the container it belongs to.
    \param[in] fieldSize Size in byte of the field.

    \return Iterator that points to the PtrFieldInfo structure
    that was created for this field.
 */
OSBCommonElement::PtrFieldListIt
OSBCommonElement::readAttachmentMapField(
    const UInt32 fieldId, const UInt32 fieldSize)
{
    OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
            "fieldId: [%u]\n", fieldId));

    bool               hasBindingInfo = false;
    UInt32             ptrId;
    UInt32             numElements;
    OSBRootElement    *root           = editRoot();
    BinaryReadHandler *rh             = editRoot()->getReadHandler();

    root->editPtrFieldList().push_back(PtrFieldInfo(getContainer(), fieldId));

    PtrFieldInfo &pfi = root->editPtrFieldList().back();

    rh->getValue(numElements);

    // keep these ordered from highest to lowest version
    if(root->getHeaderVersion() >= OSGOSBHeaderVersion200)
    {
        if(root->getHeaderVersion() > OSGOSBHeaderVersion200)
        {
            FINFO(("OSBCommonElement::readAttachmentMapField: "
                   "Unknown header version, trying to read as latest.\n"));
        }
    
        hasBindingInfo = true;
    }
    else if(root->getHeaderVersion() >= OSGOSBHeaderVersion100)
    {
        // distinguish format with or without binding info
        if(fieldSize == (sizeof(UInt32) + numElements * sizeof(UInt32)))
        {
            hasBindingInfo = false;
        }
        else
        {
            hasBindingInfo = true;
        }
    }

    if(hasBindingInfo == true)
    {
        OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
                "reading [%u] attachments with binding info.\n", numElements));
    
        EditMapFieldHandlePtr sfMapField =
            boost::dynamic_pointer_cast<EditMapFieldHandle>(
                getContainer()->editField(fieldId));

        if(sfMapField == NULL || sfMapField->isValid() == false)
            return --(root->editPtrFieldList().end());

        pfi.setHandledField(sfMapField->loadFromBin(rh,
                                                    numElements,
                                                    hasBindingInfo,
                                                    pfi.editBindingStore(),
                                                    pfi.editIdStore     ()));
#if 0
        for(UInt32 i = 0; i < numElements; ++i)
        {
            rh->getValue(binding);
            rh->getValue(ptrId  );

            OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
                    "attachment [%u], binding [%u], id [%u].\n",
                    i, binding, ptrId));

            pfi.editBindingStore().push_back(binding);
            pfi.editIdStore     ().push_back(ptrId  );
        }
#endif
    }
    else
    {
        OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
                "reading [%u] attachments without binding info.\n", 
                numElements));
    
        for(UInt32 i = 0; i < numElements; ++i)
        {
            rh->getValue(ptrId);
            
            OSG_OSB_LOG(("OSBCommonElement::readAttachmentMapField: "
                    "attachment [%u], id [%u].\n", i, ptrId));
                    
            pfi.editBindingStore().push_back(0    );
            pfi.editIdStore     ().push_back(ptrId);
        }
    }

    return --(root->editPtrFieldList().end());
}
/*! Reads the contents of a field from the stream. It is intended to be used
    in conjunction with readFieldHeader and uses the information obtained
    by it (\a fieldName, \a fieldTypeName, \a fieldSize ).

    If a field is not to be read, but skipped instead, its name can be passed
    in the \a excludeFields argument. The string has the format:
    "'name1' 'name2' 'name3'", the spaces between the "'" are mandatory.

    \param[in] fieldName Name of the field.
    \param[in] fieldTypeName Type of the field.
    \param[in] fieldSize Size in bytes of the field.
    \param[in] excludeFields
    \param[out] ptrFieldIt Iterator that points to the PtrFieldInfo structure
    that was created, if this is a "pointer field" - only valid if true is
    returned.

    \return True, if the field is a "pointer field", i.e. a field holding
    pointers to other FieldContainers, false otherwise.
 */
bool
OSBCommonElement::readFieldContent(
    const std::string    &fieldName,
    const std::string    &fieldTypeName,
    const UInt32          fieldSize,
    const std::string    &excludeFields,
          PtrFieldListIt &ptrFieldIt    )
{
    OSG_OSB_LOG(("OSBCommonElement::readFieldContent: [%s] [%s] [%u]\n",
            fieldName.c_str(), fieldTypeName.c_str(), fieldSize));

    BinaryReadHandler    *rh         = editRoot()->getReadHandler();
    bool                  isPtrField = false;
    FieldDescriptionBase *fieldDesc  =
        getContainer()->getFieldDescription(fieldName.c_str());

    if((!excludeFields.empty()                                        ) &&
       (excludeFields.find("'" + fieldName + "'") != std::string::npos)   )
    {
        OSG_OSB_LOG(("OSBCommonElement::readFieldContent: "
                "Skipping excluded field [%s] [%s]\n",
                fieldName.c_str(), fieldTypeName.c_str()));

        rh->skip(fieldSize);
        return false;
    }

    if(fieldDesc == 0)
    {
        DynFieldContainerInterface *pIf = 
            dynamic_cast<DynFieldContainerInterface *>(getContainer());

        if(pIf != NULL)
        {
            pIf->addField(fieldTypeName.c_str(), fieldName.c_str());

            fieldDesc = getContainer()->getFieldDescription(fieldName.c_str());
        }
    }

    if(fieldDesc == 0)
    {
        FWARNING(("OSBCommonElement::readFieldContent: "
                  "Skipping unknown field [%s] [%s].\n",
                  fieldName.c_str(), fieldTypeName.c_str()));

        rh->skip(fieldSize);
        return false;
    }

    const FieldType &fieldType  = fieldDesc->getFieldType();
    UInt32           fieldId    = fieldDesc->getFieldId  ();
    BitVector        fieldMask  = fieldDesc->getFieldMask();

    if(fieldType.getContentType().isDerivedFrom(
        FieldTraits<FieldContainer *>::getMapType()) == true)
    {
        ptrFieldIt = readAttachmentMapField(fieldId, fieldSize);
        isPtrField = true;
    }
    else if(fieldType.getContentType().isDerivedFrom(
        FieldTraits<FieldContainer *>::getType()) == true)
    {
        if(fieldType.getClass() == FieldType::ParentPtrField)
        {
            rh->skip(fieldSize);
            isPtrField = false;
        }
        else
        {
            if(fieldType.getCardinality() == FieldType::SingleField)
            {
                ptrFieldIt = readPtrSingleField(fieldId);
                isPtrField = true;
            }
            else if(fieldType.getCardinality() == FieldType::MultiField)
            {
                ptrFieldIt = readPtrMultiField(fieldId, fieldSize);
                isPtrField = true;
            }
        }
    }
    else
    {
        getContainer()->copyFromBin(*rh, fieldMask);
        isPtrField = false;
    }

    return isPtrField;
}