Beispiel #1
0
        /// <summary>
        /// Writes an FBX document to the stream
        /// </summary>
        /// <param name="document"></param>
        /// <exception cref="ArgumentNullException"/>
        /// <remarks>
        /// ASCII FBX files have no header or footer, so you can call this multiple times
        /// </remarks>
        public void Write(FbxDocument document)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            var sb = new StringBuilder();

            // Write version header (a comment, but required for many importers)
            var vMajor = (int)document.Version / 1000;
            var vMinor = ((int)document.Version % 1000) / 100;
            var vRev   = ((int)document.Version % 100) / 10;

            sb.Append($"; FBX {vMajor}.{vMinor}.{vRev} project file\n\n");

            nodePath.Clear();
            foreach (var n in document.Nodes)
            {
                if (n == null)
                {
                    continue;
                }
                BuildString(n, sb, document.Version >= FbxVersion.v7_1);
                sb.Append('\n');
            }

            var b = Encoding.ASCII.GetBytes(sb.ToString());

            stream.Write(b, 0, b.Length);
        }
Beispiel #2
0
		/// <summary>
		/// Writes an FBX document
		/// </summary>
		/// <param name="document">The top level document node</param>
		/// <param name="path"></param>
		public static void WriteAscii(FbxDocument document, string path)
		{
			if (path == null)
				throw new ArgumentNullException(nameof(path));
			using (var stream = new FileStream(path, FileMode.Create))
			{
				var writer = new FbxAsciiWriter(stream);
				writer.Write(document);
			}
		}
Beispiel #3
0
        /// <summary>
        /// Reads a full document from the stream
        /// </summary>
        /// <returns>The complete document object</returns>
        public FbxDocument Read()
        {
            CultureInfo cultureInfoOriginal = Thread.CurrentThread.CurrentCulture;

            try
            {
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                var ret = new FbxDocument();

                // Read version string
                const string versionString = @"; FBX (\d)\.(\d)\.(\d) project file";
                char         c;
                while (char.IsWhiteSpace(c = ReadChar()) && !endStream)
                {
                }                                                                           // Skip whitespace
                bool hasVersionString = false;
                if (c == ';')
                {
                    var sb = new StringBuilder();
                    do
                    {
                        sb.Append(c);
                    } while (!IsLineEnd(c = ReadChar()) && !endStream);

                    var match = Regex.Match(sb.ToString(), versionString);
                    hasVersionString = match.Success;
                    if (hasVersionString)
                    {
                        ret.Version = (FbxVersion)(
                            int.Parse(match.Groups[1].Value) * 1000 +
                            int.Parse(match.Groups[2].Value) * 100 +
                            int.Parse(match.Groups[3].Value) * 10
                            );
                    }
                }
                if (!hasVersionString && errorLevel >= ErrorLevel.Strict)
                {
                    throw new FbxException(line, column, "Invalid version string; first line must match \"" + versionString + "\"");
                }

                FbxNode node;
                while ((node = ReadNode()) != null)
                {
                    ret.Nodes.Add(node);
                }

                return(ret);
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = cultureInfoOriginal;
            }
        }
Beispiel #4
0
 /// <summary>
 /// Writes an FBX document
 /// </summary>
 /// <param name="document">The top level document node</param>
 /// <param name="path"></param>
 public static void WriteAscii(FbxDocument document, string path)
 {
     if (path == null)
     {
         throw new ArgumentNullException(nameof(path));
     }
     using (var stream = new FileStream(path, FileMode.Create))
     {
         var writer = new FbxAsciiWriter(stream);
         writer.Write(document);
     }
 }
Beispiel #5
0
        public FbxDocument Read()
        {
            // Read header
            bool validHeader = ReadHeader(binStream.BaseStream);

            if (errorLevel >= ErrorLevel.Strict && !validHeader)
            {
                throw new FbxException(binStream.BaseStream.Position,
                                       "Invalid header string");
            }

            versionNumber = binStream.ReadInt32();
            var document = new FbxDocument {
                Version = (FbxVersion)versionNumber
            };

            // Read nodes
            FbxNode nested;

            do
            {
                nested = ReadNode();
                if (nested != null)
                {
                    document.Nodes.Add(nested);
                }
            } while (nested != null);

            // Read footer code
            var footerCode = new byte[footerCodeSize];

            binStream.BaseStream.Read(footerCode, 0, footerCode.Length);
            if (errorLevel >= ErrorLevel.Strict)
            {
                var validCode = GenerateFooterCode(document);
                if (!CheckEqual(footerCode, validCode))
                {
                    throw new FbxException(binStream.BaseStream.Position - footerCodeSize,
                                           "Incorrect footer code");
                }
            }

            // Read footer extension
            var validFooterExtension = CheckFooter(binStream, document.Version);

            if (errorLevel >= ErrorLevel.Strict && !validFooterExtension)
            {
                throw new FbxException(binStream.BaseStream.Position, "Invalid footer");
            }
            return(document);
        }
