161 lines
4.9 KiB
Java
161 lines
4.9 KiB
Java
/* GENERATED SOURCE. DO NOT MODIFY. */
|
|
/*
|
|
* Copyright (C) 2014 Square, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package com.android.okhttp.okio;
|
|
|
|
import java.io.IOException;
|
|
import java.util.zip.Deflater;
|
|
|
|
import static com.android.okhttp.okio.Util.checkOffsetAndCount;
|
|
|
|
/**
|
|
* A sink that uses <a href="http://tools.ietf.org/html/rfc1951">DEFLATE</a> to
|
|
* compress data written to another source.
|
|
*
|
|
* <h3>Sync flush</h3>
|
|
* Aggressive flushing of this stream may result in reduced compression. Each
|
|
* call to {@link #flush} immediately compresses all currently-buffered data;
|
|
* this early compression may be less effective than compression performed
|
|
* without flushing.
|
|
*
|
|
* <p>This is equivalent to using {@link Deflater} with the sync flush option.
|
|
* This class does not offer any partial flush mechanism. For best performance,
|
|
* only call {@link #flush} when application behavior requires it.
|
|
* @hide This class is not part of the Android public SDK API
|
|
*/
|
|
public final class DeflaterSink implements Sink {
|
|
private final BufferedSink sink;
|
|
private final Deflater deflater;
|
|
private boolean closed;
|
|
|
|
public DeflaterSink(Sink sink, Deflater deflater) {
|
|
this(Okio.buffer(sink), deflater);
|
|
}
|
|
|
|
/**
|
|
* This package-private constructor shares a buffer with its trusted caller.
|
|
* In general we can't share a BufferedSource because the deflater holds input
|
|
* bytes until they are inflated.
|
|
*/
|
|
DeflaterSink(BufferedSink sink, Deflater deflater) {
|
|
if (sink == null) throw new IllegalArgumentException("source == null");
|
|
if (deflater == null) throw new IllegalArgumentException("inflater == null");
|
|
this.sink = sink;
|
|
this.deflater = deflater;
|
|
}
|
|
|
|
@Override public void write(Buffer source, long byteCount)
|
|
throws IOException {
|
|
checkOffsetAndCount(source.size, 0, byteCount);
|
|
while (byteCount > 0) {
|
|
// Share bytes from the head segment of 'source' with the deflater.
|
|
Segment head = source.head;
|
|
int toDeflate = (int) Math.min(byteCount, head.limit - head.pos);
|
|
deflater.setInput(head.data, head.pos, toDeflate);
|
|
|
|
// Deflate those bytes into sink.
|
|
deflate(false);
|
|
|
|
// Mark those bytes as read.
|
|
source.size -= toDeflate;
|
|
head.pos += toDeflate;
|
|
if (head.pos == head.limit) {
|
|
source.head = head.pop();
|
|
SegmentPool.recycle(head);
|
|
}
|
|
|
|
byteCount -= toDeflate;
|
|
}
|
|
}
|
|
|
|
// ANDROID-BEGIN
|
|
// @IgnoreJRERequirement
|
|
// ANDROID-END
|
|
private void deflate(boolean syncFlush) throws IOException {
|
|
Buffer buffer = sink.buffer();
|
|
while (true) {
|
|
Segment s = buffer.writableSegment(1);
|
|
|
|
// The 4-parameter overload of deflate() doesn't exist in the RI until
|
|
// Java 1.7, and is public (although with @hide) on Android since 2.3.
|
|
// The @hide tag means that this code won't compile against the Android
|
|
// 2.3 SDK, but it will run fine there.
|
|
int deflated = syncFlush
|
|
? deflater.deflate(s.data, s.limit, Segment.SIZE - s.limit, Deflater.SYNC_FLUSH)
|
|
: deflater.deflate(s.data, s.limit, Segment.SIZE - s.limit);
|
|
|
|
if (deflated > 0) {
|
|
s.limit += deflated;
|
|
buffer.size += deflated;
|
|
sink.emitCompleteSegments();
|
|
} else if (deflater.needsInput()) {
|
|
if (s.pos == s.limit) {
|
|
// We allocated a tail segment, but didn't end up needing it. Recycle!
|
|
buffer.head = s.pop();
|
|
SegmentPool.recycle(s);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override public void flush() throws IOException {
|
|
deflate(true);
|
|
sink.flush();
|
|
}
|
|
|
|
void finishDeflate() throws IOException {
|
|
deflater.finish();
|
|
deflate(false);
|
|
}
|
|
|
|
@Override public void close() throws IOException {
|
|
if (closed) return;
|
|
|
|
// Emit deflated data to the underlying sink. If this fails, we still need
|
|
// to close the deflater and the sink; otherwise we risk leaking resources.
|
|
Throwable thrown = null;
|
|
try {
|
|
finishDeflate();
|
|
} catch (Throwable e) {
|
|
thrown = e;
|
|
}
|
|
|
|
try {
|
|
deflater.end();
|
|
} catch (Throwable e) {
|
|
if (thrown == null) thrown = e;
|
|
}
|
|
|
|
try {
|
|
sink.close();
|
|
} catch (Throwable e) {
|
|
if (thrown == null) thrown = e;
|
|
}
|
|
closed = true;
|
|
|
|
if (thrown != null) Util.sneakyRethrow(thrown);
|
|
}
|
|
|
|
@Override public Timeout timeout() {
|
|
return sink.timeout();
|
|
}
|
|
|
|
@Override public String toString() {
|
|
return "DeflaterSink(" + sink + ")";
|
|
}
|
|
}
|