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