<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">
Hi Eirik,
<div class=""><br class="">
</div>
<div class="">Please see below<br class="">
<div><br class="">
<blockquote type="cite" class="">
<div class="">On Mar 6, 2023, at 1:43 PM, Eirik Bjørsnøs <<a href="mailto:eirbjo@gmail.com" class="">eirbjo@gmail.com</a>> wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<div dir="ltr" class=""><br class="">
<div class="">Hi,</div>
<div class=""><br class="">
</div>
<div class="">I noticed that ZipOutputStream violates APPNOTE.txt when writing directory entries:<br class="">
</div>
</div>
</div>
</blockquote>
<div><br class="">
</div>
You are referring to section:</div>
<div><br class="">
</div>
<div>------------</div>
<div><br class="">
</div>
<div> <span style="white-space: pre-wrap;" class="">4.3.8 File data</span>
<pre style="overflow-wrap: break-word; white-space: pre-wrap;" class="">
      Immediately following the local header for a file
      SHOULD be placed the compressed or stored data for the file.
      If the file is encrypted, the encryption header for the file 
      SHOULD be placed after the local header and before the file 
      data. The series of [local file header][encryption header]
      [file data][data descriptor] repeats for each file in the 
      .ZIP archive. 

      Zero-byte files, directories, and other file types that 
      contain no content MUST NOT include file data.</pre>
<div class="">
<div>——————</div>
</div>
<div><br class="">
</div>
<div>I don’t think changing the default will cause any harm but I have been surprised by even the most trivial change before.</div>
<div><br class="">
</div>
<div>The jar tool  already addresses this in Main.java:addFile() on a quick glance.</div>
<div><br class="">
</div>
<div>So I guess I do not see a huge downside, however we might want to look at a property to adjust in the unlikely event the unexpected occurs?</div>
<div><br class="">
</div>
<div>Alan thoughts?</div>
<div><br class="">
</div>
<div><br class="">
</div>
<div class=""><br class="">
</div>
<blockquote type="cite" class="">
<div class="">
<div dir="ltr" class="">
<div class=""><br class="">
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Zero-byte files, directories, and other file types that<br class="">
contain no content MUST NOT include file data.</blockquote>
<div class=""><br class="">
</div>
<div class="">Nobody seems to have complained about this violation (I searched JBS), so in itself it might not be worth pursuing a fix. However, in addition to breaking the specification, this also causes suboptimal performance both on the write and read paths.</div>
<div class=""><br class="">
</div>
<div class="">Before I go ahead and suggest any particular solution, I wanted to share some analysis:</div>
<div class=""><br class="">
</div>
<div class="">ZipOutputStream writes directories as any other entry, so by default it ends up writing a LOC header with the DEFLATED method and the data descriptor bit set. This is followed by a final, empty DEFLATE block (0x0300) and then a signed data descriptor
 with the CRC, csize (2) and size (0), each 4 bytes:</div>
<div class=""><br class="">
</div>
<div class="">------  Local File Header  ------<br class="">
000000  signature          0x04034b50     <br class="">
000004  version            20             <br class="">
000006  flags              0x0808         <br class="">
000008  method             8              Deflated<br class="">
000010  time               0x9812         19:00:36<br class="">
000012  date               0x5666         2023-03-06<br class="">
000014  crc                0x00000000     <br class="">
000018  csize              0              <br class="">
000022  size               0              <br class="">
000026  nlen               9              <br class="">
000028  elen               0              <br class="">
000030  name               9 bytes        'META-INF/'<br class="">
</div>
<div class=""><br class="">
------  File Data  ------<br class="">
000039  data               2 bytes        <br class="">
<br class="">
------  Data Descriptor  ------<br class="">
000041  signature          0x08074b50     <br class="">
000045  crc                0x00000000     <br class="">
000049  csize              2              <br class="">
000053  size               0              <br class="">
</div>
<div class=""><br class="">
</div>
<div class="">In total, this means that an extra 18 bytes is output, which is a waste of storage space and IO cycles while writing and reading/parsing the unnecessary headers and data. If the directory entry has the STORED method and the sizes and crc is set
 to 0, then the file data and data descriptors are skipped and we reclaim 18 bytes.</div>
