Skip to content

Commit

Permalink
Added some defensive checks when reading/writing to IO file stream. I…
Browse files Browse the repository at this point in the history
…f a format (like OBJ) is distributed across multiple files, make a note in the Import/Convert from stream methods that a custiom IOSystem only works from Import/Convert from file.

Added a unit test to verify this. Refreshed docs
  • Loading branch information
Starnick committed Oct 5, 2018
1 parent 44096d8 commit c6cf162
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 12 deletions.
36 changes: 36 additions & 0 deletions AssimpNet.Test/IOSystem_TestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,41 @@ public void TestIOSystemError()
importer.ImportFile(fileName, PostProcessSteps.None);
});
}

[Test]
public void TestIOSystem_ImportObj()
{
String dir = Path.Combine(TestHelper.RootPath, "TestFiles");
LogStream.IsVerboseLoggingEnabled = true;
ConsoleLogStream log = new ConsoleLogStream();
log.Attach();

using(AssimpContext importer = new AssimpContext())
{
FileIOSystem iOSystem = new FileIOSystem(dir);
importer.SetIOSystem(iOSystem);

//Using stream does not use the IO system...
using(Stream fs = File.OpenRead(Path.Combine(dir, "sphere.obj")))
{
Scene scene = importer.ImportFileFromStream(fs, "obj");
Assert.IsTrue(scene != null);
Assert.IsTrue(scene.HasMeshes);
Assert.IsTrue(scene.HasMaterials);

//No material file, so the mesh will always use the default material
Assert.IsTrue(scene.Materials[scene.Meshes[0].MaterialIndex].Name == "DefaultMaterial");
}

//Using custom IO system requires us to pass in the file name, assimp will ask the io system to get a stream
Scene scene2 = importer.ImportFile("sphere.obj");
Assert.IsTrue(scene2 != null);
Assert.IsTrue(scene2.HasMeshes);
Assert.IsTrue(scene2.HasMaterials);

//Should have found a material with the name "SphereMaterial" in the mtl file
Assert.IsTrue(scene2.Materials[scene2.Meshes[0].MaterialIndex].Name == "SphereMaterial");
}
}
}
}
2 changes: 1 addition & 1 deletion AssimpNet.Test/TestFiles/sphere.mtl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Blender MTL File: 'sphere.blend'
# Material Count: 1
newmtl
newmtl SphereMaterial
Ns 0
Ka 0.000000 0.000000 0.000000
Kd 0.8 0.8 0.8
Expand Down
5 changes: 3 additions & 2 deletions AssimpNet.shfbproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<RootNamespace>Documentation</RootNamespace>
<Name>Documentation</Name>
<!-- SHFB properties -->
<OutputPath>C:\Users\Nicholas\Documents\Visual Studio 2017\Projects\AssimpNet-Next\Docs\</OutputPath>
<OutputPath>C:\Users\Nicholas\Documents\Visual Studio 2017\Projects\AssimpNet\Docs\</OutputPath>
<HtmlHelpName>AssimpNet Documentation %28October 2018%29</HtmlHelpName>
<Language>en-US</Language>
<PresentationStyle>VS2013</PresentationStyle>
Expand All @@ -25,7 +25,8 @@
</VendorName>
<DocumentationSources>
<DocumentationSource sourceFile="AssimpNet\bin\Release\netstandard1.3\AssimpNet.dll" />
<DocumentationSource sourceFile="AssimpNet\bin\Release\netstandard1.3\AssimpNet.xml" /></DocumentationSources>
<DocumentationSource sourceFile="AssimpNet\bin\Release\netstandard1.3\AssimpNet.xml" />
</DocumentationSources>
<HelpTitle>AssimpNet Documentation %28October 2018%29</HelpTitle>
<CopyrightText>Copyright &amp;#169%3b 2012-2018 AssimpNet - Nicholas Woodfield. All rights reserved.</CopyrightText>
<NamespaceSummaries>
Expand Down
31 changes: 23 additions & 8 deletions AssimpNet/AssimpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ public AssimpContext()
/// <summary>
/// Imports a model from the stream without running any post-process steps. The importer sets configurations
/// and loads the model into managed memory, releasing the unmanaged memory used by Assimp. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ImportFile" family of functions.
/// </summary>
/// <param name="stream">Stream to read from</param>
/// <param name="formatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand All @@ -192,8 +194,9 @@ public Scene ImportFileFromStream(Stream stream, String formatHint = null)
}

