blob: b6cbf08e5e78b63bf568da2ec9f479bdcfe36a45 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package android.content.res;
18
Mathew Inwood5c0d3542018-08-14 13:54:31 +010019import android.annotation.UnsupportedAppUsage;
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070020import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.os.Parcel;
22import android.os.ParcelFileDescriptor;
23import android.os.Parcelable;
24
Jeff Sharkey32559e12013-04-29 11:19:18 -070025import java.io.Closeable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import java.io.FileDescriptor;
27import java.io.FileInputStream;
28import java.io.FileOutputStream;
29import java.io.IOException;
30
31/**
32 * File descriptor of an entry in the AssetManager. This provides your own
33 * opened FileDescriptor that can be used to read the data, as well as the
34 * offset and length of that entry's data in the file.
35 */
Jeff Sharkey32559e12013-04-29 11:19:18 -070036public class AssetFileDescriptor implements Parcelable, Closeable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 /**
38 * Length used with {@link #AssetFileDescriptor(ParcelFileDescriptor, long, long)}
39 * and {@link #getDeclaredLength} when a length has not been declared. This means
40 * the data extends to the end of the file.
41 */
42 public static final long UNKNOWN_LENGTH = -1;
43
Mathew Inwood5c0d3542018-08-14 13:54:31 +010044 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 private final ParcelFileDescriptor mFd;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010046 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 private final long mStartOffset;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010048 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 private final long mLength;
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070050 private final Bundle mExtras;
51
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 /**
53 * Create a new AssetFileDescriptor from the given values.
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070054 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 * @param fd The underlying file descriptor.
56 * @param startOffset The location within the file that the asset starts.
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070057 * This must be 0 if length is UNKNOWN_LENGTH.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 * @param length The number of bytes of the asset, or
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070059 * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 */
61 public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
62 long length) {
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070063 this(fd, startOffset, length, null);
64 }
65
66 /**
67 * Create a new AssetFileDescriptor from the given values.
68 *
69 * @param fd The underlying file descriptor.
70 * @param startOffset The location within the file that the asset starts.
71 * This must be 0 if length is UNKNOWN_LENGTH.
72 * @param length The number of bytes of the asset, or
73 * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
74 * @param extras additional details that can be used to interpret the
75 * underlying file descriptor. May be null.
76 */
77 public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
78 long length, Bundle extras) {
Jeff Brownaf67fc62012-05-08 14:29:09 -070079 if (fd == null) {
80 throw new IllegalArgumentException("fd must not be null");
81 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 if (length < 0 && startOffset != 0) {
83 throw new IllegalArgumentException(
84 "startOffset must be 0 when using UNKNOWN_LENGTH");
85 }
86 mFd = fd;
87 mStartOffset = startOffset;
88 mLength = length;
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070089 mExtras = extras;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 }
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -070091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 /**
93 * The AssetFileDescriptor contains its own ParcelFileDescriptor, which
94 * in addition to the normal FileDescriptor object also allows you to close
95 * the descriptor when you are done with it.
96 */
97 public ParcelFileDescriptor getParcelFileDescriptor() {
98 return mFd;
99 }
100
101 /**
102 * Returns the FileDescriptor that can be used to read the data in the
103 * file.
104 */
105 public FileDescriptor getFileDescriptor() {
106 return mFd.getFileDescriptor();
107 }
108
109 /**
110 * Returns the byte offset where this asset entry's data starts.
111 */
112 public long getStartOffset() {
113 return mStartOffset;
114 }
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700115
116 /**
117 * Returns any additional details that can be used to interpret the
118 * underlying file descriptor. May be null.
119 */
120 public Bundle getExtras() {
121 return mExtras;
122 }
123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
125 * Returns the total number of bytes of this asset entry's data. May be
126 * {@link #UNKNOWN_LENGTH} if the asset extends to the end of the file.
127 * If the AssetFileDescriptor was constructed with {@link #UNKNOWN_LENGTH},
128 * this will use {@link ParcelFileDescriptor#getStatSize()
129 * ParcelFileDescriptor.getStatSize()} to find the total size of the file,
130 * returning that number if found or {@link #UNKNOWN_LENGTH} if it could
131 * not be determined.
132 *
133 * @see #getDeclaredLength()
134 */
135 public long getLength() {
136 if (mLength >= 0) {
137 return mLength;
138 }
139 long len = mFd.getStatSize();
140 return len >= 0 ? len : UNKNOWN_LENGTH;
141 }
142
143 /**
144 * Return the actual number of bytes that were declared when the
145 * AssetFileDescriptor was constructed. Will be
146 * {@link #UNKNOWN_LENGTH} if the length was not declared, meaning data
147 * should be read to the end of the file.
148 *
149 * @see #getDeclaredLength()
150 */
151 public long getDeclaredLength() {
152 return mLength;
153 }
154
155 /**
156 * Convenience for calling <code>getParcelFileDescriptor().close()</code>.
157 */
Jeff Sharkey32559e12013-04-29 11:19:18 -0700158 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 public void close() throws IOException {
160 mFd.close();
161 }
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100162
163 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 * Create and return a new auto-close input stream for this asset. This
165 * will either return a full asset {@link AutoCloseInputStream}, or
166 * an underlying {@link ParcelFileDescriptor.AutoCloseInputStream
167 * ParcelFileDescriptor.AutoCloseInputStream} depending on whether the
168 * the object represents a complete file or sub-section of a file. You
169 * should only call this once for a particular asset.
170 */
171 public FileInputStream createInputStream() throws IOException {
172 if (mLength < 0) {
173 return new ParcelFileDescriptor.AutoCloseInputStream(mFd);
174 }
175 return new AutoCloseInputStream(this);
176 }
177
178 /**
179 * Create and return a new auto-close output stream for this asset. This
180 * will either return a full asset {@link AutoCloseOutputStream}, or
181 * an underlying {@link ParcelFileDescriptor.AutoCloseOutputStream
182 * ParcelFileDescriptor.AutoCloseOutputStream} depending on whether the
183 * the object represents a complete file or sub-section of a file. You
184 * should only call this once for a particular asset.
185 */
186 public FileOutputStream createOutputStream() throws IOException {
187 if (mLength < 0) {
188 return new ParcelFileDescriptor.AutoCloseOutputStream(mFd);
189 }
190 return new AutoCloseOutputStream(this);
191 }
192
193 @Override
194 public String toString() {
195 return "{AssetFileDescriptor: " + mFd
196 + " start=" + mStartOffset + " len=" + mLength + "}";
197 }
198
199 /**
200 * An InputStream you can create on a ParcelFileDescriptor, which will
201 * take care of calling {@link ParcelFileDescriptor#close
Jonathan Dormody1c7c4b22017-11-30 15:06:55 -0700202 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 */
204 public static class AutoCloseInputStream
205 extends ParcelFileDescriptor.AutoCloseInputStream {
206 private long mRemaining;
207
208 public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException {
209 super(fd.getParcelFileDescriptor());
210 super.skip(fd.getStartOffset());
211 mRemaining = (int)fd.getLength();
212 }
213
214 @Override
215 public int available() throws IOException {
216 return mRemaining >= 0
217 ? (mRemaining < 0x7fffffff ? (int)mRemaining : 0x7fffffff)
218 : super.available();
219 }
220
221 @Override
222 public int read() throws IOException {
Bjorn Bringert21279932010-12-02 11:34:28 +0000223 byte[] buffer = new byte[1];
224 int result = read(buffer, 0, 1);
225 return result == -1 ? -1 : buffer[0] & 0xff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 }
227
228 @Override
229 public int read(byte[] buffer, int offset, int count) throws IOException {
230 if (mRemaining >= 0) {
231 if (mRemaining == 0) return -1;
232 if (count > mRemaining) count = (int)mRemaining;
233 int res = super.read(buffer, offset, count);
234 if (res >= 0) mRemaining -= res;
235 return res;
236 }
237
238 return super.read(buffer, offset, count);
239 }
240
241 @Override
242 public int read(byte[] buffer) throws IOException {
Bjorn Bringert21279932010-12-02 11:34:28 +0000243 return read(buffer, 0, buffer.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 }
245
246 @Override
247 public long skip(long count) throws IOException {
248 if (mRemaining >= 0) {
249 if (mRemaining == 0) return -1;
250 if (count > mRemaining) count = mRemaining;
251 long res = super.skip(count);
252 if (res >= 0) mRemaining -= res;
253 return res;
254 }
255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 return super.skip(count);
257 }
258
259 @Override
260 public void mark(int readlimit) {
261 if (mRemaining >= 0) {
262 // Not supported.
263 return;
264 }
265 super.mark(readlimit);
266 }
267
268 @Override
269 public boolean markSupported() {
270 if (mRemaining >= 0) {
271 return false;
272 }
273 return super.markSupported();
274 }
275
276 @Override
277 public synchronized void reset() throws IOException {
278 if (mRemaining >= 0) {
279 // Not supported.
280 return;
281 }
282 super.reset();
283 }
284 }
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100285
286 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 * An OutputStream you can create on a ParcelFileDescriptor, which will
288 * take care of calling {@link ParcelFileDescriptor#close
Jonathan Dormody1c7c4b22017-11-30 15:06:55 -0700289 * ParcelFileDescriptor.close()} for you when the stream is closed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 */
291 public static class AutoCloseOutputStream
292 extends ParcelFileDescriptor.AutoCloseOutputStream {
293 private long mRemaining;
294
295 public AutoCloseOutputStream(AssetFileDescriptor fd) throws IOException {
296 super(fd.getParcelFileDescriptor());
297 if (fd.getParcelFileDescriptor().seekTo(fd.getStartOffset()) < 0) {
298 throw new IOException("Unable to seek");
299 }
300 mRemaining = (int)fd.getLength();
301 }
302
303 @Override
304 public void write(byte[] buffer, int offset, int count) throws IOException {
305 if (mRemaining >= 0) {
306 if (mRemaining == 0) return;
307 if (count > mRemaining) count = (int)mRemaining;
308 super.write(buffer, offset, count);
309 mRemaining -= count;
310 return;
311 }
312
313 super.write(buffer, offset, count);
314 }
315
316 @Override
317 public void write(byte[] buffer) throws IOException {
318 if (mRemaining >= 0) {
319 if (mRemaining == 0) return;
320 int count = buffer.length;
321 if (count > mRemaining) count = (int)mRemaining;
322 super.write(buffer);
323 mRemaining -= count;
324 return;
325 }
326
327 super.write(buffer);
328 }
329
330 @Override
331 public void write(int oneByte) throws IOException {
332 if (mRemaining >= 0) {
333 if (mRemaining == 0) return;
334 super.write(oneByte);
335 mRemaining--;
336 return;
337 }
338
339 super.write(oneByte);
340 }
341 }
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 /* Parcelable interface */
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700344 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 public int describeContents() {
346 return mFd.describeContents();
347 }
348
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700349 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 public void writeToParcel(Parcel out, int flags) {
351 mFd.writeToParcel(out, flags);
352 out.writeLong(mStartOffset);
353 out.writeLong(mLength);
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700354 if (mExtras != null) {
355 out.writeInt(1);
356 out.writeBundle(mExtras);
357 } else {
358 out.writeInt(0);
359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 }
361
362 AssetFileDescriptor(Parcel src) {
363 mFd = ParcelFileDescriptor.CREATOR.createFromParcel(src);
364 mStartOffset = src.readLong();
365 mLength = src.readLong();
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700366 if (src.readInt() != 0) {
367 mExtras = src.readBundle();
368 } else {
369 mExtras = null;
370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
Jeff Sharkeyc1c8f3f2013-10-14 14:57:33 -0700372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 public static final Parcelable.Creator<AssetFileDescriptor> CREATOR
374 = new Parcelable.Creator<AssetFileDescriptor>() {
375 public AssetFileDescriptor createFromParcel(Parcel in) {
376 return new AssetFileDescriptor(in);
377 }
378 public AssetFileDescriptor[] newArray(int size) {
379 return new AssetFileDescriptor[size];
380 }
381 };
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383}