• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.documentsui.archives;
18 
19 import android.os.ProxyFileDescriptorCallback;
20 import android.system.ErrnoException;
21 import android.system.OsConstants;
22 import android.util.Log;
23 import android.util.jar.StrictJarFile;
24 
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.util.zip.ZipEntry;
28 
29 import libcore.io.IoUtils;
30 
31 /**
32  * Provides a backend for a seekable file descriptors for files in archives.
33  */
34 public class Proxy extends ProxyFileDescriptorCallback {
35     private final StrictJarFile mFile;
36     private final ZipEntry mEntry;
37     private InputStream mInputStream = null;
38     private long mOffset = 0;
39 
Proxy(StrictJarFile file, ZipEntry entry)40     Proxy(StrictJarFile file, ZipEntry entry) throws IOException {
41         mFile = file;
42         mEntry = entry;
43         recreateInputStream();
44     }
45 
46     @Override
onGetSize()47     public long onGetSize() throws ErrnoException {
48         return mEntry.getSize();
49     }
50 
51     @Override
onRead(long offset, int size, byte[] data)52     public int onRead(long offset, int size, byte[] data) throws ErrnoException {
53         // TODO: Add a ring buffer to prevent expensive seeks.
54         if (offset < mOffset) {
55             try {
56                 recreateInputStream();
57             } catch (IOException e) {
58                 throw new ErrnoException("onRead", OsConstants.EIO);
59             }
60         }
61 
62         while (mOffset < offset) {
63             try {
64                 mOffset +=  mInputStream.skip(offset - mOffset);
65             } catch (IOException e) {
66                 throw new ErrnoException("onRead", OsConstants.EIO);
67             }
68         }
69 
70         int remainingSize = size;
71         while (remainingSize > 0) {
72             try {
73                 int bytes = mInputStream.read(data, size - remainingSize, remainingSize);
74                 if (bytes <= 0) {
75                     return size - remainingSize;
76                 }
77                 remainingSize -= bytes;
78                 mOffset += bytes;
79             } catch (IOException e) {
80                 throw new ErrnoException("onRead", OsConstants.EIO);
81             }
82         }
83 
84         return size - remainingSize;
85    }
86 
onRelease()87     @Override public void onRelease() {
88         IoUtils.closeQuietly(mInputStream);
89     }
90 
recreateInputStream()91     private void recreateInputStream() throws IOException {
92         IoUtils.closeQuietly(mInputStream);
93         mInputStream = mFile.getInputStream(mEntry);
94         mOffset = 0;
95     }
96 }
97