<div class=""><br class="">
</div>
<div class="">The use of DEFLATE has an adverse negative impact on performance, since native ZLIB code needs to be called to produce and read (in ZipInputStream) the empty DEFLATE block. Worse, Deflater.reset and Inflater.reset are called, which seems to incur
 a significant overhead.</div>
<div class=""><br class="">
</div>
<div class="">In fact, when configuring the STORED method and explicitly setting csize, size and crc to 0, we see considerable benchmark improvements writing and reading directory entries:</div>
<div class=""><br class="">
</div>
<div class="">DEFLATED:</div>
<div class=""><br class="">
</div>
<div class=""><font face="monospace" class="">Benchmark                        (size)  Mode  Cnt  Score   Error  Units<br class="">
ZipEmptyStreams.readDirStream       512  avgt   15  0.278 ± 0.005  ms/op<br class="">
ZipEmptyStreams.readDirStream      1024  avgt   15  0.550 ± 0.006  ms/op<br class="">
ZipEmptyStreams.writeDirStreams     512  avgt   15  2.379 ± 0.043  ms/op<br class="">
ZipEmptyStreams.writeDirStreams    1024  avgt   15  4.845 ± 0.087  ms/op</font><br class="">
</div>
<div class=""><br class="">
</div>
<div class="">STORED:</div>
<div class=""><br class="">
</div>
<div class=""><font face="monospace" class="">Benchmark                       (size)  Mode  Cnt  Score   Error  Units<br class="">
ZipEmptyStreams.readDirStream      512  avgt   15  0.082 ± 0.001  ms/op<br class="">
ZipEmptyStreams.readDirStream     1024  avgt   15  0.176 ± 0.015  ms/op<br class="">
ZipEmptyStreams.writeDirStream     512  avgt   15  0.233 ± 0.021  ms/op<br class="">
ZipEmptyStreams.writeDirStream    1024  avgt   15  0.460 ± 0.028  ms/op</font><br class="">
</div>
<div class=""><br class="">
</div>
<div class=""><br class="">
</div>
<div class="">Possible actions:</div>
<div class=""><br class="">
</div>
<div class="">- Do nothing: Nobody complained so far, so if is ain't broke, don't fix it.</div>
<div class="">- Update Javadocs of ZipInputStream.putNextEntry to recommend that users should use STORED  and configure sizes & crc for directory entries for correctness and performance </div>
<div class="">- Change the default compression method for directories to STORED and set sizes & crc to 0. This would add the risk of changing behavior of existing code.</div>
<div class=""><br class="">
</div>
<div class="">For context, 7% of entries in the dependencies of Spring Petclinic are directories.  </div>
<div class=""><br class="">
</div>
<div class="">Any thoughts or input?</div>
<div class=""><br class="">
</div>
<div class="">Thanks,</div>
<div class="">Eirik.</div>
</div>
</div>
</blockquote>
</div>
<br class="">
<div class=""><span><img apple-inline="yes" id="D7481346-E8CC-40B6-902B-05470CADDF5E" src="cid:E1C4E2F0-ECD0-4C9D-ADB4-B16CA7BCB7FC@home" class=""></span>
<div dir="auto" style="font-family: Helvetica; font-size: 18px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0); word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">
<div><br class="Apple-interchange-newline">
<br class="Apple-interchange-newline">
<br class="Apple-interchange-newline">
<br class="">
<br class="">
<br class="">
Lance Andersen | Principal Member of Technical Staff | +1.781.442.2037</div>
<div>Oracle Java Engineering <br class="">
1 Network Drive <br class="">
Burlington, MA 01803<br class="">
<a href="mailto:Lance.Andersen@oracle.com" class="">Lance.Andersen@oracle.com</a></div>
</div>
<br class="Apple-interchange-newline" style="font-family: Helvetica; font-size: 18px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">
<br class="Apple-interchange-newline" style="font-family: Helvetica; font-size: 18px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none; caret-color: rgb(0, 0, 0); color: rgb(0, 0, 0);">
</div>
<br class="">
</div>
</body>
</html>