JDK-4813151 : Jar utility should store compressed entry size information in LOC headers
  • Type: Enhancement
  • Component: tools
  • Sub-Component: jar
  • Affected Version: 1.2.1,1.4.0,1.4.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: generic,solaris_8,windows_2000
  • CPU: generic,x86,sparc
  • Submitted: 2003-02-05
  • Updated: 2020-06-11
  • Resolved: 2020-06-11
Related Reports
Relates :  
Relates :  
Relates :  
Description

Name: gm110360			Date: 02/05/2003


FULL PRODUCT VERSION :
Solaris:
java version "1.3.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_01)
Java HotSpot(TM) Client VM (build 1.3.1_01, mixed mode)

Windows:
java version "1.4.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-b21)
Java HotSpot(TM) Client VM (build 1.4.1-b21, mixed mode)

java version "1.3.1_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02)
Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode)


FULL OPERATING SYSTEM VERSION :
SunOS dev280r1 5.8 Generic_108528-13 sun4u sparc SUNW,Sun-
Fire-280R

ADDITIONAL OPERATING SYSTEMS :
Windows NT Version 4.00.1381


A DESCRIPTION OF THE PROBLEM :
If a jar file is created using the JDK jar utility, the
getSize and getCompressedSize methods of the JarEntry (and
ZipEntry) class return -1 (unknown.)

The methods report the correct sizes if the archive is a
zip file (created with Info-ZIP zip or other popular third-
party compression utility.)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. create a sample text file with some content and name it:
afile.txt
2. jar cvf test.jar afile.txt
3. Compile and run the sample code below against test.jar

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expect the program to display:

Size is: size

where size is the actual file size, but instead the program
will display:

Size is: -1

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.util.jar.*;
import java.io.*;


public class Main{

	public static void main(String [] args){
		JarInputStream in = null;

		if(args.length != 1){
			System.err.println("Exiting...");
			System.exit(1);
		}
		else{
			try{
				in = new JarInputStream(new FileInputStream(args
[0]));
				while(in.available()>0){
					JarEntry current = in.getNextJarEntry();
					if(current != null){
						System.out.println("Size
is : "+ current.getSize());
					}
				}
			}
			catch(Exception e){
				System.err.println("Caught exception "+ e);
			}
			finally{
				try{
					in.close();
				}
				catch(Exception e){
					//do nothing - we don't care!
				}
			}
		}
	}
}

---------- END SOURCE ----------
(Review ID: 166348) 
======================================================================

Comments
WORK AROUND Adding a call to closeEntry() makes the file sizes correct.
11-06-2004

EVALUATION This behaviour has existed since jdk1.2, when the api in question was introduced. -- iag@sfbay 2003-02-05 The submitter's code is missing a call to closeEntry(). The following program, ------------------------------------------------------------------------ import java.io.*; import java.util.zip.*; public class EntrySize { public static void main(String[] args) throws Exception { ZipInputStream s = new ZipInputStream (new FileInputStream(args[0])); ZipEntry e; while ((e = s.getNextEntry()) != null) { System.out.println(e.getSize() + " " + e.getCompressedSize()); s.closeEntry(); System.out.println(e.getSize() + " " + e.getCompressedSize()); } } } ------------------------------------------------------------------------ when run against a jar file containing one compressed entry, produces output like -1 -1 562 315 This is unintuitive and under-documented and inefficient, but working as designed, so Not A Bug. The reason it works this way is that jar files are written using non-seekable InputStreams and OutputStreams. Because the compressed size is not known until after the compressed size is known, it is written AFTER the data. When it is read later, the data must be read before the compressed size is available, since it is written beyond the data. closeEntry() can make the sizes available, because the data will not be needed. This situation is unsatisfactory, and should be fixed as an RFE. - Accessing zip files as non-seekable streams is unnatural and inefficient. An access method assuming a seekable source of bytes should be provided. This should be MUCH more efficient (the target app here is javac). - Even with the current non-seekable API, `jar' could write the file sizes BEFORE the data by using a two-pass algorithm at jar file creation time. This would make jar file writing less efficient, but jar file reading more efficient -- an excellent exchange. The file size for a zip file entry can be stored in 3 different places in a zip file! ###@###.### 2003-12-26
26-12-2003