R_D
R_D

Reputation: 13

Create ZipArchive from XML with base64 encoded content

I am creating an XML file on the fly. One of it's nodes contains a ZIP file encoded as a BASE64 string.

I then create another ZIP file. I add this XML file and a few other JPEG files. I output the file to the browser.

I am unable to open the FINAL ZIP file. I get: "Windows cannot open the folder. The Compressed(zipped) Folder'c:\path\file.zip' is invalid."

I am able to save my original XML file to the file system. I can open that XML file, decode the ZIP node and save to the file system. I am then able to open that Zip file with no problems.

I can create the final ZIP file, OMIT my XML file, and the ZIP file opens no problem.

I seem to only have an issue with I attempt to ZIP an XML file that has a node with ZIP content encoded as a BASE64 string.

Any ideas? Code snipets are below. Heavily edited.

XDocument xDoc = new XDocument();
XDocument xDocReport = new XDocument();
XElement xNodeReport;

using (FileStream fsData = new FileStream(strFullFilePath, FileMode.Open, FileAccess.Read)) {
    xDoc = XDocument.Load(fsData);

xNodeReport = xDoc.Element("Data").Element("Reports").Element("Report");

//SNIP
//create XDocument xDocReport 
//SNIO

  using (MemoryStream zipInMemoryReport = new MemoryStream()) {
    using (ZipArchive zipFile = new ZipArchive(zipInMemoryReport, ZipArchiveMode.Update)) {
    //Add REPORT to ZIP file
    ZipArchiveEntry entryReport = zipFile.CreateEntry("data.xml");
      using (StreamWriter writer = new StreamWriter(entryReport.Open())) {
        writer.Write(xDocReport.ToString());
      } //END USING report entry
    }
    xNodeReport.Value = System.Convert.ToBase64String(zipInMemoryReport.GetBuffer());

  //I am able to write this file to disk and manipulate it no problem.
  //File.WriteAllText("c:\\users\\snip\\desktop\\Report.xml",xDoc.ToString());

  }

  //create ZIP for response
  using (MemoryStream zipInMemory = new MemoryStream()) {
    using (ZipArchive zipFile = new ZipArchive(zipInMemory, ZipArchiveMode.Update)) {

    //Add REPORT to ZIP file
    ZipArchiveEntry entryReportWrapper = zipFile.CreateEntry("Report.xml");

    //THIS IS THE STEP THAT makes the Zip "invalid".  Although i can open and manipulate this source file no problem.
    //********
      using (StreamWriter writer = new StreamWriter(entryReportWrapper.Open())) {
        xDoc.Save(writer);
      } 

    //Add JPEG(s) to report
    //Create Charts
    if (chkDLSalesPrice.Checked) {chartDownloadSP.SaveImage(entryChartSP.Open(), ChartImageFormat.Jpeg);}
    if (chkDLSalesDOM.Checked) {chartDownloadDOM.SaveImage(entryChartDOM.Open(), ChartImageFormat.Jpeg);}
    if (chkDLSPLP.Checked) {chartDownloadSPLP.SaveImage(entryChartSPLP.Open(), ChartImageFormat.Jpeg);}
    if (chkDLSPLP.Checked) {chartDownloadLP.SaveImage(entryChartLP.Open(), ChartImageFormat.Jpeg);}

  } // END USING ziparchive

Response.Clear();
Response.AppendHeader("content-disposition", "attachment; filename=file.zip");
Response.ContentType = "application/zip";
Response.BinaryWrite(zipInMemory.GetBuffer());
Response.End();

Upvotes: 1

Views: 1538

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70652

Without a good, minimal, complete code example, it's impossible to know for sure what bugs are in the code. But there are at least two apparent errors in the code snippet you posted, one of which could easily be responsible for the "invalid .zip" error:

  1. In the statement writer.Write(xDocReport.ToString());, the variable xDocReport has not been initialized to anything useful, at least not in the code you posted. So you'll get an empty XML document in the archive.

Since the code example is incomplete, it's possible you just omitted from the code example in your question the initialization of that variable to something else. In any case, even if you didn't that would just lead to an empty XML document in the archive, not an invalid archive.

More problematic though…

  1. You are calling GetBuffer() on your MemoryStream objects, instead of ToArray(). You want the latter. The former gets the entire backing buffer for the MemoryStream object, including the uninitialized bytes past the end of the valid stream. Since a valid .zip file includes a CRC value at the end of the file, adding extra data beyond that causes anything trying to read the file as a .zip archive to miss the correct CRC, reading the uninitialized data instead.

Replace your calls to GetBuffer() with calls to ToArray() instead.

If the above does not lead to a solution for your problem, you should edit your post, to provide a better code example.


One last comment: there is no point in initializing a variable like xDoc to an empty XDocument object when you're going to just replace that object with a different one (e.g. by calling XDocument.Load()).

Upvotes: 1

Related Questions