Beispiel #6
0
 /// <summary>
 /// Writes an FBX file to the output
 /// </summary>
 /// <param name="document"></param>
 public void Write(FbxDocument document)
 {
     stream.BaseStream.Position = 0;
     WriteHeader(stream.BaseStream);
     stream.Write((int)document.Version);
     // TODO: Do we write a top level node or not? Maybe check the version?
     nodePath.Clear();
     foreach (var node in document.Nodes)
     {
         WriteNode(node);
     }
     WriteNode(null);
     stream.Write(GenerateFooterCode(document));
     WriteFooter(stream, (int)document.Version);
     output.Write(memory.GetBuffer(), 0, (int)memory.Position);
 }
Beispiel #7
0
        /// <summary>
        /// Writes an FBX document
        /// </summary>
        /// <param name="document">The top level document node</param>
        /// <param name="path"></param>
        public static void WriteAscii(FbxDocument document, Stream stream)
        {
            CultureInfo cultureInfoOriginal = Thread.CurrentThread.CurrentCulture;

            try
            {
                Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

                var writer = new FbxAsciiWriter(stream);
                writer.Write(document);
            }
            finally
            {
                Thread.CurrentThread.CurrentCulture = cultureInfoOriginal;
            }
        }
Beispiel #8
0
		/// <summary>
		/// Reads an FBX document from the stream
		/// </summary>
		/// <returns>The top-level node</returns>
		/// <exception cref="FbxException">The FBX data was malformed
		/// for the reader's error level</exception>
		public FbxDocument Read()
		{
			// Read header
			bool validHeader = ReadHeader(stream.BaseStream);
			if (errorLevel >= ErrorLevel.Strict && !validHeader)
				throw new FbxException(stream.BaseStream.Position,
					"Invalid header string");
			var document = new FbxDocument {Version = (FbxVersion) stream.ReadInt32()};

			// Read nodes
			var dataPos = stream.BaseStream.Position;
			FbxNode nested;
			do
			{
				nested = ReadNode();
				if(nested != null)
					document.Nodes.Add(nested);
			} while (nested != null);

			// Read footer code
			var footerCode = new byte[footerCodeSize];
			stream.BaseStream.Read(footerCode, 0, footerCode.Length);
			if (errorLevel >= ErrorLevel.Strict)
			{
				var validCode = GenerateFooterCode(document);
				if(!CheckEqual(footerCode, validCode))
					throw new FbxException(stream.BaseStream.Position - footerCodeSize,
						"Incorrect footer code");
			}

			// Read footer extension
			dataPos = stream.BaseStream.Position;
			var validFooterExtension = CheckFooter(stream, document.Version);
			if(errorLevel >= ErrorLevel.Strict && !validFooterExtension)
				throw new FbxException(dataPos, "Invalid footer");
			return document;
		}
Beispiel #9
0
        // Writes a single document to the buffer
        void WriteNode(FbxDocument document, FbxNode node)
        {
            if (node == null)
            {
                var data = document.Version >= FbxVersion.v7_5 ? nullData7500 : nullData;
                stream.BaseStream.Write(data, 0, data.Length);
            }
            else
            {
                nodePath.Push(node.Name ?? "");
                var name = string.IsNullOrEmpty(node.Name) ? null : Encoding.ASCII.GetBytes(node.Name);
                if (name != null && name.Length > byte.MaxValue)
                {
                    throw new FbxException(stream.BaseStream.Position, "Node name is too long");
                }

                // Header
                var  endOffsetPos = stream.BaseStream.Position;
                long propertyLengthPos;
                if (document.Version >= FbxVersion.v7_5)
                {
                    stream.Write((long)0);                     // End offset placeholder
                    stream.Write((long)node.Properties.Count);
                    propertyLengthPos = stream.BaseStream.Position;
                    stream.Write((long)0);                     // Property length placeholder
                }
                else
                {
                    stream.Write(0);                     // End offset placeholder
                    stream.Write(node.Properties.Count);
                    propertyLengthPos = stream.BaseStream.Position;
                    stream.Write(0);                     // Property length placeholder
                }

                stream.Write((byte)(name?.Length ?? 0));
                if (name != null)
                {
                    stream.Write(name);
                }

                // Write properties and length
                var propertyBegin = stream.BaseStream.Position;
                for (int i = 0; i < node.Properties.Count; i++)
                {
                    WriteProperty(node.Properties[i], i);
                }
                var propertyEnd = stream.BaseStream.Position;
                stream.BaseStream.Position = propertyLengthPos;

                if (document.Version >= FbxVersion.v7_5)
                {
                    stream.Write((long)(propertyEnd - propertyBegin));
                }
                else
                {
                    stream.Write((int)(propertyEnd - propertyBegin));
                }

                stream.BaseStream.Position = propertyEnd;

                // Write child nodes
                if (node.Nodes.Count > 0)
                {
                    foreach (var n in node.Nodes)
                    {
                        if (n == null)
                        {
                            continue;
                        }

                        WriteNode(document, n);
                    }
                    WriteNode(document, null);
                }

                // Write end offset
                var dataEnd = stream.BaseStream.Position;
                stream.BaseStream.Position = endOffsetPos;
                if (document.Version >= FbxVersion.v7_5)
                {
                    stream.Write((long)dataEnd);
                }
                else
                {
                    stream.Write((int)dataEnd);
                }

                stream.BaseStream.Position = dataEnd;

                nodePath.Pop();
            }
        }
