001/* 002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * matic 018 */ 019package org.nuxeo.ecm.automation.jaxrs.io; 020 021import java.io.BufferedInputStream; 022import java.io.File; 023import java.io.FileInputStream; 024import java.io.IOException; 025import java.io.InputStream; 026 027import javax.mail.internet.SharedInputStream; 028 029public class SharedFileInputStream extends InputStream implements SharedInputStream { 030 031 protected final InputStream in; 032 033 protected final SharedFileInputStream parent; 034 035 protected final File file; 036 037 protected final long length; 038 039 protected final long start; 040 041 protected long current; 042 043 protected long marked; 044 045 public SharedFileInputStream(File file) throws IOException { 046 this.in = new BufferedInputStream(new FileInputStream(file)); 047 this.parent = null; 048 this.file = file; 049 this.start = 0; 050 this.length = file.length(); 051 } 052 053 protected SharedFileInputStream(SharedFileInputStream parent, long start, long len) throws IOException { 054 this.in = new BufferedInputStream(new FileInputStream(parent.file)); 055 this.parent = parent; 056 this.file = parent.file; 057 this.start = start; 058 this.length = len; 059 skip(this.in, start); 060 } 061 062 /** Skip reliably; this is more efficient than IOUtils.skip which calls read(). */ 063 protected static void skip(InputStream in, long n) throws IOException { 064 long todo = n; 065 while (todo > 0) { 066 long skipped = in.skip(todo); 067 if (skipped <= 0) { 068 throw new IOException("Failed to skip " + n + " bytes"); 069 } 070 todo -= skipped; 071 } 072 } 073 074 @Override 075 public long getPosition() { 076 return this.current; 077 } 078 079 @Override 080 public SharedFileInputStream newStream(long start, long end) { 081 try { 082 long length; 083 if (end == -1L) { 084 length = this.length - start; 085 } else { 086 length = end - start; 087 } 088 return new SharedFileInputStream(this, this.start + start, length); 089 } catch (IOException localIOException) { 090 throw new IllegalStateException("unable to create shared stream: " + localIOException); 091 } 092 } 093 094 @Override 095 public int read(byte[] buffer) throws IOException { 096 return read(buffer, 0, buffer.length); 097 } 098 099 @Override 100 public int read(byte[] buffer, int offset, int len) throws IOException { 101 int i = 0; 102 if (len == 0) 103 return 0; 104 while (i < len) { 105 int j = read(); 106 if (j < 0) 107 break; 108 buffer[(offset + i)] = (byte) j; 109 ++i; 110 } 111 if (i == 0) 112 return -1; 113 return i; 114 } 115 116 @Override 117 public int read() throws IOException { 118 if (this.current == this.length) 119 return -1; 120 this.current += 1L; 121 return this.in.read(); 122 } 123 124 @Override 125 public boolean markSupported() { 126 return true; 127 } 128 129 @Override 130 public long skip(long len) throws IOException { 131 for (int count = 0; count < len; ++count) { 132 if (read() < 0) 133 return count; 134 } 135 return len; 136 } 137 138 @Override 139 public void mark(int limit) { 140 this.marked = this.current; 141 this.in.mark(limit); 142 } 143 144 @Override 145 public void reset() throws IOException { 146 current = marked; 147 in.reset(); 148 } 149 150 public SharedFileInputStream getRoot() { 151 if (parent != null) 152 return parent.getRoot(); 153 return this; 154 } 155}