xref: /aosp_15_r20/external/javassist/src/main/javassist/ClassPoolTail.java (revision f1fbf3c2ab775ce834e0af96b7a85bdc7a0eac65)
1*f1fbf3c2SXin Li /*
2*f1fbf3c2SXin Li  * Javassist, a Java-bytecode translator toolkit.
3*f1fbf3c2SXin Li  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4*f1fbf3c2SXin Li  *
5*f1fbf3c2SXin Li  * The contents of this file are subject to the Mozilla Public License Version
6*f1fbf3c2SXin Li  * 1.1 (the "License"); you may not use this file except in compliance with
7*f1fbf3c2SXin Li  * the License.  Alternatively, the contents of this file may be used under
8*f1fbf3c2SXin Li  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9*f1fbf3c2SXin Li  * or the Apache License Version 2.0.
10*f1fbf3c2SXin Li  *
11*f1fbf3c2SXin Li  * Software distributed under the License is distributed on an "AS IS" basis,
12*f1fbf3c2SXin Li  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13*f1fbf3c2SXin Li  * for the specific language governing rights and limitations under the
14*f1fbf3c2SXin Li  * License.
15*f1fbf3c2SXin Li  */
16*f1fbf3c2SXin Li 
17*f1fbf3c2SXin Li package javassist;
18*f1fbf3c2SXin Li 
19*f1fbf3c2SXin Li import java.io.File;
20*f1fbf3c2SXin Li import java.io.FileInputStream;
21*f1fbf3c2SXin Li import java.io.FileNotFoundException;
22*f1fbf3c2SXin Li import java.io.FilenameFilter;
23*f1fbf3c2SXin Li import java.io.IOException;
24*f1fbf3c2SXin Li import java.io.InputStream;
25*f1fbf3c2SXin Li import java.io.OutputStream;
26*f1fbf3c2SXin Li import java.net.MalformedURLException;
27*f1fbf3c2SXin Li import java.net.URL;
28*f1fbf3c2SXin Li import java.util.ArrayList;
29*f1fbf3c2SXin Li import java.util.Collections;
30*f1fbf3c2SXin Li import java.util.List;
31*f1fbf3c2SXin Li import java.util.jar.JarEntry;
32*f1fbf3c2SXin Li import java.util.jar.JarFile;
33*f1fbf3c2SXin Li 
34*f1fbf3c2SXin Li final class ClassPathList {
35*f1fbf3c2SXin Li     ClassPathList next;
36*f1fbf3c2SXin Li     ClassPath path;
37*f1fbf3c2SXin Li 
ClassPathList(ClassPath p, ClassPathList n)38*f1fbf3c2SXin Li     ClassPathList(ClassPath p, ClassPathList n) {
39*f1fbf3c2SXin Li         next = n;
40*f1fbf3c2SXin Li         path = p;
41*f1fbf3c2SXin Li     }
42*f1fbf3c2SXin Li }
43*f1fbf3c2SXin Li 
44*f1fbf3c2SXin Li final class DirClassPath implements ClassPath {
45*f1fbf3c2SXin Li     String directory;
46*f1fbf3c2SXin Li 
DirClassPath(String dirName)47*f1fbf3c2SXin Li     DirClassPath(String dirName) {
48*f1fbf3c2SXin Li         directory = dirName;
49*f1fbf3c2SXin Li     }
50*f1fbf3c2SXin Li 
51*f1fbf3c2SXin Li     @Override
openClassfile(String classname)52*f1fbf3c2SXin Li     public InputStream openClassfile(String classname) {
53*f1fbf3c2SXin Li         try {
54*f1fbf3c2SXin Li             char sep = File.separatorChar;
55*f1fbf3c2SXin Li             String filename = directory + sep
56*f1fbf3c2SXin Li                 + classname.replace('.', sep) + ".class";
57*f1fbf3c2SXin Li             return new FileInputStream(filename.toString());
58*f1fbf3c2SXin Li         }
59*f1fbf3c2SXin Li         catch (FileNotFoundException e) {}
60*f1fbf3c2SXin Li         catch (SecurityException e) {}
61*f1fbf3c2SXin Li         return null;
62*f1fbf3c2SXin Li     }
63*f1fbf3c2SXin Li 
64*f1fbf3c2SXin Li     @Override
find(String classname)65*f1fbf3c2SXin Li     public URL find(String classname) {
66*f1fbf3c2SXin Li         char sep = File.separatorChar;
67*f1fbf3c2SXin Li         String filename = directory + sep
68*f1fbf3c2SXin Li             + classname.replace('.', sep) + ".class";
69*f1fbf3c2SXin Li         File f = new File(filename);
70*f1fbf3c2SXin Li         if (f.exists())
71*f1fbf3c2SXin Li             try {
72*f1fbf3c2SXin Li                 return f.getCanonicalFile().toURI().toURL();
73*f1fbf3c2SXin Li             }
74*f1fbf3c2SXin Li             catch (MalformedURLException e) {}
75*f1fbf3c2SXin Li             catch (IOException e) {}
76*f1fbf3c2SXin Li 
77*f1fbf3c2SXin Li         return null;
78*f1fbf3c2SXin Li     }
79*f1fbf3c2SXin Li 
80*f1fbf3c2SXin Li     @Override
toString()81*f1fbf3c2SXin Li     public String toString() {
82*f1fbf3c2SXin Li         return directory;
83*f1fbf3c2SXin Li     }
84*f1fbf3c2SXin Li }
85*f1fbf3c2SXin Li 
86*f1fbf3c2SXin Li final class JarDirClassPath implements ClassPath {
87*f1fbf3c2SXin Li     JarClassPath[] jars;
88*f1fbf3c2SXin Li 
JarDirClassPath(String dirName)89*f1fbf3c2SXin Li     JarDirClassPath(String dirName) throws NotFoundException {
90*f1fbf3c2SXin Li         File[] files = new File(dirName).listFiles(new FilenameFilter() {
91*f1fbf3c2SXin Li             @Override
92*f1fbf3c2SXin Li             public boolean accept(File dir, String name) {
93*f1fbf3c2SXin Li                 name = name.toLowerCase();
94*f1fbf3c2SXin Li                 return name.endsWith(".jar") || name.endsWith(".zip");
95*f1fbf3c2SXin Li             }
96*f1fbf3c2SXin Li         });
97*f1fbf3c2SXin Li 
98*f1fbf3c2SXin Li         if (files != null) {
99*f1fbf3c2SXin Li             jars = new JarClassPath[files.length];
100*f1fbf3c2SXin Li             for (int i = 0; i < files.length; i++)
101*f1fbf3c2SXin Li                 jars[i] = new JarClassPath(files[i].getPath());
102*f1fbf3c2SXin Li         }
103*f1fbf3c2SXin Li     }
104*f1fbf3c2SXin Li 
105*f1fbf3c2SXin Li     @Override
openClassfile(String classname)106*f1fbf3c2SXin Li     public InputStream openClassfile(String classname) throws NotFoundException {
107*f1fbf3c2SXin Li         if (jars != null)
108*f1fbf3c2SXin Li             for (int i = 0; i < jars.length; i++) {
109*f1fbf3c2SXin Li                 InputStream is = jars[i].openClassfile(classname);
110*f1fbf3c2SXin Li                 if (is != null)
111*f1fbf3c2SXin Li                     return is;
112*f1fbf3c2SXin Li             }
113*f1fbf3c2SXin Li 
114*f1fbf3c2SXin Li         return null;    // not found
115*f1fbf3c2SXin Li     }
116*f1fbf3c2SXin Li 
117*f1fbf3c2SXin Li     @Override
find(String classname)118*f1fbf3c2SXin Li     public URL find(String classname) {
119*f1fbf3c2SXin Li         if (jars != null)
120*f1fbf3c2SXin Li             for (int i = 0; i < jars.length; i++) {
121*f1fbf3c2SXin Li                 URL url = jars[i].find(classname);
122*f1fbf3c2SXin Li                 if (url != null)
123*f1fbf3c2SXin Li                     return url;
124*f1fbf3c2SXin Li             }
125*f1fbf3c2SXin Li 
126*f1fbf3c2SXin Li         return null;    // not found
127*f1fbf3c2SXin Li     }
128*f1fbf3c2SXin Li }
129*f1fbf3c2SXin Li 
130*f1fbf3c2SXin Li final class JarClassPath implements ClassPath {
131*f1fbf3c2SXin Li     List<String> jarfileEntries;
132*f1fbf3c2SXin Li     String jarfileURL;
133*f1fbf3c2SXin Li 
JarClassPath(String pathname)134*f1fbf3c2SXin Li     JarClassPath(String pathname) throws NotFoundException {
135*f1fbf3c2SXin Li         JarFile jarfile = null;
136*f1fbf3c2SXin Li         try {
137*f1fbf3c2SXin Li             jarfile = new JarFile(pathname);
138*f1fbf3c2SXin Li             jarfileEntries = new ArrayList<String>();
139*f1fbf3c2SXin Li             for (JarEntry je:Collections.list(jarfile.entries()))
140*f1fbf3c2SXin Li                 if (je.getName().endsWith(".class"))
141*f1fbf3c2SXin Li                     jarfileEntries.add(je.getName());
142*f1fbf3c2SXin Li             jarfileURL = new File(pathname).getCanonicalFile()
143*f1fbf3c2SXin Li                     .toURI().toURL().toString();
144*f1fbf3c2SXin Li             return;
145*f1fbf3c2SXin Li         } catch (IOException e) {}
146*f1fbf3c2SXin Li         finally {
147*f1fbf3c2SXin Li             if (null != jarfile)
148*f1fbf3c2SXin Li                 try {
149*f1fbf3c2SXin Li                     jarfile.close();
150*f1fbf3c2SXin Li                 } catch (IOException e) {}
151*f1fbf3c2SXin Li         }
152*f1fbf3c2SXin Li         throw new NotFoundException(pathname);
153*f1fbf3c2SXin Li     }
154*f1fbf3c2SXin Li 
155*f1fbf3c2SXin Li     @Override
openClassfile(String classname)156*f1fbf3c2SXin Li     public InputStream openClassfile(String classname)
157*f1fbf3c2SXin Li             throws NotFoundException
158*f1fbf3c2SXin Li     {
159*f1fbf3c2SXin Li         URL jarURL = find(classname);
160*f1fbf3c2SXin Li         if (null != jarURL)
161*f1fbf3c2SXin Li             try {
162*f1fbf3c2SXin Li                 java.net.URLConnection con = jarURL.openConnection();
163*f1fbf3c2SXin Li                 con.setUseCaches(false);
164*f1fbf3c2SXin Li                 return con.getInputStream();
165*f1fbf3c2SXin Li             }
166*f1fbf3c2SXin Li             catch (IOException e) {
167*f1fbf3c2SXin Li                 throw new NotFoundException("broken jar file?: "
168*f1fbf3c2SXin Li                         + classname);
169*f1fbf3c2SXin Li             }
170*f1fbf3c2SXin Li         return null;
171*f1fbf3c2SXin Li     }
172*f1fbf3c2SXin Li 
173*f1fbf3c2SXin Li     @Override
find(String classname)174*f1fbf3c2SXin Li     public URL find(String classname) {
175*f1fbf3c2SXin Li         String jarname = classname.replace('.', '/') + ".class";
176*f1fbf3c2SXin Li         if (jarfileEntries.contains(jarname))
177*f1fbf3c2SXin Li             try {
178*f1fbf3c2SXin Li                 return new URL(String.format("jar:%s!/%s", jarfileURL, jarname));
179*f1fbf3c2SXin Li             }
180*f1fbf3c2SXin Li             catch (MalformedURLException e) {}
181*f1fbf3c2SXin Li         return null;            // not found
182*f1fbf3c2SXin Li     }
183*f1fbf3c2SXin Li 
184*f1fbf3c2SXin Li     @Override
toString()185*f1fbf3c2SXin Li     public String toString() {
186*f1fbf3c2SXin Li         return jarfileURL == null ? "<null>" : jarfileURL.toString();
187*f1fbf3c2SXin Li     }
188*f1fbf3c2SXin Li }
189*f1fbf3c2SXin Li 
190*f1fbf3c2SXin Li final class ClassPoolTail {
191*f1fbf3c2SXin Li     protected ClassPathList pathList;
192*f1fbf3c2SXin Li 
ClassPoolTail()193*f1fbf3c2SXin Li     public ClassPoolTail() {
194*f1fbf3c2SXin Li         pathList = null;
195*f1fbf3c2SXin Li     }
196*f1fbf3c2SXin Li 
197*f1fbf3c2SXin Li     @Override
toString()198*f1fbf3c2SXin Li     public String toString() {
199*f1fbf3c2SXin Li         StringBuffer buf = new StringBuffer();
200*f1fbf3c2SXin Li         buf.append("[class path: ");
201*f1fbf3c2SXin Li         ClassPathList list = pathList;
202*f1fbf3c2SXin Li         while (list != null) {
203*f1fbf3c2SXin Li             buf.append(list.path.toString());
204*f1fbf3c2SXin Li             buf.append(File.pathSeparatorChar);
205*f1fbf3c2SXin Li             list = list.next;
206*f1fbf3c2SXin Li         }
207*f1fbf3c2SXin Li 
208*f1fbf3c2SXin Li         buf.append(']');
209*f1fbf3c2SXin Li         return buf.toString();
210*f1fbf3c2SXin Li     }
211*f1fbf3c2SXin Li 
insertClassPath(ClassPath cp)212*f1fbf3c2SXin Li     public synchronized ClassPath insertClassPath(ClassPath cp) {
213*f1fbf3c2SXin Li         pathList = new ClassPathList(cp, pathList);
214*f1fbf3c2SXin Li         return cp;
215*f1fbf3c2SXin Li     }
216*f1fbf3c2SXin Li 
appendClassPath(ClassPath cp)217*f1fbf3c2SXin Li     public synchronized ClassPath appendClassPath(ClassPath cp) {
218*f1fbf3c2SXin Li         ClassPathList tail = new ClassPathList(cp, null);
219*f1fbf3c2SXin Li         ClassPathList list = pathList;
220*f1fbf3c2SXin Li         if (list == null)
221*f1fbf3c2SXin Li             pathList = tail;
222*f1fbf3c2SXin Li         else {
223*f1fbf3c2SXin Li             while (list.next != null)
224*f1fbf3c2SXin Li                 list = list.next;
225*f1fbf3c2SXin Li 
226*f1fbf3c2SXin Li             list.next = tail;
227*f1fbf3c2SXin Li         }
228*f1fbf3c2SXin Li 
229*f1fbf3c2SXin Li         return cp;
230*f1fbf3c2SXin Li     }
231*f1fbf3c2SXin Li 
removeClassPath(ClassPath cp)232*f1fbf3c2SXin Li     public synchronized void removeClassPath(ClassPath cp) {
233*f1fbf3c2SXin Li         ClassPathList list = pathList;
234*f1fbf3c2SXin Li         if (list != null)
235*f1fbf3c2SXin Li             if (list.path == cp)
236*f1fbf3c2SXin Li                 pathList = list.next;
237*f1fbf3c2SXin Li             else {
238*f1fbf3c2SXin Li                 while (list.next != null)
239*f1fbf3c2SXin Li                     if (list.next.path == cp)
240*f1fbf3c2SXin Li                         list.next = list.next.next;
241*f1fbf3c2SXin Li                     else
242*f1fbf3c2SXin Li                         list = list.next;
243*f1fbf3c2SXin Li             }
244*f1fbf3c2SXin Li     }
245*f1fbf3c2SXin Li 
appendSystemPath()246*f1fbf3c2SXin Li     public ClassPath appendSystemPath() {
247*f1fbf3c2SXin Li         if (javassist.bytecode.ClassFile.MAJOR_VERSION < javassist.bytecode.ClassFile.JAVA_9)
248*f1fbf3c2SXin Li             return appendClassPath(new ClassClassPath());
249*f1fbf3c2SXin Li         ClassLoader cl = Thread.currentThread().getContextClassLoader();
250*f1fbf3c2SXin Li         return appendClassPath(new LoaderClassPath(cl));
251*f1fbf3c2SXin Li     }
252*f1fbf3c2SXin Li 
insertClassPath(String pathname)253*f1fbf3c2SXin Li     public ClassPath insertClassPath(String pathname)
254*f1fbf3c2SXin Li         throws NotFoundException
255*f1fbf3c2SXin Li     {
256*f1fbf3c2SXin Li         return insertClassPath(makePathObject(pathname));
257*f1fbf3c2SXin Li     }
258*f1fbf3c2SXin Li 
appendClassPath(String pathname)259*f1fbf3c2SXin Li     public ClassPath appendClassPath(String pathname)
260*f1fbf3c2SXin Li         throws NotFoundException
261*f1fbf3c2SXin Li     {
262*f1fbf3c2SXin Li         return appendClassPath(makePathObject(pathname));
263*f1fbf3c2SXin Li     }
264*f1fbf3c2SXin Li 
makePathObject(String pathname)265*f1fbf3c2SXin Li     private static ClassPath makePathObject(String pathname)
266*f1fbf3c2SXin Li         throws NotFoundException
267*f1fbf3c2SXin Li     {
268*f1fbf3c2SXin Li         String lower = pathname.toLowerCase();
269*f1fbf3c2SXin Li         if (lower.endsWith(".jar") || lower.endsWith(".zip"))
270*f1fbf3c2SXin Li             return new JarClassPath(pathname);
271*f1fbf3c2SXin Li 
272*f1fbf3c2SXin Li         int len = pathname.length();
273*f1fbf3c2SXin Li         if (len > 2 && pathname.charAt(len - 1) == '*'
274*f1fbf3c2SXin Li             && (pathname.charAt(len - 2) == '/'
275*f1fbf3c2SXin Li                 || pathname.charAt(len - 2) == File.separatorChar)) {
276*f1fbf3c2SXin Li             String dir = pathname.substring(0, len - 2);
277*f1fbf3c2SXin Li             return new JarDirClassPath(dir);
278*f1fbf3c2SXin Li         }
279*f1fbf3c2SXin Li 
280*f1fbf3c2SXin Li         return new DirClassPath(pathname);
281*f1fbf3c2SXin Li     }
282*f1fbf3c2SXin Li 
283*f1fbf3c2SXin Li     /**
284*f1fbf3c2SXin Li      * This method does not close the output stream.
285*f1fbf3c2SXin Li      */
writeClassfile(String classname, OutputStream out)286*f1fbf3c2SXin Li     void writeClassfile(String classname, OutputStream out)
287*f1fbf3c2SXin Li         throws NotFoundException, IOException, CannotCompileException
288*f1fbf3c2SXin Li     {
289*f1fbf3c2SXin Li         InputStream fin = openClassfile(classname);
290*f1fbf3c2SXin Li         if (fin == null)
291*f1fbf3c2SXin Li             throw new NotFoundException(classname);
292*f1fbf3c2SXin Li 
293*f1fbf3c2SXin Li         try {
294*f1fbf3c2SXin Li             copyStream(fin, out);
295*f1fbf3c2SXin Li         }
296*f1fbf3c2SXin Li         finally {
297*f1fbf3c2SXin Li             fin.close();
298*f1fbf3c2SXin Li         }
299*f1fbf3c2SXin Li     }
300*f1fbf3c2SXin Li 
301*f1fbf3c2SXin Li     /*
302*f1fbf3c2SXin Li     -- faster version --
303*f1fbf3c2SXin Li     void checkClassName(String classname) throws NotFoundException {
304*f1fbf3c2SXin Li         if (find(classname) == null)
305*f1fbf3c2SXin Li             throw new NotFoundException(classname);
306*f1fbf3c2SXin Li     }
307*f1fbf3c2SXin Li 
308*f1fbf3c2SXin Li     -- slower version --
309*f1fbf3c2SXin Li 
310*f1fbf3c2SXin Li     void checkClassName(String classname) throws NotFoundException {
311*f1fbf3c2SXin Li         InputStream fin = openClassfile(classname);
312*f1fbf3c2SXin Li         try {
313*f1fbf3c2SXin Li             fin.close();
314*f1fbf3c2SXin Li         }
315*f1fbf3c2SXin Li         catch (IOException e) {}
316*f1fbf3c2SXin Li     }
317*f1fbf3c2SXin Li     */
318*f1fbf3c2SXin Li 
319*f1fbf3c2SXin Li 
320*f1fbf3c2SXin Li     /**
321*f1fbf3c2SXin Li      * Opens the class file for the class specified by
322*f1fbf3c2SXin Li      * <code>classname</code>.
323*f1fbf3c2SXin Li      *
324*f1fbf3c2SXin Li      * @param classname             a fully-qualified class name
325*f1fbf3c2SXin Li      * @return null                 if the file has not been found.
326*f1fbf3c2SXin Li      * @throws NotFoundException    if any error is reported by ClassPath.
327*f1fbf3c2SXin Li      */
openClassfile(String classname)328*f1fbf3c2SXin Li     InputStream openClassfile(String classname)
329*f1fbf3c2SXin Li         throws NotFoundException
330*f1fbf3c2SXin Li     {
331*f1fbf3c2SXin Li         ClassPathList list = pathList;
332*f1fbf3c2SXin Li         InputStream ins = null;
333*f1fbf3c2SXin Li         NotFoundException error = null;
334*f1fbf3c2SXin Li         while (list != null) {
335*f1fbf3c2SXin Li             try {
336*f1fbf3c2SXin Li                 ins = list.path.openClassfile(classname);
337*f1fbf3c2SXin Li             }
338*f1fbf3c2SXin Li             catch (NotFoundException e) {
339*f1fbf3c2SXin Li                 if (error == null)
340*f1fbf3c2SXin Li                     error = e;
341*f1fbf3c2SXin Li             }
342*f1fbf3c2SXin Li 
343*f1fbf3c2SXin Li             if (ins == null)
344*f1fbf3c2SXin Li                 list = list.next;
345*f1fbf3c2SXin Li             else
346*f1fbf3c2SXin Li                 return ins;
347*f1fbf3c2SXin Li         }
348*f1fbf3c2SXin Li 
349*f1fbf3c2SXin Li         if (error != null)
350*f1fbf3c2SXin Li             throw error;
351*f1fbf3c2SXin Li         return null;    // not found
352*f1fbf3c2SXin Li     }
353*f1fbf3c2SXin Li 
354*f1fbf3c2SXin Li     /**
355*f1fbf3c2SXin Li      * Searches the class path to obtain the URL of the class file
356*f1fbf3c2SXin Li      * specified by classname.  It is also used to determine whether
357*f1fbf3c2SXin Li      * the class file exists.
358*f1fbf3c2SXin Li      *
359*f1fbf3c2SXin Li      * @param classname     a fully-qualified class name.
360*f1fbf3c2SXin Li      * @return null if the class file could not be found.
361*f1fbf3c2SXin Li      */
find(String classname)362*f1fbf3c2SXin Li     public URL find(String classname) {
363*f1fbf3c2SXin Li         ClassPathList list = pathList;
364*f1fbf3c2SXin Li         URL url = null;
365*f1fbf3c2SXin Li         while (list != null) {
366*f1fbf3c2SXin Li             url = list.path.find(classname);
367*f1fbf3c2SXin Li             if (url == null)
368*f1fbf3c2SXin Li                 list = list.next;
369*f1fbf3c2SXin Li             else
370*f1fbf3c2SXin Li                 return url;
371*f1fbf3c2SXin Li         }
372*f1fbf3c2SXin Li 
373*f1fbf3c2SXin Li         return null;
374*f1fbf3c2SXin Li     }
375*f1fbf3c2SXin Li 
376*f1fbf3c2SXin Li     /**
377*f1fbf3c2SXin Li      * Reads from an input stream until it reaches the end.
378*f1fbf3c2SXin Li      *
379*f1fbf3c2SXin Li      * @return          the contents of that input stream
380*f1fbf3c2SXin Li      */
readStream(InputStream fin)381*f1fbf3c2SXin Li     public static byte[] readStream(InputStream fin) throws IOException {
382*f1fbf3c2SXin Li         byte[][] bufs = new byte[8][];
383*f1fbf3c2SXin Li         int bufsize = 4096;
384*f1fbf3c2SXin Li 
385*f1fbf3c2SXin Li         for (int i = 0; i < 8; ++i) {
386*f1fbf3c2SXin Li             bufs[i] = new byte[bufsize];
387*f1fbf3c2SXin Li             int size = 0;
388*f1fbf3c2SXin Li             int len = 0;
389*f1fbf3c2SXin Li             do {
390*f1fbf3c2SXin Li                 len = fin.read(bufs[i], size, bufsize - size);
391*f1fbf3c2SXin Li                 if (len >= 0)
392*f1fbf3c2SXin Li                     size += len;
393*f1fbf3c2SXin Li                 else {
394*f1fbf3c2SXin Li                     byte[] result = new byte[bufsize - 4096 + size];
395*f1fbf3c2SXin Li                     int s = 0;
396*f1fbf3c2SXin Li                     for (int j = 0; j < i; ++j) {
397*f1fbf3c2SXin Li                         System.arraycopy(bufs[j], 0, result, s, s + 4096);
398*f1fbf3c2SXin Li                         s = s + s + 4096;
399*f1fbf3c2SXin Li                     }
400*f1fbf3c2SXin Li 
401*f1fbf3c2SXin Li                     System.arraycopy(bufs[i], 0, result, s, size);
402*f1fbf3c2SXin Li                     return result;
403*f1fbf3c2SXin Li                 }
404*f1fbf3c2SXin Li             } while (size < bufsize);
405*f1fbf3c2SXin Li             bufsize *= 2;
406*f1fbf3c2SXin Li         }
407*f1fbf3c2SXin Li 
408*f1fbf3c2SXin Li         throw new IOException("too much data");
409*f1fbf3c2SXin Li     }
410*f1fbf3c2SXin Li 
411*f1fbf3c2SXin Li     /**
412*f1fbf3c2SXin Li      * Reads from an input stream and write to an output stream
413*f1fbf3c2SXin Li      * until it reaches the end.  This method does not close the
414*f1fbf3c2SXin Li      * streams.
415*f1fbf3c2SXin Li      */
copyStream(InputStream fin, OutputStream fout)416*f1fbf3c2SXin Li     public static void copyStream(InputStream fin, OutputStream fout)
417*f1fbf3c2SXin Li         throws IOException
418*f1fbf3c2SXin Li     {
419*f1fbf3c2SXin Li         int bufsize = 4096;
420*f1fbf3c2SXin Li         byte[] buf = null;
421*f1fbf3c2SXin Li         for (int i = 0; i < 64; ++i) {
422*f1fbf3c2SXin Li             if (i < 8) {
423*f1fbf3c2SXin Li                 bufsize *= 2;
424*f1fbf3c2SXin Li                 buf = new byte[bufsize];
425*f1fbf3c2SXin Li             }
426*f1fbf3c2SXin Li             int size = 0;
427*f1fbf3c2SXin Li             int len = 0;
428*f1fbf3c2SXin Li             do {
429*f1fbf3c2SXin Li                 len = fin.read(buf, size, bufsize - size);
430*f1fbf3c2SXin Li                 if (len >= 0)
431*f1fbf3c2SXin Li                     size += len;
432*f1fbf3c2SXin Li                 else {
433*f1fbf3c2SXin Li                     fout.write(buf, 0, size);
434*f1fbf3c2SXin Li                     return;
435*f1fbf3c2SXin Li                 }
436*f1fbf3c2SXin Li             } while (size < bufsize);
437*f1fbf3c2SXin Li             fout.write(buf);
438*f1fbf3c2SXin Li         }
439*f1fbf3c2SXin Li 
440*f1fbf3c2SXin Li         throw new IOException("too much data");
441*f1fbf3c2SXin Li     }
442*f1fbf3c2SXin Li }
443