-
CSR
-
Resolution: Withdrawn
-
P4
-
low
-
This change only adding new Constructors and keeps the old ones work as before. So set the risk to "low"
-
Java API
-
SE
Summary
Introduce new constructors of GZIPOutputStream to support adding optional flags/fields into the gzip file header.
Problem
As described in JDK-4890732 , the GZIPOutputStream does not support adding extra fields
, file name
and file comment
into the gzip header. And it is hard for programmer to achieve this target by simply extend GZIPOutputStream because the writeHeader() method is private and hence can not be override.
Per the gzip file specification RFC-1952 (https://tools.ietf.org/html/rfc1952), these optional flags/fields in gzip file header could help add extra information about the gzip file.
one example is the gziped heap dump file generated by jcmd jmap -dump
command, it adds file comment
in the header which describe the block size, so that the decompressor could specify proper block size for decompressing . (please refer comments in https://github.com/openjdk/jdk/blob/ff52f2989fd60ec8251eaf76f4c4b78f10d3e048/src/hotspot/share/services/heapDumperCompression.cpp#L127)
Solution
Add a class GZIPHeaderBuilder
and a record GZIPHeaderBuilder.GZIPHeaderData
to set and get gzip header data.
Users could use GZIPHeaderBuilder
to generate GZIPHeaderBuilder.GZIPHeaderData
with builder pattern.
Add two constructors of GZIPOutputStream:
public GZIPOutputStream(OutputStream out, int size, boolean syncFlush, GZIPHeaderBuilder.GZIPHeaderData gzipHeaderData)
and
public GZIPOutputStream(OutputStream out, GZIPHeaderBuilder.GZIPHeaderData gzipHeaderData)
Users could use them for the purpose of setting gzip header fields.
Specification
In summary, this CSR contains 4 kind of changes:
- Adds the definition of class GZIPHeaderBuilder's API for setting gzip header fields and generate header bytes.
- Adds the Record GZIPHeaderData inside GZIPHeaderBuilder, which includes header fields.
- Adds 2 new constructors in GZIPOutputStream to generate gzip data with specified header data.
- Adds 1 new API in GZIPInputStream to get the header data from the gzip data.
Defined API for added GZIPHeaderBuilder:
/**
* Creates a GZIP file header builder.
* Current only {@code Deflater.DEFLATED} compress method supportted.
*
* @since 18
*/
public GZIPHeaderBuilder()
/**
* Add extra field in GZIP file header.
* This method verifies the extra fileds layout per RFC-1952.
* See comments of {@code verifyExtraFieldLayout}
*
* @param extraFieldBytes The byte array of extra field.
* @return {@code this}
*
* @throws ZipException if extra field layout is incorrect.
*
* @since 18
*/
public GZIPHeaderBuilder withExtraFieldBytes(byte[] extraFieldBytes) throws ZipException
/**
* Add file name in GZIP file header.
*
* Per RFC-1952, the file name string should in ISO_8859-1 character set.
*
* @param filename The file name
* @return {@code this}
*
* @since 18
*/
public GZIPHeaderBuilder withFileName(String filename)
/**
* Add file comment in GZIP file header.
*
* Per RFC-1952, the file comment string should in ISO_8859-1 character set.
*
* @param fileComment The file comment
* @return {@code this}'
*
* @since 18
*/
public GZIPHeaderBuilder withFileComment(String fileComment)
/**
* Enable/Disable the CRC calculation of GZIP file header.
*
* @param calculateHeaderCRC if {@code true} the header data contains the lower 16 bytes of header CRC
* @return {@code this}
*
* @since 18
*/
public GZIPHeaderBuilder calculateHeaderCRC(boolean calculateHeaderCRC)
/**
* Generate the GZIP header data
* @return the {@code record} of GZIP header data.
*
* @throws ZipException If extra field size is out of range.
* Or if extra filed data layout is incorrect.
* @throws IllegalArgumentException If compress method is not {@code Deflater.DEFLATED}
* @since 18
*/
public GZIPHeaderData build() throws IOException
/**
* Creates GZIP header bytes with optional header members and compress method.
* Per RFC-1952:
* The filename and fileComment member should be String in
* LATIN-1 (ISO-8859-1) character set.
*
* A compliant compressor must produce files with correct ID1,
* ID2, CM, CRC32, and ISIZE, but may set all the other fields in
* the fixed-length part of the header to default values (255 for
* OS, 0 for all others). The compressor must set all reserved
* bits to zero.
*
* The XFL (extra Flags) is set to zero and OS is set to {@code OS_UNKNOWN (=255)}.
* The FTEXT flag is set to zero and MTIME is filled with 0.
*
* @param cm compress method,
* per RFC-1952, 0-7 are reserved, 8 denotes "deflate".
* at present only support {@code Deflater.DEFLATED}
*
* @param extraFieldBytes
* The byte array of extra filed, the generated header would calculate the
* byte[] size and fill it before the byte[] in header.
* @param filename the original file name in ISO-8859-1 character set
* @param fileComment the file comment in ISO_8859-1 character set.
*
* @return Bytes of header data generated.
*
* @throws ZipException If extra field size is out of range.
* Or if extra filed data layout is incorrect.
* @throws IllegalArgumentException If compress method is not {@code Deflater.DEFLATED}.
*
* @since 18
*/
public byte[] generateBytes(byte cm,
byte[] extraFieldBytes,
String filename,
String fileComment) throws IOException
The Record definition of GZIPHeaderBuilder.GZIPHeaderData :
/**
* This class implements the header of GZIP file which contains members defined
* in the RFC 1952 specification
*
* @since 18
*
*/
public record GZIPHeaderData (byte compressMethod, byte flags,
byte[] extraFieldBytes,
String filename,
String fileComment,
int headerCRC16,
byte[] headerBytes)
For GZIPOutputStream the specification of the added two constructors are as following:
/**
* Creates a new output stream with the specified buffer size,
* flush mode flags and header fields.
*
* @param out the output stream
* @param size the output buffer size
* @param syncFlush
* if {@code true} invocation of the inherited
* {@link DeflaterOutputStream#flush() flush()} method of
* this instance flushes the compressor with flush mode
* {@link Deflater#SYNC_FLUSH} before flushing the output
* stream, otherwise only flushes the output stream
* @param gzipHeaderData
* The header of Gzip file, contains header members defined
* in RFC 1952. if {@code null}, use default header data.
*
* @throws IOException If an I/O error has occurred.
* @throws IllegalArgumentException if {@code size <= 0}
*
* @since 18
*/
public GZIPOutputStream(OutputStream out,
int size,
boolean syncFlush,
GZIPHeaderBuilder.GZIPHeaderData gzipHeaderData)
throws IOException
and:
/**
* Creates a new output stream with the specified flags.
*
* @param out the output stream
* @param gzipHeaderData
* The header of Gzip file, contains header members defined
* in RFC 1952. if {@code null}, use default header data.
* @throws IOException If an I/O error has occurred.
* @throws IllegalArgumentException if {@code size <= 0}
*
* @since 18
*/
public GZIPOutputStream(OutputStream out,
GZIPHeaderBuilder.GZIPHeaderData gzipHeaderData)
throws IOException
For GInputOutputStream the specification of the added method is as following:
/**
* Retures gzip header data
* @return header data
*/
public GZIPHeaderBuilder.GZIPHeaderData headerData() {
return headerData;
}
- csr of
-
JDK-4890732 GZIPOutputStream doesn't support optional GZIP fields
-
- In Progress
-