15ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski/* 25ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * Copyright (C) 2016 The Android Open Source Project 35ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * 45ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * Licensed under the Apache License, Version 2.0 (the "License"); 55ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * you may not use this file except in compliance with the License. 65ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * You may obtain a copy of the License at 75ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * 85ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * http://www.apache.org/licenses/LICENSE-2.0 95ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * 105ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * Unless required by applicable law or agreed to in writing, software 115ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * distributed under the License is distributed on an "AS IS" BASIS, 125ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * See the License for the specific language governing permissions and 145ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * limitations under the License. 155ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski */ 165ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 175ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskipackage com.android.documentsui.archives; 185ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 195ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport android.os.ProxyFileDescriptorCallback; 205ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport android.system.ErrnoException; 215ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport android.system.OsConstants; 225ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport android.util.Log; 235ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport android.util.jar.StrictJarFile; 245ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 255ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport java.io.IOException; 265ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport java.io.InputStream; 275ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport java.util.zip.ZipEntry; 285ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 295ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskiimport libcore.io.IoUtils; 305ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 315ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski/** 325ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski * Provides a backend for a seekable file descriptors for files in archives. 335ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski */ 345ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewskipublic class Proxy extends ProxyFileDescriptorCallback { 355ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski private final StrictJarFile mFile; 365ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski private final ZipEntry mEntry; 375ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski private InputStream mInputStream = null; 385ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski private long mOffset = 0; 395ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 405ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski Proxy(StrictJarFile file, ZipEntry entry) throws IOException { 415ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski mFile = file; 425ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski mEntry = entry; 435ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski recreateInputStream(); 445ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 455ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 465ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski @Override 475ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski public long onGetSize() throws ErrnoException { 485ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski return mEntry.getSize(); 495ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 505ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 515ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski @Override 525ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski public int onRead(long offset, int size, byte[] data) throws ErrnoException { 535ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski // TODO: Add a ring buffer to prevent expensive seeks. 545ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski if (offset < mOffset) { 555ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski try { 565ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski recreateInputStream(); 575ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } catch (IOException e) { 585ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski throw new ErrnoException("onRead", OsConstants.EIO); 595ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 605ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 615ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 625ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski while (mOffset < offset) { 635ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski try { 645ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski mOffset += mInputStream.skip(offset - mOffset); 655ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } catch (IOException e) { 665ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski throw new ErrnoException("onRead", OsConstants.EIO); 675ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 685ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 695ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 705ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski int remainingSize = size; 715ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski while (remainingSize > 0) { 725ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski try { 735ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski int bytes = mInputStream.read(data, size - remainingSize, remainingSize); 745ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski if (bytes <= 0) { 755ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski return size - remainingSize; 765ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 775ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski remainingSize -= bytes; 785ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski mOffset += bytes; 795ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } catch (IOException e) { 805ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski throw new ErrnoException("onRead", OsConstants.EIO); 815ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 825ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 835ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 845ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski return size - remainingSize; 855ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 865ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 875ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski @Override public void onRelease() { 885ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski IoUtils.closeQuietly(mInputStream); 895ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 905ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski 915ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski private void recreateInputStream() throws IOException { 925ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski IoUtils.closeQuietly(mInputStream); 935ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski mInputStream = mFile.getInputStream(mEntry); 945ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski mOffset = 0; 955ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski } 965ed698344f36d5ce7c342033e7c8fe370d1c9c69Tomasz Mikolajewski} 97