/// <summary> /// Reads a single node. /// </summary> /// <remarks> /// This won't read the file header or footer, and as such will fail if the stream is a full FBX file /// </remarks> /// <returns>The node</returns> /// <exception cref="FbxException">The FBX data was malformed /// for the reader's error level</exception> public FbxNode ReadNode(FbxDocument document) { var endOffset = document.Version >= FbxVersion.v7_5 ? stream.ReadInt64() : stream.ReadInt32(); var numProperties = document.Version >= FbxVersion.v7_5 ? stream.ReadInt64() : stream.ReadInt32(); var propertyListLen = document.Version >= FbxVersion.v7_5 ? stream.ReadInt64() : stream.ReadInt32(); var nameLen = stream.ReadByte(); var name = nameLen == 0 ? "" : Encoding.ASCII.GetString(stream.ReadBytes(nameLen)); if (endOffset == 0) { // The end offset should only be 0 in a null node if (errorLevel >= ErrorLevel.Checked && (numProperties != 0 || propertyListLen != 0 || !string.IsNullOrEmpty(name))) { throw new FbxException(stream.BaseStream.Position, "Invalid node; expected NULL record"); } return(null); } var node = new FbxNode { Name = name }; var propertyEnd = stream.BaseStream.Position + propertyListLen; // Read properties for (int i = 0; i < numProperties; i++) { node.AddProperty(ReadProperty()); } if (errorLevel >= ErrorLevel.Checked && stream.BaseStream.Position != propertyEnd) { throw new FbxException(stream.BaseStream.Position, "Too many bytes in property list, end point is " + propertyEnd); } // Read nested nodes var listLen = endOffset - stream.BaseStream.Position; if (errorLevel >= ErrorLevel.Checked && listLen < 0) { throw new FbxException(stream.BaseStream.Position, "Node has invalid end point"); } if (listLen > 0) { FbxNode nested; do { nested = ReadNode(document); node.AddNode(nested); } while (nested != null); if (errorLevel >= ErrorLevel.Checked && stream.BaseStream.Position != endOffset) { throw new FbxException(stream.BaseStream.Position, "Too many bytes in node, end point is " + endOffset); } } return(node); }
/// <summary> /// Reads the next node from the stream /// </summary> /// <returns>The read node, or <c>null</c></returns> public FbxNode ReadNode() { var first = ReadToken(); if (!(first is Identifier id)) { if (first is EndOfStream) { return(null); } throw new FbxException(_fbxAsciiFileInfo, "Unexpected '" + first + "', expected an identifier"); } var node = new FbxNode { Name = id.Value }; // Read properties object token = ReadToken(); bool expectComma = false; while (!'{'.Equals(token) && !(token is Identifier) && !'}'.Equals(token)) { if (expectComma) { if (!','.Equals(token)) { throw new FbxException(_fbxAsciiFileInfo, "Unexpected '" + token + "', expected a ','"); } expectComma = false; token = ReadToken(); continue; } if (token is char c) { switch (c) { case '*': token = ReadArray(); break; case '}': case ':': case ',': throw new FbxException(_fbxAsciiFileInfo, "Unexpected '" + c + "' in property list"); } } node.AddProperty(new FbxValue(token)); expectComma = true; // The final comma before the open brace isn't required token = ReadToken(); } // TODO: Merge property list into an array as necessary // Now we're either at an open brace, close brace or a new node if (token is Identifier || '}'.Equals(token)) { prevToken = token; return(node); } // The while loop can't end unless we're at an open brace, so we can continue right on object endBrace = ReadToken(); while (!'}'.Equals(endBrace)) { prevToken = endBrace; // If it's not an end brace, the next node will need it node.AddNode(ReadNode()); endBrace = ReadToken(); } if (node.Nodes.Length < 1) // If there's an open brace, we want that to be preserved { node.AddNode(null); } return(node); }
/// <summary> /// Reads the next node from the stream /// </summary> /// <returns>The read node, or <c>null</c></returns> public FbxNode ReadNode() { var first = ReadToken(); if (!(first is IdentifierToken id)) { if (first is Token tok && tok.TokenType == TokenType.EndOfStream) { return(null); } throw new FbxException(_fbxAsciiFileInfo, "Unexpected '" + first + "', expected an identifier"); } var node = new FbxNode(id); // Read properties Token token = ReadToken(); bool expectComma = false; while (token.TokenType != TokenType.OpenBrace && token.TokenType != TokenType.Identifier && token.TokenType != TokenType.CloseBrace) { if (expectComma) { if (token.TokenType != TokenType.Comma) { throw new FbxException(_fbxAsciiFileInfo, "Unexpected '" + token + "', expected a ','"); } expectComma = false; token = ReadToken(); continue; } if (token.TokenType == TokenType.Asterix) { token = ReadArray(); } else if (token.TokenType == TokenType.CloseBrace || token.TokenType == TokenType.Comma) { throw new FbxException(_fbxAsciiFileInfo, "Unexpected '" + token.TokenType + "' in property list"); } node.AddProperty(token); expectComma = true; // The final comma before the open brace isn't required token = ReadToken(); } // TODO: Merge property list into an array as necessary // Now we're either at an open brace, close brace or a new node if (token.TokenType == TokenType.Identifier || token.TokenType == TokenType.CloseBrace) { _tokenStack.Push(token); return(node); } // The while loop can't end unless we're at an open brace, so we can continue right on Token endBrace = ReadToken(); while (endBrace.TokenType != TokenType.CloseBrace) { _tokenStack.Push(endBrace); node.AddNode(ReadNode()); endBrace = ReadToken(); } if (node.Nodes.Length < 1) // If there's an open brace, we want that to be preserved { node.AddNode(null); } return(node); }