#2688 Parameters for deflateOutStream

Richard Sat 17 Mar 2018

I am experimenting with ePUB and need to be able to write the mimetype file without compression and the other files as standard Deflate compressed files. I am having trouble figuring out how to set the compression level option to 0. Could you please provide an example of how to pass the parameters to this method? Can I write the uncompressed file and then switch to Deflate for the remaining files on-the-fly or do I need to close the zip and then append files? Any help would be much appreciated.

SlimerDude Sat 17 Mar 2018

Hello Richard!

Zip.deflateOutStream() wraps an existing OutStream and is used like this:

outStream := ... // where ever your standard OutStream comes from
deflateStream := Zip.deflateOutStream(out, ["level":0])
deflateStream.write(...)
deflateStream.flush.close

Don't forget to flush the stream before closing, as this writes out any final meta.

I don't know anything about EPUB files, but from your description it sounds like you're trying to deflate single file in a Zip. That can be accomplished like this:

file    := `wotever.pub`.toFile
fout    := file.out
zip     := Zip.write(fout)

out     := zip.writeNext(`/file1`)
deflate := Zip.deflateOutStream(out, ["level":0])
deflate.write(...)  // write file contents
deflate.flush.close

zip.finish
fout.flush.close

Note how the Zip is written as normal, but the content of the /file is deflated.

Richard Tue 20 Mar 2018

Thanks for the prompt reply. I now see how to set the level parameter, but still can not get an uncompressed file to be added. I had to move the zip.finish to before the deflate.flush.close to prevent Java IOException: Stream closed.

I am using deflate.writeChars(...) to write the ePUB "mimetype" content of "application/epub+zip". Do I need to use the "nowrap" parameter to achieve what is referred to as a STORED file?

SlimerDude Tue 20 Mar 2018

I had to move the zip.finish to before the deflate.flush.close

That doesn't sound right. I was thinking that a safer way to accomplish the same would be to not to wrap Zip streams, but to write file contents to a separate Buf instead. Should be conceptually easier to follow if nothing else. Something like:

// open zip stream
zipOut  := `wotever.pub`.toFile.out
zip     := Zip.write(zipOut)

// deflate contents to a Buf
fileBuf := Buf()
deflate := Zip.deflateOutStream(fileBuf.out, ["level":0])
deflate.write(...)  // write file contents for /file1
deflate.flush.close

// write buf to the zip stream
out     := zip.writeNext(`/file1`)
out.writeBuf(fileBuf.flip)
out.close

// close zip stream
zip.finish
zipOut.flush.close

Do I need to use the "nowrap" parameter to achieve what is referred to as a STORED file?

I have no idea. Do you have any links to the ePUB specification?

Richard Sun 1 Sep 2019

Back to look at this again after a long break. An ePUB has the mimetype with content "application/epub+zip" as the first file in the zip archive. It needs to be stored as-in without deflate compression (this is referred to as STORED). The remaining files are stored using Deflate as the compression method. So is there a way to add the first file without any compression and just use compression on the ePUB content files? Sorry if this is confusing.

SlimerDude Mon 2 Sep 2019

Hi Richard,

Looking around (as I confess to not fully understanding your predicament), it seems EPUB files adhere to the Open Container Format which is described by Wikipedia as

The mimetype file must be a text document in ASCII that contains the string application/epub+zip. It must also be uncompressed, unencrypted, and the first file in the ZIP archive. This file provides a more reliable way for applications to identify the mimetype of the file than just the .epub extension.

I don't know if Brian or others can shed light on some kind of ->trap backdoor but I don't think this is supported by the current Fantom API.

This StackOverflow post shows how to achieve it in Java though:

private void writeMimeType(ZipOutputStream zip) throws IOException {
    byte[] content = "application/epub+zip".getBytes("UTF-8");
    ZipEntry entry = new ZipEntry("mimetype");
    entry.setMethod(ZipEntry.STORED);
    entry.setSize(20);
    entry.setCompressedSize(20);
    entry.setCrc(0x2CAB616F); // pre-computed
    zip.putNextEntry(entry);
    zip.write(content);
    zip.closeEntry();
}

Being nosey, in general, what does / will your EPUB library do?

Richard Mon 2 Sep 2019

Again, thanks for the prompt reply. I am developing an application to store Configuration Management data for systems in a simpler way. I prototyped bits in Lua but have been looking for alternative languages. I played with Fanton some time ago and liked it - hence the return visit.

I have decided to use ePub as an open way to share the "reports" from the database for easy distribution. I was going to use PDF but then came across ePub and thought that would be better.

Login or Signup to reply.