Procházet zdrojové kódy

improved binary reading

vpenades před 2 roky
rodič
revize
6fc681f6a0
1 změnil soubory, kde provedl 41 přidání a 26 odebrání
  1. 41 26
      src/SharpGLTF.Core/Schema2/Serialization.Binary.cs

+ 41 - 26
src/SharpGLTF.Core/Schema2/Serialization.Binary.cs

@@ -45,7 +45,6 @@ namespace SharpGLTF.Schema2
                 return false;
             }
         }
-        
 
         internal static bool _Identify(Stream stream)
         {
@@ -92,21 +91,31 @@ namespace SharpGLTF.Schema2
 
             using (var binaryReader = new BinaryReader(stream, Encoding.ASCII))
             {
-                var bodyLen = _ReadBinaryHeader(binaryReader);
-
                 // body length can actually be smaller than the stream length,
                 // in which case, the data afterwards is considered "extra data".
+
+                var remaining = _ReadBinaryHeader(binaryReader);
+                
                 void _checkCanRead(long count)
                 {
-                    bool canRead = (bodyLen - stream.Position - count) >= 0;
-                    if (!canRead) throw new Validation.SchemaException(null, "unexpected End of GLB block");
+                    if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
+                    if (count > int.MaxValue) throw new Validation.SchemaException(null, $"{count} bytes to read exceeds maximum capacity.");
+                    if (remaining < count) throw new Validation.SchemaException(null, "unexpected End of GLB block.");
+                    remaining -= count;
                 }                
 
                 var chunks = new Dictionary<uint, Byte[]>();
 
-                _checkCanRead(4);
-                while (binaryReader._TryReadUInt32(out var chunkLength)) // keep reading until EndOfFile
+                while (remaining >= 4)
                 {
+                    remaining -= 4;
+                    if (!binaryReader._TryReadUInt32(out var chunkLength)) break;
+
+                    if (chunkLength  == 0)
+                    {
+                        throw new Validation.SchemaException(null, $"The chunk must non zero size.");
+                    }                    
+
                     if ((chunkLength & 3) != 0)
                     {
                         throw new Validation.SchemaException(null, $"The chunk must be padded to 4 bytes: {chunkLength}");
@@ -115,16 +124,25 @@ namespace SharpGLTF.Schema2
                     _checkCanRead(4);
                     uint chunkId = binaryReader.ReadUInt32();
 
-                    if (chunks.ContainsKey(chunkId)) throw new Validation.SchemaException(null, $"Duplicated chunk found {chunkId}");
-
+                    if (chunks.ContainsKey(chunkId))
+                    {
+                        throw new Validation.SchemaException(null, $"Duplicated chunk found {chunkId}");
+                    }
+                    
                     _checkCanRead(chunkLength);
                     var data = binaryReader.ReadBytes((int)chunkLength);
 
                     chunks[chunkId] = data;
                 }
 
-                if (!chunks.ContainsKey(CHUNKJSON)) throw new Validation.SchemaException(null, "JSON Chunk chunk not found");
+                // finish reading remainder
+                // if (remaining > 0) { binaryReader.ReadBytes((int)remaining); }
+
+                if (!chunks.ContainsKey(CHUNKJSON)) throw new Validation.SchemaException(null, "JSON Chunk chunk not found");                
+
+                // warnings
                 // if (!chunks.ContainsKey(CHUNKBIN)) throw new Validation.SchemaException(null, "BIN Chunk chunk not found");
+                // if (remaining > 0) throw new Validation.SchemaException(null, "Extra bytes found");
 
                 return chunks;
             }
@@ -140,30 +158,27 @@ namespace SharpGLTF.Schema2
             uint version = binaryReader.ReadUInt32();
             if (version != GLTFVERSION2) throw new Validation.SchemaException(null, $"Unknown version number: {version}");
 
-            uint bodyLength = binaryReader.ReadUInt32(); // length if the actual glb body
-
-            uint? fileLength = null;
+            uint bodyLength = binaryReader.ReadUInt32(); // length of the actual glb body            
 
-            try
+            try // check stream is large enough
             {
-                fileLength = (uint)binaryReader.BaseStream.Length;                
+                if (binaryReader.BaseStream.CanSeek)
+                {
+                    var fileLength = (uint)binaryReader.BaseStream.Length;
+
+                    if (bodyLength > fileLength)
+                    {
+                        throw new Validation.SchemaException(null, $"The specified length of the file ({bodyLength}) is not equal to the actual length of the file ({fileLength}).");
+                    }
+                }
             }
             catch (System.NotSupportedException)
             {
                 // Some streams like Android assets don't support getting the length
                 // https://github.com/vpenades/SharpGLTF/issues/178
-            }
-
-            // actual block can be larger than the expected block size, in which case
-            // there might be extra data after the binary file.
-            // gltfvalidator only considers this as a warning.
-
-            if (fileLength.HasValue && bodyLength > fileLength.Value)
-            {
-                throw new Validation.SchemaException(null, $"The specified length of the file ({bodyLength}) is not equal to the actual length of the file ({fileLength}).");
-            }
+            }            
 
-            return bodyLength;
+            return bodyLength - 12;
         }
 
         #endregion