1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.build.apkzlib.zip.utils; 18 19 import com.google.common.hash.HashCode; 20 import com.google.common.hash.HashFunction; 21 import com.google.common.io.ByteProcessor; 22 import com.google.common.io.ByteSink; 23 import com.google.common.io.ByteSource; 24 import com.google.common.io.CharSource; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.OutputStream; 28 import java.nio.charset.Charset; 29 import javax.annotation.Nonnull; 30 import javax.annotation.Nullable; 31 32 /** 33 * Closeable byte source that delegates to another byte source. 34 */ 35 public class CloseableDelegateByteSource extends CloseableByteSource { 36 37 /** 38 * The byte source we delegate all operations to. {@code null} if disposed. 39 */ 40 @Nullable 41 private ByteSource inner; 42 43 /** 44 * Size of the byte source. This is the same as {@code inner.size()} (when {@code inner} 45 * is not {@code null}), but we keep it separate to avoid calling {@code inner.size()} 46 * because it might throw {@code IOException}. 47 */ 48 private final long mSize; 49 50 /** 51 * Creates a new byte source. 52 * 53 * @param inner the inner byte source 54 * @param size the size of the source 55 */ CloseableDelegateByteSource(@onnull ByteSource inner, long size)56 public CloseableDelegateByteSource(@Nonnull ByteSource inner, long size) { 57 this.inner = inner; 58 mSize = size; 59 } 60 61 /** 62 * Obtains the inner byte source. Will throw an exception if the inner by byte source has 63 * been disposed of. 64 * 65 * @return the inner byte source 66 */ 67 @Nonnull get()68 private synchronized ByteSource get() { 69 if (inner == null) { 70 throw new ByteSourceDisposedException(); 71 } 72 73 return inner; 74 } 75 76 /** 77 * Mark the byte source as disposed. 78 */ 79 @Override innerClose()80 protected synchronized void innerClose() throws IOException { 81 if (inner == null) { 82 return; 83 } 84 85 inner = null; 86 } 87 88 /** 89 * Obtains the size of this byte source. Equivalent to {@link #size()} but not throwing 90 * {@code IOException}. 91 * 92 * @return the size of the byte source 93 */ sizeNoException()94 public long sizeNoException() { 95 return mSize; 96 } 97 98 @Override asCharSource(Charset charset)99 public CharSource asCharSource(Charset charset) { 100 return get().asCharSource(charset); 101 } 102 103 @Override openBufferedStream()104 public InputStream openBufferedStream() throws IOException { 105 return get().openBufferedStream(); 106 } 107 108 @Override slice(long offset, long length)109 public ByteSource slice(long offset, long length) { 110 return get().slice(offset, length); 111 } 112 113 @Override isEmpty()114 public boolean isEmpty() throws IOException { 115 return get().isEmpty(); 116 } 117 118 @Override size()119 public long size() throws IOException { 120 return get().size(); 121 } 122 123 @Override copyTo(@onnull OutputStream output)124 public long copyTo(@Nonnull OutputStream output) throws IOException { 125 return get().copyTo(output); 126 } 127 128 @Override copyTo(@onnull ByteSink sink)129 public long copyTo(@Nonnull ByteSink sink) throws IOException { 130 return get().copyTo(sink); 131 } 132 133 @Override read()134 public byte[] read() throws IOException { 135 return get().read(); 136 } 137 138 @Override read(@onnull ByteProcessor<T> processor)139 public <T> T read(@Nonnull ByteProcessor<T> processor) throws IOException { 140 return get().read(processor); 141 } 142 143 @Override hash(HashFunction hashFunction)144 public HashCode hash(HashFunction hashFunction) throws IOException { 145 return get().hash(hashFunction); 146 } 147 148 @Override contentEquals(@onnull ByteSource other)149 public boolean contentEquals(@Nonnull ByteSource other) throws IOException { 150 return get().contentEquals(other); 151 } 152 153 @Override openStream()154 public InputStream openStream() throws IOException { 155 return get().openStream(); 156 } 157 158 /** 159 * Exception thrown when trying to use a byte source that has been disposed. 160 */ 161 private static class ByteSourceDisposedException extends RuntimeException { 162 163 /** 164 * Creates a new exception. 165 */ ByteSourceDisposedException()166 private ByteSourceDisposedException() { 167 super("Byte source was created by a ByteTracker and is now disposed. If you see " 168 + "this message, then there is a bug."); 169 } 170 } 171 } 172