Skip to content

Commit

Permalink
Merge branch 'hotfix/StlReader_opens_binary_stl_with_ascii_reader'
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Spatz committed Nov 11, 2014
2 parents a1d672f + 70810d0 commit a91bee9
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 22 deletions.
Binary file not shown.
Binary file not shown.
20 changes: 20 additions & 0 deletions GenericStl.Tests/BinaryStlWriterTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
using ApprovalTests;
using ApprovalTests.Reporters;
using GenericStl.Tests.TestDataStructures;
Expand Down Expand Up @@ -37,5 +39,23 @@ public void Write_WithBlock_ReturnsExpectedResult()
var result = ObjectUnderTest.Write(TestHelpers.BlockExpectedResult);
Approvals.VerifyBinaryFile(result, ".stl");
}

[Test]
public void Write_WithSmallHeader_ReturnsExpectedResult()
{
var hdr = new ASCIIEncoding().GetBytes("short header");
var result = ObjectUnderTest.Write(TestHelpers.BlockExpectedResult, hdr);
Approvals.VerifyBinaryFile(result, ".stl");
}

[Test]
public void Write_WithLargeHeader_ReturnsExpectedResult()
{
var hdr = string.Join("", Enumerable.Repeat("abcdefghijklmnopqrstuvwxyz1234567890", 10));
var hdrBytes = new ASCIIEncoding().GetBytes(hdr);

var result = ObjectUnderTest.Write(TestHelpers.BlockExpectedResult, hdrBytes);
Approvals.VerifyBinaryFile(result, ".stl");
}
}
}
4 changes: 4 additions & 0 deletions GenericStl.Tests/GenericStl.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
<ItemGroup>
<Compile Include="AsciiStlReaderTests.cs" />
<Compile Include="AsciiStlWriterTests.cs" />
<Compile Include="StlFileTests.cs" />
<Compile Include="StlReaderBaseTests.cs" />
<Compile Include="StlReaderTests.cs" />
<Compile Include="StlWriterBaseTests.cs" />
Expand All @@ -101,6 +102,9 @@
<None Include="TestData\binary_block.stl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData\binary_block_with_solid_header.stl">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GenericStl\GenericStl.csproj">
Expand Down
31 changes: 31 additions & 0 deletions GenericStl.Tests/StlFileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GenericStl.Tests.TestDataStructures;
using NUnit.Framework;

namespace GenericStl.Tests
{
[TestFixture]
public class StlFileTests
{
public IEnumerable IsBinaryFileTestCases
{
get
{
yield return new TestCaseData(@".\TestData\ascii_block.stl").SetName("Ascii file").Returns(false);
yield return new TestCaseData(@".\TestData\binary_block.stl").SetName("Binary block file").Returns(true);
yield return new TestCaseData(@".\TestData\binary_block_with_solid_header.stl").SetName("Binary file with solid header").Returns(true);
}
}

[TestCaseSource("IsBinaryFileTestCases")]
public bool IsBinaryFile_ReturnsExpected(string filename)
{
return StlFile.IsBinaryFile(filename);
}
}
}
Binary file not shown.
33 changes: 28 additions & 5 deletions GenericStl/BinaryStlWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,11 @@ public void WriteToStream(Stream s, IEnumerable<TTriangle> triangles, byte[] hea
throw new ArgumentNullException("triangles");
}

if (header != null && header.Length != 80)
{
throw new ArgumentException("header must have a size of 80 bytes.", "header");
}
var hdr = PrepareHeader(header);

using (var w = new BinaryWriter(s, new UTF8Encoding(false, true), true))
{
WriteHeader(w, header ?? new byte[HeaderLengthInByte]);
WriteHeader(w, hdr);
WriteLength(w, 0);

var length = 0;
Expand All @@ -84,6 +81,32 @@ public void WriteToStream(Stream s, IEnumerable<TTriangle> triangles, byte[] hea
}
}