Beispiel #10
0
		/// <summary>
		/// Reads a full document from the stream
		/// </summary>
		/// <returns>The complete document object</returns>
		public FbxDocument Read()
		{
			var ret = new FbxDocument();

			// Read version string
			const string versionString = @"; FBX (\d)\.(\d)\.(\d) project file";
            char c;
			while(char.IsWhiteSpace(c = ReadChar()) && !endStream) { } // Skip whitespace
			bool hasVersionString = false;
			if (c == ';')
			{
				var sb = new StringBuilder();
				do
				{
					sb.Append(c);
				} while (!IsLineEnd(c = ReadChar()) && !endStream);
				var match = Regex.Match(sb.ToString(), versionString);
				hasVersionString = match.Success;
				if(hasVersionString)
					ret.Version = (FbxVersion)(
						int.Parse(match.Groups[1].Value)*1000 +
						int.Parse(match.Groups[2].Value)*100 +
						int.Parse(match.Groups[3].Value)*10
					);
			}
			if(!hasVersionString && errorLevel >= ErrorLevel.Strict)
				throw new FbxException(line, column,
					"Invalid version string; first line must match \"" + versionString + "\"");
			FbxNode node;
			while((node = ReadNode()) != null)
				ret.Nodes.Add(node);
			return ret;
		}
Beispiel #11
0
        /// <summary>
        /// Writes an FBX document
        /// </summary>
        /// <param name="document">The top level document node</param>
        /// <param name="stream">Output stream</param>
        public static void WriteBinary(FbxDocument document, Stream stream)
        {
            var writer = new FbxBinaryWriter(stream);

            writer.Write(document);
        }
Beispiel #12
0
		/// <summary>
		/// Writes an FBX file to the output
		/// </summary>
		/// <param name="document"></param>
		public void Write(FbxDocument document)
		{
			stream.BaseStream.Position = 0;
			WriteHeader(stream.BaseStream);
			stream.Write((int)document.Version);
			// TODO: Do we write a top level node or not? Maybe check the version?
			nodePath.Clear();
			foreach (var node in document.Nodes)
				WriteNode(node);
			WriteNode(null);
			stream.Write(GenerateFooterCode(document));
			WriteFooter(stream, (int)document.Version);
			output.Write(memory.GetBuffer(), 0, (int)memory.Position);
		}
Beispiel #13
0
        /// <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.Properties.Add(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.Nodes.Add(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);
        }
Beispiel #14
0
		/// <summary>
		/// Writes an FBX document to the stream
		/// </summary>
		/// <param name="document"></param>
		/// <remarks>
		/// ASCII FBX files have no header or footer, so you can call this multiple times
		/// </remarks>
		public void Write(FbxDocument document)
		{
			if(document == null)
				throw new ArgumentNullException(nameof(document));
			var sb = new StringBuilder();

			// Write version header (a comment, but required for many importers)
			var vMajor = (int)document.Version/1000;
			var vMinor = ((int) document.Version%1000)/100;
			var vRev = ((int) document.Version%100)/10;
			sb.Append($"; FBX {vMajor}.{vMinor}.{vRev} project file\n\n");

			nodePath.Clear();
			foreach (var n in document.Nodes)
			{
				if (n == null)
					continue;
				BuildString(n, sb, document.Version >= FbxVersion.v7_1);
				sb.Append('\n');
			}
			var b = Encoding.ASCII.GetBytes(sb.ToString());
			stream.Write(b, 0, b.Length);
		}