/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* This class implements a simple utility for creating files in the JAR
* (Java Archive) file format. The JAR format is based on the ZIP file
* format, with optional meta-information stored in a MANIFEST entry.
*/
public
class Main {
// An entryName(path)->File map generated during "expand", it helps to
// decide whether or not an existing entry in a jar file needs to be
// replaced, during the "update" operation.
// Directories specified by "-C" operation.
/*
* cflag: create
* uflag: update
* xflag: xtract
* tflag: table
* vflag: verbose
* flag0: no zip compression (store only)
* Mflag: DO NOT generate a manifest file (just ZIP)
* iflag: generate jar index
*/
/**
* If true, maintain compatibility with JDK releases prior to 6.0 by
* timestamping extracted files with the time at which they are extracted.
* Default is to use the time given in the archive.
*/
private static final boolean useExtractionTime =
/**
* Initialize ResourceBundle
*/
static {
try {
} catch (MissingResourceException e) {
throw new Error("Fatal: Resource for jar is missing");
}
}
try {
} catch (MissingResourceException e) {
throw new Error("Error in message file");
}
}
}
}
}
/**
* Creates a new empty temporary file in the same directory as the
* specified file. A variant of File.createTempFile.
*/
throws IOException {
}
private boolean ok;
/**
* Starts main program with the specified arguments.
*/
ok = true;
return false;
}
try {
// The name of the zip file as it would appear as its own
// zip file entry. We use this to make sure that we don't
// add the zip file to itself.
}
}
}
if (cflag) {
if (!Mflag) {
} else {
}
if (isAmbiguousMainClass(manifest)) {
}
return false;
}
}
}
} else {
if (vflag) {
// Disable verbose output so that it does not appear
// on stdout along with file data
// error("Warning: -v option ignored");
vflag = false;
}
}
}
} else if (uflag) {
} else {
vflag = false;
}
if (ok) {
}
}
// on Win32, we need this delete
}
}
} else if (tflag) {
} else {
try{
} finally {
}
}
} else if (xflag) {
} else {
: new FileInputStream(fname);
try {
} finally {
}
}
} else if (iflag) {
}
} catch (IOException e) {
fatalError(e);
ok = false;
ok = false;
} catch (Throwable t) {
t.printStackTrace();
ok = false;
}
return ok;
}
/**
* Parses command line arguments.
*/
/* Preprocess and expand @file arguments */
try {
} catch (FileNotFoundException e) {
return false;
} catch (IOException e) {
fatalError(e);
return false;
}
/* parse flags */
int count = 1;
try {
}
case 'c':
usageError();
return false;
}
cflag = true;
break;
case 'u':
usageError();
return false;
}
uflag = true;
break;
case 'x':
usageError();
return false;
}
xflag = true;
break;
case 't':
usageError();
return false;
}
tflag = true;
break;
case 'M':
Mflag = true;
break;
case 'v':
vflag = true;
break;
case 'f':
break;
case 'm':
break;
case '0':
flag0 = true;
break;
case 'i':
usageError();
return false;
}
// do not increase the counter, files will contain rootjar
iflag = true;
break;
case 'e':
break;
default:
usageError();
return false;
}
}
} catch (ArrayIndexOutOfBoundsException e) {
usageError();
return false;
}
usageError();
return false;
}
/* parse file arguments */
if (n > 0) {
int k = 0;
try {
/* change the directory */
}
} else {
}
}
} catch (ArrayIndexOutOfBoundsException e) {
usageError();
return false;
}
usageError();
return false;
} else if (uflag) {
/* just want to update the manifest */
return true;
} else {
usageError();
return false;
}
}
return true;
}
/**
* Expands list of files to process into full list of all files that
* can be found by recursively descending directories.
*/
return;
}
File f;
} else {
}
if (f.isFile()) {
if (isUpdate)
}
} else if (f.isDirectory()) {
if (isUpdate) {
}
}
} else {
ok = false;
}
}
}
/**
* Creates a new JAR file.
*/
throws IOException
{
if (flag0) {
}
if (vflag) {
}
e.setSize(0);
e.setCrc(0);
zos.putNextEntry(e);
e = new ZipEntry(MANIFEST_NAME);
if (flag0) {
crc32Manifest(e, manifest);
}
zos.putNextEntry(e);
zos.closeEntry();
}
}
}
private char toUpperCaseASCII(char c) {
return (c < 'a' || c > 'z') ? c : (char) (c + 'A' - 'a');
}
/**
* Compares two strings for equality, ignoring case. The second
* argument must contain only upper-case ASCII characters.
* We don't want case comparison to be locale-dependent (else we
* have the notorious "turkish i bug").
*/
int len;
return false;
for (int i = 0; i < len; i++) {
return false;
}
return true;
}
/**
* Updates an existing jar file.
*/
{
boolean foundManifest = false;
boolean updateOk = true;
}
// put the old entries first, replace if necessary
|| (Mflag && isManifestEntry)) {
continue;
foundManifest = true;
if (newManifest != null) {
// Don't read from the newManifest InputStream, as we
// might need it below, and we can't re-read the same data
// twice.
if (ambiguous) {
return false;
}
}
// Update the manifest.
if (newManifest != null) {
}
} else {
// do our own compression
}
} else { // replace with the new files
}
}
}
// add the remaining new files
}
if (!foundManifest) {
if (newManifest != null) {
updateOk = !isAmbiguousMainClass(m);
if (updateOk) {
updateManifest(m, zos);
}
}
}
return updateOk;
}
throws IOException
{
if (flag0) {
os.updateEntry(e);
}
zos.putNextEntry(e);
zos.closeEntry();
}
throws IOException
{
addVersion(m);
addCreatedBy(m);
addMainClass(m, ename);
}
if (flag0) {
crc32Manifest(e, m);
}
zos.putNextEntry(e);
if (vflag) {
}
}
}
}
}
return name;
}
}
}
javaVendor + ")");
}
}
// overrides any existing Main-Class attribute
}
usageError();
return true;
}
}
return false;
}
/**
* Adds a new file entry to the ZIP output stream.
*/
if (isDir) {
}
return;
&& !Mflag) {
if (vflag) {
}
return;
}
if (vflag) {
}
if (size == 0) {
e.setSize(0);
e.setCrc(0);
} else if (flag0) {
}
zos.putNextEntry(e);
if (!isDir) {
}
zos.closeEntry();
/* report how much compression occurred. */
if (vflag) {
long csize = e.getCompressedSize();
long ratio = 0;
if (size != 0) {
}
} else {
}
}
}
/**
* A buffer for use only by copy(InputStream, OutputStream).
* Not as clean as allocating a new buffer as needed by copy,
* but significantly more efficient.
*/
/**
* Copies all bytes from the input stream to the output stream.
* Does not close or flush either stream.
*
* @param from the input stream to read from
* @param to the output stream to write to
* @throws IOException if an I/O error occurs
*/
int n;
}
/**
* Copies all bytes from the input file to the output stream.
* Does not close or flush the output stream.
*
* @param from the input file to read from
* @param to the output stream to write to
* @throws IOException if an I/O error occurs
*/
try {
} finally {
}
}
/**
* Copies all bytes from the input stream to the output file.
* Does not close the input stream.
*
* @param from the input stream to read from
* @param to the output file to write to
* @throws IOException if an I/O error occurs
*/
try {
} finally {
}
}
/**
* Computes the crc32 of a Manifest. This is necessary when the
* ZipOutputStream is in STORED mode.
*/
os.updateEntry(e);
}
/**
* Computes the crc32 of a File. This is necessary when the
* ZipOutputStream is in STORED mode.
*/
throw new JarException(formatMsg(
"error.incorrect.length", f.getPath()));
}
os.updateEntry(e);
}
}
}
}
@SuppressWarnings("serial")
}};
}
if (lastModified != -1) {
}
}
}
/**
* Extracts specified entries from JAR file.
*/
ZipEntry e;
// Set of all directory entries specified in archive. Disallows
// null entries. Disallows all entries if using pre-6.0 behavior.
} else {
break;
}
}
}
}
// Update timestamps of directories specified in archive with their
// timestamps as given in the archive. We do this after extraction,
// instead of during, because creating a file in a directory changes
// that directory's timestamp.
}
/**
* Extracts specified entries from JAR file, via ZipFile.
*/
while (zes.hasMoreElements()) {
} else {
break;
}
}
}
}
}
/**
* Extracts next entry from JAR file, creating directories as needed. If
* the entry is for a directory which doesn't exist prior to this
* invocation, returns that entry, otherwise returns null.
*/
if (e.isDirectory()) {
if (f.exists()) {
if (!f.isDirectory()) {
f.getPath()));
}
} else {
if (!f.mkdirs()) {
f.getPath()));
} else {
rc = e;
}
}
if (vflag) {
}
} else {
throw new IOException(formatMsg(
"error.create.dir", d.getPath()));
}
}
try {
} finally {
if (is instanceof ZipInputStream)
else
}
if (vflag) {
} else {
}
}
}
if (!useExtractionTime) {
long lastModified = e.getTime();
if (lastModified != -1) {
}
}
return rc;
}
/**
* Lists contents of JAR file.
*/
ZipEntry e;
/*
* In the case of a compressed (deflated) entry, the entry size
* is stored immediately following the entry data and cannot be
* determined until the entry is fully read. Therefore, we close
* the entry first before printing out its attributes.
*/
zis.closeEntry();
printEntry(e, files);
}
}
/**
* Lists contents of JAR file, via ZipFile.
*/
while (zes.hasMoreElements()) {
}
}
/**
* Outputs the class index table to the INDEX.LIST file of the
* root jar file.
*/
try {
try {
} catch (IOException e) {
}
}
} finally {
}
}
/**
* Generates the transitive closure of the Class-Path attribute for
* the specified jar file.
*/
// take out the current path
// class path attribute will give us jar file name with
// '/' as separators, so we need to change them to the
// appropriate one before we open the jar file.
while (st.hasMoreTokens()) {
/* check on cyclic dependency */
}
}
}
}
}
}
}
return files;
}
/**
* Generates class index file for the specified root jar file.
*/
// no class-path attribute defined in rootjar, will
// use command line specified list of jars
}
}
}
/**
* Prints entry information, if requested.
*/
printEntry(e);
} else {
printEntry(e);
return;
}
}
}
}
/**
* Prints entry information.
*/
if (vflag) {
}
} else {
}
}
/**
* Prints usage message.
*/
void usageError() {
}
/**
* A fatal exception has been caught. No recovery possible
*/
e.printStackTrace();
}
/**
* A fatal condition has been detected; message is "s".
* No recovery possible
*/
}
/**
* Print an output message; like verbose output and the like
*/
}
/**
* Print an error mesage; like something is broken
*/
}
/**
* Main routine to start program.
*/
}
/**
* An OutputStream that doesn't send its output anywhere, (but could).
* It's here to find the CRC32 of an input file, necessary for STORED
* mode in ZIP.
*/
long n = 0;
CRC32OutputStream() {}
n++;
}
n += len;
}
/**
* Updates a ZipEntry which describes the data read by this
* output stream, in STORED mode.
*/
e.setSize(n);
}
}
}