6

I am trying to modify an XLSX file programmatically using Objective-C.

So far, I am only modifying the data on one of the sheets. The steps I am taking are as follows:

  • Copy the XLSX file to Documents folder
  • Unzip the XLSX container with keeping the directory structure
  • Parse the corresponding sheet XML file (sheet2.xml in my case)
  • Add some rows
  • Rewrite the XML structure and save it
  • Put the updated XML file back into the XLSX container

However, the new XLSX file becomes corrupt. I am using GDataXML for XML parsing/writing and Objective-Zip for zipping/unzipping.

I know that the XML file I have created is proper, because when I manually unzip and the re-zip the corrupt XLSX file, it opens without any errors. I have done this on both OS X (using Unarchiver) and Windows (using 7-Zip).

The problem is either with the Objective-Zip library, or the way I use it. Below is how I implement the zipping method:

ZipFile *zipFile = [[ZipFile alloc] initWithFileName:XLSXDocumentsFilePath mode:ZipFileModeAppend];
ZipWriteStream *stream= [zipFile writeFileInZipWithName:XLSX_WORKSHEET_XML_SUBPATH compressionLevel:ZipCompressionLevelNone];
[stream writeData:data];
[stream finishedWriting];
[zipFile close];

I also tried the other compressionLevel arguments available with no luck:

ZipCompressionLevelDefault
ZipCompressionLevelBest
ZipCompressionLevelFastest

My questions are:

  • Which zipping library should I use to create a valid XLSX file programmatically?
  • If Objective-Zip is suitable, what is wrong with my code?

From an answer to another question, I found out that: "The OOXML format imposes that the only compression method permitted in the package is DEFLATE".

Is it possible to force Objective-Zip to use DEFLATE? Or is there an open-source iOS zipping library that uses DEFLATE?

Community
  • 1
  • 1
tolgamorf
  • 809
  • 6
  • 23
  • 2
    [miniz.c](http://code.google.com/p/miniz/source/browse/trunk/miniz.c) implements the DEFLATE algorithm. I'm not sure how you feel about plain C though. – CodaFi Mar 03 '13 at 21:32
  • @CodaFi, I am not very enthusiastic about using plain C. However, I know that Objective-Zip library uses ZLib and MiniZip. – tolgamorf Mar 03 '13 at 21:50
  • Objective-Zip implements deflation, but I believe it defaults to gzip, which may be why it's "corrupting" your archive. Short of licensing the DEFLATE algorithm and writing your own, you could just write a wrapper around that. Sorry there's nothing easier, but that's patents and dumb standards (OOXML is ridiculous) for ya'. – CodaFi Mar 03 '13 at 21:52
  • @CodaFi, I went ahead and looked into the implementation codes of Objective-Zip, and from there to MiniZip and Zlib to investigate the compression method. The default method is DEFLATE. There is another problem and I am about to sort it out, will post it soon. – tolgamorf Mar 04 '13 at 21:47

1 Answers1

2

I found the answer upon doing some research and also having a one to one correspondence with Objective-Zip's developer, flyingdolphinstudio.

First of all, Objective-Zip uses DEFLATE as the default compression method. I also confirmed this with the developer, who told me that using ZipCompressionLevelDefault, ZipCompressionLevelFastest or ZipCompressionLevelBest for the argument compressionLevel: will guarantee a DEFLATE compression.

So, the problem is coming from the mode: argument, which is ZipFileModeAppend in my case. It seems that MiniZip does not have a method to delete the files inside a zip file and that's why I am not overwriting the existing file, but adding a new one. To make it more clear, take a look at how my xl/worksheets folder look like after zipping it using Objective-Zip: worksheets folder

So, the only way to create a valid XLSX container is to create the zip file from scratch, by adding all the files and also keeping the directory/file structure intact.

I hope this experience would help somebody out.

tolgamorf
  • 809
  • 6
  • 23
  • Yes, I believe so, but it tells me to wait for 24 hours :) – tolgamorf Mar 04 '13 at 22:25
  • [zipzap](http://github.com/pixelglow/zipzap) is an Objective-C library that allows you to delete entries within a zip file, and does the minimal work to update it i.e. it will only rewrite subsequent entries and the central directory to cover the hole. – Glen Low Aug 21 '13 at 03:54
  • @GlenLow thanks for the advice, I had a quick look and it looks very promising. I might migrate to zipzap in the future, when I have time. – tolgamorf Aug 24 '13 at 03:59