/// <summary>
/// Imports a model from the stream. The importer sets configurations
/// and loads the model into managed memory, releasing the unmanaged memory used by Assimp. It is up to the caller to dispose of the stream.
/// Imports a model from the stream. The importer sets configurations and loads the model into managed memory, releasing the unmanaged memory
/// used by Assimp. It is up to the caller to dispose of the stream. If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ImportFile" family of functions.
/// </summary>
/// <param name="stream">Stream to read from</param>
/// <param name="postProcessFlags">Post processing flags, if any</param>
Expand Down Expand Up @@ -617,7 +620,9 @@ public ExportDataBlob ConvertFromFileToBlob(String inputFilename, PostProcessSte
#region Stream to File

/// <summary>
/// Converts the model contained in the stream to the specified format and save it to a file.
/// Converts the model contained in the stream to the specified format and save it to a file. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ConvertFromFileToFile" family of functions.
/// </summary>
/// <param name="inputStream">Stream to read from</param>
/// <param name="importFormatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand All @@ -633,7 +638,9 @@ public bool ConvertFromStreamToFile(Stream inputStream, String importFormatHint,
}

/// <summary>
/// Converts the model contained in the stream to the specified format and save it to a file.
/// Converts the model contained in the stream to the specified format and save it to a file. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ConvertFromFileToFile" family of functions.
/// </summary>
/// <param name="inputStream">Stream to read from</param>
/// <param name="importFormatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand All @@ -650,7 +657,9 @@ public bool ConvertFromStreamToFile(Stream inputStream, String importFormatHint,
}

/// <summary>
/// Converts the model contained in the stream to the specified format and save it to a file.
/// Converts the model contained in the stream to the specified format and save it to a file. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ConvertFromFileToFile" family of functions.
/// </summary>
/// <param name="inputStream">Stream to read from</param>
/// <param name="importFormatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand Down Expand Up @@ -705,7 +714,9 @@ public bool ConvertFromStreamToFile(Stream inputStream, String importFormatHint,
#region Stream to Blob

/// <summary>
/// Converts the model contained in the stream to the specified format and save it to a data blob.
/// Converts the model contained in the stream to the specified format and save it to a data blob. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ConvertFromFileToBlob" family of functions.
/// </summary>
/// <param name="inputStream">Stream to read from</param>
/// <param name="importFormatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand All @@ -720,7 +731,9 @@ public ExportDataBlob ConvertFromStreamToBlob(Stream inputStream, String importF
}

/// <summary>
/// Converts the model contained in the stream to the specified format and save it to a data blob.
/// Converts the model contained in the stream to the specified format and save it to a data blob. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ConvertFromFileToBlob" family of functions.
/// </summary>
/// <param name="inputStream">Stream to read from</param>
/// <param name="importFormatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand All @@ -736,7 +749,9 @@ public ExportDataBlob ConvertFromStreamToBlob(Stream inputStream, String importF
}

/// <summary>
/// Converts the model contained in the stream to the specified format and save it to a data blob.
/// Converts the model contained in the stream to the specified format and save it to a data blob. It is up to the caller to dispose of the stream.
/// If the format is distributed across multiple files/streams, set a custom <see cref="IOSystem"/>
/// and use the "ConvertFromFileToBlob" family of functions.
/// </summary>
/// <param name="inputStream">Stream to read from</param>
/// <param name="importFormatHint">Optional format extension to serve as a hint to Assimp to choose which importer to use. If null or empty, the system will
Expand Down
6 changes: 6 additions & 0 deletions AssimpNet/FileIOSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ public override long Write(byte[] dataToWrite, long count)
if(m_fileStream == null || !m_fileStream.CanWrite)
throw new IOException("Stream is not writable.");

if(m_fileStream.Position >= m_fileStream.Length)
return 0;

m_fileStream.Write(dataToWrite, (int) m_fileStream.Position, (int) count);

return count;
Expand All @@ -187,6 +190,9 @@ public override long Read(byte[] dataRead, long count)
if(m_fileStream == null || !m_fileStream.CanRead)
throw new IOException("Stream is not readable.");

if(m_fileStream.Position >= m_fileStream.Length)
return 0;

m_fileStream.Read(dataRead, (int) m_fileStream.Position, (int) count);

return count;
Expand Down
7 changes: 6 additions & 1 deletion AssimpNet/IOStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ private UIntPtr OnAiFileWriteProc(IntPtr file, IntPtr dataToWrite, UIntPtr sizeO
long longNum = (long) numElements.ToUInt64();
long count = longSize * longNum;

if(count == 0)
return UIntPtr.Zero;

byte[] byteBuffer = GetByteBuffer(longSize, longNum);
MemoryHelper.Read<byte>(dataToWrite, byteBuffer, 0, (int) count);

Expand Down Expand Up @@ -258,7 +261,9 @@ private UIntPtr OnAiFileReadProc(IntPtr file, IntPtr dataRead, UIntPtr sizeOfEle
try
{
actualCount = Read(byteBuffer, count);
MemoryHelper.Write<byte>(dataRead, byteBuffer, 0, (int) actualCount);

if(actualCount > 0)
MemoryHelper.Write<byte>(dataRead, byteBuffer, 0, (int) actualCount);
}
catch(Exception) { /*Assimp will report an IO error*/ }

Expand Down
Binary file modified Docs/AssimpNet Documentation (October 2018).chm
Binary file not shown.

0 comments on commit c6cf162

Please sign in to comment.