1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.webkit; 18 19 import com.android.internal.R; 20 21 import android.content.res.AssetManager; 22 import android.net.http.EventHandler; 23 import android.net.http.Headers; 24 import android.util.Log; 25 import android.util.TypedValue; 26 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.lang.reflect.Field; 30 31 /** 32 * This class is a concrete implementation of StreamLoader that uses a 33 * file or asset as the source for the stream. 34 * 35 */ 36 class FileLoader extends StreamLoader { 37 38 private String mPath; // Full path to the file to load 39 private int mType; // Indicates the type of the load 40 private boolean mAllowFileAccess; // Allow/block file system access 41 42 // used for files under asset directory 43 static final int TYPE_ASSET = 1; 44 // used for files under res directory 45 static final int TYPE_RES = 2; 46 // generic file 47 static final int TYPE_FILE = 3; 48 49 private static final String LOGTAG = "webkit"; 50 51 /** 52 * Construct a FileLoader with the file URL specified as the content 53 * source. 54 * 55 * @param url Full file url pointing to content to be loaded 56 * @param loadListener LoadListener to pass the content to 57 * @param asset true if url points to an asset. 58 * @param allowFileAccess true if this WebView is allowed to access files 59 * on the file system. 60 */ 61 FileLoader(String url, LoadListener loadListener, int type, 62 boolean allowFileAccess) { 63 super(loadListener); 64 mType = type; 65 mAllowFileAccess = allowFileAccess; 66 67 // clean the Url 68 int index = url.indexOf('?'); 69 if (mType == TYPE_ASSET) { 70 mPath = index > 0 ? URLUtil.stripAnchor( 71 url.substring(URLUtil.ASSET_BASE.length(), index)) : 72 URLUtil.stripAnchor(url.substring( 73 URLUtil.ASSET_BASE.length())); 74 } else if (mType == TYPE_RES) { 75 mPath = index > 0 ? URLUtil.stripAnchor( 76 url.substring(URLUtil.RESOURCE_BASE.length(), index)) : 77 URLUtil.stripAnchor(url.substring( 78 URLUtil.RESOURCE_BASE.length())); 79 } else { 80 mPath = index > 0 ? URLUtil.stripAnchor( 81 url.substring(URLUtil.FILE_BASE.length(), index)) : 82 URLUtil.stripAnchor(url.substring( 83 URLUtil.FILE_BASE.length())); 84 } 85 } 86 87 private String errString(Exception ex) { 88 String exMessage = ex.getMessage(); 89 String errString = mContext.getString(R.string.httpErrorFileNotFound); 90 if (exMessage != null) { 91 errString += " " + exMessage; 92 } 93 return errString; 94 } 95 96 @Override 97 protected boolean setupStreamAndSendStatus() { 98 try { 99 if (mType == TYPE_ASSET) { 100 try { 101 mDataStream = mContext.getAssets().open(mPath); 102 } catch (java.io.FileNotFoundException ex) { 103 // try the rest files included in the package 104 mDataStream = mContext.getAssets().openNonAsset(mPath); 105 } 106 } else if (mType == TYPE_RES) { 107 // get the resource id from the path. e.g. for the path like 108 // drawable/foo.png, the id is located at field "foo" of class 109 // "<package>.R$drawable" 110 if (mPath == null || mPath.length() == 0) { 111 Log.e(LOGTAG, "Need a path to resolve the res file"); 112 mLoadListener.error(EventHandler.FILE_ERROR, mContext 113 .getString(R.string.httpErrorFileNotFound)); 114 return false; 115 116 } 117 int slash = mPath.indexOf('/'); 118 int dot = mPath.indexOf('.', slash); 119 if (slash == -1 || dot == -1) { 120 Log.e(LOGTAG, "Incorrect res path: " + mPath); 121 mLoadListener.error(EventHandler.FILE_ERROR, mContext 122 .getString(R.string.httpErrorFileNotFound)); 123 return false; 124 } 125 String subClassName = mPath.substring(0, slash); 126 String fieldName = mPath.substring(slash + 1, dot); 127 String errorMsg = null; 128 try { 129 final Class<?> d = mContext.getApplicationContext() 130 .getClassLoader().loadClass( 131 mContext.getPackageName() + ".R$" 132 + subClassName); 133 final Field field = d.getField(fieldName); 134 final int id = field.getInt(null); 135 TypedValue value = new TypedValue(); 136 mContext.getResources().getValue(id, value, true); 137 if (value.type == TypedValue.TYPE_STRING) { 138 mDataStream = mContext.getAssets().openNonAsset( 139 value.assetCookie, value.string.toString(), 140 AssetManager.ACCESS_STREAMING); 141 } else { 142 errorMsg = "Only support TYPE_STRING for the res files"; 143 } 144 } catch (ClassNotFoundException e) { 145 errorMsg = "Can't find class: " 146 + mContext.getPackageName() + ".R$" + subClassName; 147 } catch (SecurityException e) { 148 errorMsg = "Caught SecurityException: " + e; 149 } catch (NoSuchFieldException e) { 150 errorMsg = "Can't find field: " + fieldName + " in " 151 + mContext.getPackageName() + ".R$" + subClassName; 152 } catch (IllegalArgumentException e) { 153 errorMsg = "Caught IllegalArgumentException: " + e; 154 } catch (IllegalAccessException e) { 155 errorMsg = "Caught IllegalAccessException: " + e; 156 } 157 if (errorMsg != null) { 158 mLoadListener.error(EventHandler.FILE_ERROR, mContext 159 .getString(R.string.httpErrorFileNotFound)); 160 return false; 161 } 162 } else { 163 if (!mAllowFileAccess) { 164 mLoadListener.error(EventHandler.FILE_ERROR, 165 mContext.getString(R.string.httpErrorFileNotFound)); 166 return false; 167 } 168 169 mDataStream = new FileInputStream(mPath); 170 mContentLength = (new File(mPath)).length(); 171 } 172 mLoadListener.status(1, 1, 200, "OK"); 173 174 } catch (java.io.FileNotFoundException ex) { 175 mLoadListener.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex)); 176 return false; 177 178 } catch (java.io.IOException ex) { 179 mLoadListener.error(EventHandler.FILE_ERROR, errString(ex)); 180 return false; 181 } 182 return true; 183 } 184 185 @Override 186 protected void buildHeaders(Headers headers) { 187 // do nothing. 188 } 189 } 190