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