haplokuon / netDxf

.net dxf Reader-Writer
MIT License
990 stars 401 forks source link

netDxf.DxfDocument.Load(System.IO.Compression.DeflateStream) returns null #273

Open watanabelikewelltech opened 3 years ago

watanabelikewelltech commented 3 years ago

I zipped dxf file then unzip it on memory and tried to load dxf by public static DxfDocument Load(Stream stream); which every time returns null.

//-------------------
//make zip from dxf.
using var memoryStream = new MemoryStream();
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true, Encoding.UTF8);
var entryFile = archive.CreateEntry("data");
using var entryStream = entryFile.Open();
using var fs = new FileStream(dxfFilePath, FileMode.Open);
fs.CopyTo(entryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var zipBytes= memoryStream.ToArray();

//unzip and try read dxf from zip entry
using var zipSource = new MemoryStream(zipBytes);
using var archive = new ZipArchive(zipSource, ZipArchiveMode.Read);
var entry = archive.Entries.First();
using var stream = entry.Open();
//it fails here.
Trace.Assert(netDxf.DxfDocument.Load(stream) != null);

//workaround is copy deflatestream to memorystream then load from it.
//-------------------
using var ms = new MemoryStream();
stream.CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
netDxf.DxfDocument.Load(ms);
haplokuon commented 3 years ago

I have taken a look at your code and I have run into a couple problems. The code you have shown does not work as it is. In the line

using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true, Encoding.UTF8);

the first parenthesis is not needed. Also there is a duplicate name error for the variable "archive". I deleted the unneeded parenthesis and I renamed them as archiveIn and archiveOut, but even then, after providing a sample DXF file for the dxfFilePath variable, your sample code keeps crashing in the line

using var archiveOut = new ZipArchive(zipSource, ZipArchiveMode.Read);

with the exception

System.IO.InvalidDataException: 'End of Central Directory record could not be found.'

before the loading of the DXF file. I am not familiar with the new Zip compression classes in the net framework so I do not know what is the problem here.

Try to post a full working sample and give me the details of what version of the library you are using, I only have uploaded compiled version of the library for the Net Framework 4.5 and in that version the Net classes for managing ZIP files were not available. It would be much better if you download the latest code and compile the library yourself in Debug mode. The latest code is a multitarget project predefined for Net Framework 4.5, Net Standard 2.1, Net Core 3.1, and NET 5.0.

watanabelikewelltech commented 3 years ago

Thank you for replying.

I prepared full code.(.Net Core 3.1 MS Unit Test)

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
namespace DeflateStreamTest
{
    [TestClass]
    public class NetDxfDeflateTest
    {
        [TestMethod]
        public void check_method_with_latest_source()
        {
            string outputPath = @"empty.dxf";
            //make empty dxf
            {
                var dxf = new netDxf.DxfDocument();
                dxf.Save(outputPath);
            }
            byte[] zipBytes;
            //make zip from dxf.
            {
                var dxfFilePath =outputPath;
                using var memoryStream = new MemoryStream();
                using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true, Encoding.UTF8))
                {
                    var entryFile = archive.CreateEntry("data");
                    using var entryStream = entryFile.Open();
                    using var fs = new FileStream(dxfFilePath, FileMode.Open);
                    fs.CopyTo(entryStream);
                }
                memoryStream.Seek(0, SeekOrigin.Begin);
                zipBytes = memoryStream.ToArray();
            }
            //unzip and try read dxf from zip entry
            {
                using var zipSource = new MemoryStream(zipBytes);
                using var archive = new ZipArchive(zipSource, ZipArchiveMode.Read);
                var entry = archive.Entries.First();
                using var stream = entry.Open();
                //it fails here.
                Trace.Assert(netDxf.DxfDocument.Load(stream) != null);
            }
        }
    }
}

DeflateStream.Position Property That page says 'This property is not supported and always throws a NotSupportedException.'

I have seen some other classes which public abstract bool CanSeek{get;} returns false,

HttpWebResponse.GetResponseStream() returns ConnectStream whcih does not support Seek/Position. ConnectStream

haplokuon commented 3 years ago

Yeah, the problem is that the DefalteStream class do not allow changing the position in the stream. One of the first things that the reading process does is to read the first few bytes of the DXF file to check is it is binary or text, so the proper reader is used a BinaryReader or a TextReader, then the position is reset to the beginning to start the loading process. If there is a better way to do it, I do not know.

At the moment the only thing I will do is raise an exception for streams that do not support changing the position. So, you have two choices copying the data to a memory stream or saving the unzipped DXF file to a temporary directory.