private static byte[] PrepareHeader(byte[] header)
{
if (header == null)
{
return new byte[HeaderLengthInByte];
}

if (header.Length == HeaderLengthInByte)
{
return header;
}

var newHdr = new byte[HeaderLengthInByte];

if (header.Length < HeaderLengthInByte)
{
Array.Copy(header, newHdr, header.Length);
}
else if (header.Length > HeaderLengthInByte)
{
Array.Copy(header, newHdr, newHdr.Length);
}

return newHdr;
}

private void WriteTriangle(BinaryWriter w, TTriangle t)
{
var triangleData = ExtractTriangle(t);
Expand Down
1 change: 1 addition & 0 deletions GenericStl/GenericStl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<Compile Include="IDataStructureCreator.cs" />
<Compile Include="IDataStructureExtractor.cs" />
<Compile Include="IStlWriter.cs" />
<Compile Include="StlFile.cs" />
<Compile Include="StlReader.cs" />
<Compile Include="StlWriterBase.cs" />
<Compile Include="BinaryStlReader.cs" />
Expand Down
51 changes: 51 additions & 0 deletions GenericStl/StlFile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using System.IO;
using System.Text;

namespace GenericStl
{
public static class StlFile
{
public static bool IsBinaryFile(string filename)
{
if (!File.Exists(filename))
{
throw new FileNotFoundException("filename could not be found.", filename);
}

using (var fs = File.OpenRead(filename))
{
return IsBinary(fs);
}
}

public static bool IsBinary(Stream stream)
{
try
{
using(var r = new BinaryReader(stream, Encoding.UTF8, true))
{
var firstChars = new string(r.ReadChars(5));

if (!string.Equals(firstChars, "solid", StringComparison.OrdinalIgnoreCase))
{
return true;
}

var numberOfCharsToReadAtEnd = "endsolid".Length + 300;
numberOfCharsToReadAtEnd = numberOfCharsToReadAtEnd > stream.Length ? (int)stream.Length : numberOfCharsToReadAtEnd;

stream.Seek(-numberOfCharsToReadAtEnd , SeekOrigin.End);

var lastChars = new string(r.ReadChars(numberOfCharsToReadAtEnd));

return !lastChars.Contains("endsolid");
}
}
finally
{
stream.Seek(0, SeekOrigin.Begin);
}
}
}
}
30 changes: 13 additions & 17 deletions GenericStl/StlReader.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace GenericStl
{
Expand All @@ -11,6 +10,10 @@ public StlReader(Func<TVertex, TVertex, TVertex, TNormal, TTriangle> createTrian
{
}

public StlReader(IDataStructureCreator<TTriangle, TVertex, TNormal> dataStructureCreator) : base(dataStructureCreator)
{
}

public override IEnumerable<TTriangle> ReadFromFile(string fileName)
{
using (var fs = File.OpenRead(fileName))
Expand All @@ -24,30 +27,23 @@ public override IEnumerable<TTriangle> ReadFromFile(string fileName)

public override IEnumerable<TTriangle> ReadFromStream(Stream s)
{
if (IsBinaryStl(s))
if (s == null)
{
return new BinaryStlReader<TTriangle, TVertex, TNormal>(CreateTriangle, CreateVertex, CreateNormal).ReadFromStream(s);
throw new ArgumentNullException("s", "Stream must not be null.");
}

return new AsciiStlReader<TTriangle, TVertex, TNormal>(CreateTriangle, CreateVertex, CreateNormal).ReadFromStream(s);
var reader = GetReaderFor(s);
return reader.ReadFromStream(s);
}

public static bool IsBinaryStl(Stream stream)
private IStlReader<TTriangle> GetReaderFor(Stream s)
{
try
{
using (var r = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
{
var buf = new char[20];
r.ReadBlock(buf, 0, 20);
var start = new string(buf);
return !start.TrimStart().StartsWith("solid", StringComparison.OrdinalIgnoreCase);
}
}
finally
if (StlFile.IsBinary(s))
{
stream.Seek(0, SeekOrigin.Begin);
return new BinaryStlReader<TTriangle, TVertex, TNormal>(CreateTriangle, CreateVertex, CreateNormal);
}

return new AsciiStlReader<TTriangle, TVertex, TNormal>(CreateTriangle, CreateVertex, CreateNormal);
}
}
}

0 comments on commit a91bee9

Please sign in to comment.