[Mono-dev] Patch for ZipPackagePart.GetStreamCore in System.IO.Packaging (olive)

Alan McGovern alan.mcgovern at gmail.com
Wed Mar 18 07:58:19 EDT 2009


Working on this one now.

Thanks!

Alan.

On Mon, Mar 16, 2009 at 7:21 PM, Yves Dhondt <yves.dhondt at gmail.com> wrote:

> Issue:
> -------
> ZipPackagePart.GetStreamCore in System.IO.Packaging does not handle
> Filemode mode input parameter (correctly).
>
> Test program (requires an existing openxml document, for example
> test.docx as input):
> -------------------
> I'm not that good with unit testing, but the following code should be
> easily translated into 4 tests.
>
>
> using System;
> using System.IO;
> using System.IO.Packaging;
>
> namespace MonoOpenXmlExperiment
> {
>   class Program
>   {
>     static void Main(string[] args)
>     {
>       // Warning do this with a document which can be damaged!!!
>       Package pack = Package.Open(args[0]);
>       PackagePart part = pack.CreatePart(new Uri("/somepart.xml",
> UriKind.Relative), "application/xml");
>
>       try
>       {
>         Stream s2 = part.GetStream(FileMode.CreateNew, FileAccess.Write);
>       }
>       catch (Exception ex)
>       {
>         // An ArgumentException should be throw as CreateNew is an
> unsupported mode.
>         Console.WriteLine("Expected ArgumentException, got {0}.",
> ex.GetType().ToString());
>       }
>
>       try
>       {
>         Stream s3 = part.GetStream(FileMode.Truncate, FileAccess.Write);
>       }
>       catch (Exception ex)
>       {
>         // An ArgumentException should be throw as Truncate is an
> unsupported mode.
>         Console.WriteLine("Expected ArgumentException, got {0}.",
> ex.GetType().ToString());
>       }
>
>       try
>       {
>         Stream s4 = part.GetStream(FileMode.Append, FileAccess.Write);
>       }
>       catch (Exception ex)
>       {
>         // An ArgumentException should be throw as Append is an
> unsupported mode.
>         Console.WriteLine("Expected ArgumentException, got {0}.",
> ex.GetType().ToString());
>       }
>
>       Stream s = part.GetStream(FileMode.OpenOrCreate, FileAccess.Write);
>       StreamWriter sw = new StreamWriter(s);
>       sw.Write("<test>aaaaaaa</test>");
>       sw.Flush();
>
>       Stream s5 = part.GetStream(FileMode.Create, FileAccess.ReadWrite);
>       StreamWriter sw2 = new StreamWriter(s5);
>       sw2.Write("<test>bbb</test>");
>       sw2.Flush();
>
>       // Verify that the part got overwritten correctly.
>       Stream s6 = part.GetStream();
>       StreamReader sr = new StreamReader(s6);
>       Console.WriteLine("Expected <test>bbb</test>, got {0}.",
> sr.ReadToEnd());
>
>       pack.Close();
>     }
>   }
> }
>
>
>
> Expected output:
> ------------------------
> Expected ArgumentException, got System.ArgumentException.
> Expected ArgumentException, got System.ArgumentException.
> Expected ArgumentException, got System.ArgumentException.
> Expected <test>bbb</test>, got <test>bbb</test>.
>
> Output currently given by mono:
> ---------------------------------------------
> Expected <test>bbb</test>, got <test>bbb</test>.
>
> Remarks:
> -------------
> The last test is especially important as it indicates that a create
> would only overwrite part of stream.
>
> Solution:
> ------------
> Replace function by:
>
> protected override Stream GetStreamCore (FileMode mode, FileAccess access)
>     {
>       MemoryStream stream;
>
>       switch (mode)
>       {
>         case FileMode.CreateNew:
>           throw new ArgumentException("FileMode not supported",
> "CreateNew");
>         case FileMode.Truncate:
>           throw new ArgumentException("FileMode not supported",
> "Truncate");
>         case FileMode.Append:
>           throw new ArgumentException("FileMode not supported", "Append");
>         case FileMode.Open:
>           if (Package.PartStreams.TryGetValue(Uri, out stream)) {
>             return new ZipPartStream(Package, stream, access);
>           }
>           else {
>             throw new IOException(); // Verify that this is the
> correct exception.
>           }
>         case FileMode.OpenOrCreate:
>         case FileMode.Create:
>           // Check if a stream is already loaded. If not, load it or
> create an empty one.
>           if (!Package.PartStreams.TryGetValue(Uri, out stream)) {
>             stream = new MemoryStream();
>
>             try
>             {
>               using (UnzipArchive archive = new
> UnzipArchive(Package.PackageStream))
>               {
>                 foreach (string file in archive.GetFiles())
>                 {
>                   if (file != Uri.ToString().Substring(1))
>                     continue;
>
>                   using (Stream archiveStream = archive.GetStream(file))
>                   {
>                     int read = 0;
>                     byte[] buffer = new
> byte[Math.Min(archiveStream.Length, 2 * 1024)];
>                     while ((read = archiveStream.Read(buffer, 0,
> buffer.Length)) != 0)
>                       stream.Write(buffer, 0, read);
>                   }
>                 }
>               }
>             }
>             catch
>             {
>               // The zipfile is invalid, so just create the file
>               // as if it didn't exist
>               stream.SetLength(0);
>             }
>
>             Package.PartStreams.Add(Uri, stream);
>           }
>
>    // This ensures that an existing stream to which a create
>    // is applied will be overwritten.
>    if (mode == FileMode.Create)
>             stream.SetLength(0);
>
>           return new ZipPartStream(Package, stream, access);
>  default:
>    throw new ArgumentOutOfRangeException("mode");
>       }
> }
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-devel-list/attachments/20090318/33e55964/attachment-0001.html 


More information about the Mono-devel-list mailing list