blob: 7d46710b2c5847db9adac7016909f34e32e6dfff [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
19import android.os.Parcel;
20import android.os.ParcelFileDescriptor;
21import android.os.Parcelable;
22
23import java.io.FileDescriptor;
24import java.io.FileInputStream;
25import java.io.FileOutputStream;
26import java.io.IOException;
27
28/**
29 * File descriptor of an entry in the AssetManager. This provides your own
30 * opened FileDescriptor that can be used to read the data, as well as the
31 * offset and length of that entry's data in the file.
32 */
33public class AssetFileDescriptor implements Parcelable {
34 /**
35 * Length used with {@link #AssetFileDescriptor(ParcelFileDescriptor, long, long)}
36 * and {@link #getDeclaredLength} when a length has not been declared. This means
37 * the data extends to the end of the file.
38 */
39 public static final long UNKNOWN_LENGTH = -1;
40
41 private final ParcelFileDescriptor mFd;
42 private final long mStartOffset;
43 private final long mLength;
44
45 /**
46 * Create a new AssetFileDescriptor from the given values.
47 * @param fd The underlying file descriptor.
48 * @param startOffset The location within the file that the asset starts.
49 * This must be 0 if length is UNKNOWN_LENGTH.
50 * @param length The number of bytes of the asset, or
Bjorn Bringerta006b4722010-04-14 14:43:26 +010051 * {@link #UNKNOWN_LENGTH} if it extends to the end of the file.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052 */
53 public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset,
54 long length) {
Jeff Brownaf67fc62012-05-08 14:29:09 -070055 if (fd == null) {
56 throw new IllegalArgumentException("fd must not be null");
57 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 if (length < 0 && startOffset != 0) {
59 throw new IllegalArgumentException(
60 "startOffset must be 0 when using UNKNOWN_LENGTH");
61 }
62 mFd = fd;
63 mStartOffset = startOffset;
64 mLength = length;
65 }
66
67 /**
68 * The AssetFileDescriptor contains its own ParcelFileDescriptor, which
69 * in addition to the normal FileDescriptor object also allows you to close
70 * the descriptor when you are done with it.
71 */
72 public ParcelFileDescriptor getParcelFileDescriptor() {
73 return mFd;
74 }
75
76 /**
77 * Returns the FileDescriptor that can be used to read the data in the
78 * file.
79 */
80 public FileDescriptor getFileDescriptor() {
81 return mFd.getFileDescriptor();
82 }
83
84 /**
85 * Returns the byte offset where this asset entry's data starts.
86 */
87 public long getStartOffset() {
88 return mStartOffset;
89 }
90
91 /**
92 * Returns the total number of bytes of this asset entry's data. May be
93 * {@link #UNKNOWN_LENGTH} if the asset extends to the end of the file.
94 * If the AssetFileDescriptor was constructed with {@link #UNKNOWN_LENGTH},
95 * this will use {@link ParcelFileDescriptor#getStatSize()
96 * ParcelFileDescriptor.getStatSize()} to find the total size of the file,
97 * returning that number if found or {@link #UNKNOWN_LENGTH} if it could
98 * not be determined.
99 *
100 * @see #getDeclaredLength()
101 */
102 public long getLength() {
103 if (mLength >= 0) {
104 return mLength;
105 }
106 long len = mFd.getStatSize();
107 return len >= 0 ? len : UNKNOWN_LENGTH;
108 }
109
110 /**
111 * Return the actual number of bytes that were declared when the
112 * AssetFileDescriptor was constructed. Will be
113 * {@link #UNKNOWN_LENGTH} if the length was not declared, meaning data
114 * should be read to the end of the file.
115 *
116 * @see #getDeclaredLength()
117 */
118 public long getDeclaredLength() {
119 return mLength;
120 }
121
122 /**
123 * Convenience for calling <code>getParcelFileDescriptor().close()</code>.
124 */
125 public void close() throws IOException {
126 mFd.close();
127 }
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100128
129 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 * Create and return a new auto-close input stream for this asset. This
131 * will either return a full asset {@link AutoCloseInputStream}, or
132 * an underlying {@link ParcelFileDescriptor.AutoCloseInputStream
133 * ParcelFileDescriptor.AutoCloseInputStream} depending on whether the
134 * the object represents a complete file or sub-section of a file. You
135 * should only call this once for a particular asset.
136 */
137 public FileInputStream createInputStream() throws IOException {
138 if (mLength < 0) {
139 return new ParcelFileDescriptor.AutoCloseInputStream(mFd);
140 }
141 return new AutoCloseInputStream(this);
142 }
143
144 /**
145 * Create and return a new auto-close output stream for this asset. This
146 * will either return a full asset {@link AutoCloseOutputStream}, or
147 * an underlying {@link ParcelFileDescriptor.AutoCloseOutputStream
148 * ParcelFileDescriptor.AutoCloseOutputStream} depending on whether the
149 * the object represents a complete file or sub-section of a file. You
150 * should only call this once for a particular asset.
151 */
152 public FileOutputStream createOutputStream() throws IOException {
153 if (mLength < 0) {
154 return new ParcelFileDescriptor.AutoCloseOutputStream(mFd);
155 }
156 return new AutoCloseOutputStream(this);
157 }
158
159 @Override
160 public String toString() {
161 return "{AssetFileDescriptor: " + mFd
162 + " start=" + mStartOffset + " len=" + mLength + "}";
163 }
164
165 /**
166 * An InputStream you can create on a ParcelFileDescriptor, which will
167 * take care of calling {@link ParcelFileDescriptor#close
168 * ParcelFileDescritor.close()} for you when the stream is closed.
169 */
170 public static class AutoCloseInputStream
171 extends ParcelFileDescriptor.AutoCloseInputStream {
172 private long mRemaining;
173
174 public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException {
175 super(fd.getParcelFileDescriptor());
176 super.skip(fd.getStartOffset());
177 mRemaining = (int)fd.getLength();
178 }
179
180 @Override
181 public int available() throws IOException {
182 return mRemaining >= 0
183 ? (mRemaining < 0x7fffffff ? (int)mRemaining : 0x7fffffff)
184 : super.available();
185 }
186
187 @Override
188 public int read() throws IOException {
Bjorn Bringert21279932010-12-02 11:34:28 +0000189 byte[] buffer = new byte[1];
190 int result = read(buffer, 0, 1);
191 return result == -1 ? -1 : buffer[0] & 0xff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 }
193
194 @Override
195 public int read(byte[] buffer, int offset, int count) throws IOException {
196 if (mRemaining >= 0) {
197 if (mRemaining == 0) return -1;
198 if (count > mRemaining) count = (int)mRemaining;
199 int res = super.read(buffer, offset, count);
200 if (res >= 0) mRemaining -= res;
201 return res;
202 }
203
204 return super.read(buffer, offset, count);
205 }
206
207 @Override
208 public int read(byte[] buffer) throws IOException {
Bjorn Bringert21279932010-12-02 11:34:28 +0000209 return read(buffer, 0, buffer.length);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 }
211
212 @Override
213 public long skip(long count) throws IOException {
214 if (mRemaining >= 0) {
215 if (mRemaining == 0) return -1;
216 if (count > mRemaining) count = mRemaining;
217 long res = super.skip(count);
218 if (res >= 0) mRemaining -= res;
219 return res;
220 }
221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 return super.skip(count);
223 }
224
225 @Override
226 public void mark(int readlimit) {
227 if (mRemaining >= 0) {
228 // Not supported.
229 return;
230 }
231 super.mark(readlimit);
232 }
233
234 @Override
235 public boolean markSupported() {
236 if (mRemaining >= 0) {
237 return false;
238 }
239 return super.markSupported();
240 }
241
242 @Override
243 public synchronized void reset() throws IOException {
244 if (mRemaining >= 0) {
245 // Not supported.
246 return;
247 }
248 super.reset();
249 }
250 }
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100251
252 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 * An OutputStream you can create on a ParcelFileDescriptor, which will
254 * take care of calling {@link ParcelFileDescriptor#close
255 * ParcelFileDescritor.close()} for you when the stream is closed.
256 */
257 public static class AutoCloseOutputStream
258 extends ParcelFileDescriptor.AutoCloseOutputStream {
259 private long mRemaining;
260
261 public AutoCloseOutputStream(AssetFileDescriptor fd) throws IOException {
262 super(fd.getParcelFileDescriptor());
263 if (fd.getParcelFileDescriptor().seekTo(fd.getStartOffset()) < 0) {
264 throw new IOException("Unable to seek");
265 }
266 mRemaining = (int)fd.getLength();
267 }
268
269 @Override
270 public void write(byte[] buffer, int offset, int count) throws IOException {
271 if (mRemaining >= 0) {
272 if (mRemaining == 0) return;
273 if (count > mRemaining) count = (int)mRemaining;
274 super.write(buffer, offset, count);
275 mRemaining -= count;
276 return;
277 }
278
279 super.write(buffer, offset, count);
280 }
281
282 @Override
283 public void write(byte[] buffer) throws IOException {
284 if (mRemaining >= 0) {
285 if (mRemaining == 0) return;
286 int count = buffer.length;
287 if (count > mRemaining) count = (int)mRemaining;
288 super.write(buffer);
289 mRemaining -= count;
290 return;
291 }
292
293 super.write(buffer);
294 }
295
296 @Override
297 public void write(int oneByte) throws IOException {
298 if (mRemaining >= 0) {
299 if (mRemaining == 0) return;
300 super.write(oneByte);
301 mRemaining--;
302 return;
303 }
304
305 super.write(oneByte);
306 }
307 }
308
309
310 /* Parcelable interface */
311 public int describeContents() {
312 return mFd.describeContents();
313 }
314
315 public void writeToParcel(Parcel out, int flags) {
316 mFd.writeToParcel(out, flags);
317 out.writeLong(mStartOffset);
318 out.writeLong(mLength);
319 }
320
321 AssetFileDescriptor(Parcel src) {
322 mFd = ParcelFileDescriptor.CREATOR.createFromParcel(src);
323 mStartOffset = src.readLong();
324 mLength = src.readLong();
325 }
326
327 public static final Parcelable.Creator<AssetFileDescriptor> CREATOR
328 = new Parcelable.Creator<AssetFileDescriptor>() {
329 public AssetFileDescriptor createFromParcel(Parcel in) {
330 return new AssetFileDescriptor(in);
331 }
332 public AssetFileDescriptor[] newArray(int size) {
333 return new AssetFileDescriptor[size];
334 }
335 };
Bjorn Bringert963cd0062009-05-29 14:05:12 +0100336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337}