Fixes issue 2060.  The readURL* and readFile* methods assumed that InputStream.read(byte[]) would always read the requested number of bytes before returning.

Patch by: mmendez
Review by: scottb

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1795 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/util/Util.java b/dev/core/src/com/google/gwt/dev/util/Util.java
index 123fecd..b252809 100644
--- a/dev/core/src/com/google/gwt/dev/util/Util.java
+++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
@@ -558,9 +558,7 @@
     try {
       fileInputStream = new FileInputStream(file);
       int length = (int) file.length();
-      byte[] data = new byte[length];
-      fileInputStream.read(data);
-      return data;
+      return readBytesFromInputStream(fileInputStream, length);
     } catch (IOException e) {
       return null;
     } finally {
@@ -569,48 +567,20 @@
   }
 
   public static char[] readFileAsChars(File file) {
-    if (!file.exists()) {
-      return null;
+    String string = readFileAsString(file);
+    if (string != null) {
+      return string.toCharArray();
     }
-    Reader fileReader = null;
-    try {
-      fileReader = new InputStreamReader(new FileInputStream(file),
-          DEFAULT_ENCODING);
-      int length = (int) file.length();
-      if (length < 0) {
-        return null;
-      }
-      char[] fileContents = new char[length];
-      int charsRead = fileReader.read(fileContents);
-      if (charsRead < fileContents.length) {
-        /*
-         * Calling functions expect returned char[] to be fully populated. This
-         * happens because some UTF-8 chars take more than one byte to
-         * represent.
-         */
-        char[] trimmed = new char[charsRead];
-        System.arraycopy(fileContents, 0, trimmed, 0, charsRead);
-        fileContents = trimmed;
-      }
-      return fileContents;
-    } catch (IOException e) {
-      return null;
-    } finally {
-      Utility.close(fileReader);
-    }
+    return null;
   }
 
   public static String readFileAsString(File file) {
-    try {
-      URL toURL = file.toURI().toURL();
-      char[] buf = readURLAsChars(toURL);
-      if (buf == null) {
-        return null;
-      }
-      return String.valueOf(buf);
-    } catch (MalformedURLException e) {
-      return null;
+    byte[] bytes = readFileAsBytes(file);
+    if (bytes != null) {
+      return toString(bytes, DEFAULT_ENCODING);
     }
+
+    return null;
   }
 
   /**
@@ -649,9 +619,8 @@
       if (contentLength < 0) {
         return null;
       }
-      byte[] data = new byte[contentLength];
-      input.read(data);
-      return data;
+
+      return readBytesFromInputStream(input, contentLength);
     } catch (IOException e) {
       return null;
     } finally {
@@ -664,34 +633,12 @@
    */
   public static char[] readURLAsChars(URL url) {
     // ENH: add a weak cache that has an additional check against the file date
-    InputStreamReader reader = null;
-    try {
-      URLConnection connection = url.openConnection();
-      connection.setUseCaches(false);
-      reader = new InputStreamReader(connection.getInputStream(),
-          DEFAULT_ENCODING);
-      int contentLength = connection.getContentLength();
-      if (contentLength < 0) {
-        return null;
-      }
-      char[] fileContents = new char[contentLength];
-      int charsRead = reader.read(fileContents);
-      if (charsRead < fileContents.length) {
-        /*
-         * Calling functions expect returned char[] to be fully populated. This
-         * happens because some UTF-8 chars take more than one byte to
-         * represent.
-         */
-        char[] trimmed = new char[charsRead];
-        System.arraycopy(fileContents, 0, trimmed, 0, charsRead);
-        fileContents = trimmed;
-      }
-      return fileContents;
-    } catch (IOException e) {
-      return null;
-    } finally {
-      Utility.close(reader);
+    byte[] bytes = readURLAsBytes(url);
+    if (bytes != null) {
+      return toString(bytes, DEFAULT_ENCODING).toCharArray();
     }
+
+    return null;
   }
 
   /**
@@ -1000,6 +947,57 @@
     return true;
   }
 
+  /**
+   * Reads the specified number of bytes from the {@link InputStream}.
+   * 
+   * @param byteLength number of bytes to read
+   * @return byte array containing the bytes read or <code>null</code> if
+   *         there is an {@link IOException} or if the requested number of bytes 
+   *         can not be read from the {@link InputStream}
+   */
+  private static byte[] readBytesFromInputStream(InputStream input,
+      int byteLength) {
+
+    try {
+      byte[] bytes = new byte[byteLength];
+      int byteOffset = 0;
+      while (byteOffset < byteLength) {
+        int bytesReadCount = input.read(bytes, byteOffset, byteLength
+            - byteOffset);
+        if (bytesReadCount == -1) {
+          return null;
+        }
+
+        byteOffset += bytesReadCount;
+      }
+
+      return bytes;
+    } catch (IOException e) {
+      // Ignored.
+    }
+
+    return null;
+  }
+
+  /**
+   * Creates a string from the bytes using the specified character set name.
+   * 
+   * @param bytes bytes to convert
+   * @param charsetName the name of the character set to use
+   * 
+   * @return String for the given bytes and character set or <code>null</code>
+   *         if the character set is not supported
+   */
+  private static String toString(byte[] bytes, String charsetName) {
+    try {
+      return new String(bytes, charsetName);
+    } catch (UnsupportedEncodingException e) {
+      // Ignored.
+    }
+
+    return null;
+  }
+
   private static void writeAttribute(PrintWriter w, Attr attr, int depth)
       throws IOException {
     w.write(attr.getName());