/* * Copyright (C) 2007 The Android Open Source Project * * 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 the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.webkit; import com.android.internal.R; import android.content.res.AssetManager; import android.net.http.EventHandler; import android.net.http.Headers; import android.util.Log; import android.util.TypedValue; import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Field; /** * This class is a concrete implementation of StreamLoader that uses a * file or asset as the source for the stream. * */ class FileLoader extends StreamLoader { private String mPath; // Full path to the file to load private int mType; // Indicates the type of the load private boolean mAllowFileAccess; // Allow/block file system access // used for files under asset directory static final int TYPE_ASSET = 1; // used for files under res directory static final int TYPE_RES = 2; // generic file static final int TYPE_FILE = 3; private static final String LOGTAG = "webkit"; /** * Construct a FileLoader with the file URL specified as the content * source. * * @param url Full file url pointing to content to be loaded * @param loadListener LoadListener to pass the content to * @param asset true if url points to an asset. * @param allowFileAccess true if this WebView is allowed to access files * on the file system. */ FileLoader(String url, LoadListener loadListener, int type, boolean allowFileAccess) { super(loadListener); mType = type; mAllowFileAccess = allowFileAccess; // clean the Url int index = url.indexOf('?'); if (mType == TYPE_ASSET) { mPath = index > 0 ? URLUtil.stripAnchor( url.substring(URLUtil.ASSET_BASE.length(), index)) : URLUtil.stripAnchor(url.substring( URLUtil.ASSET_BASE.length())); } else if (mType == TYPE_RES) { mPath = index > 0 ? URLUtil.stripAnchor( url.substring(URLUtil.RESOURCE_BASE.length(), index)) : URLUtil.stripAnchor(url.substring( URLUtil.RESOURCE_BASE.length())); } else { mPath = index > 0 ? URLUtil.stripAnchor( url.substring(URLUtil.FILE_BASE.length(), index)) : URLUtil.stripAnchor(url.substring( URLUtil.FILE_BASE.length())); } } private String errString(Exception ex) { String exMessage = ex.getMessage(); String errString = mContext.getString(R.string.httpErrorFileNotFound); if (exMessage != null) { errString += " " + exMessage; } return errString; } @Override protected boolean setupStreamAndSendStatus() { try { if (mType == TYPE_ASSET) { try { mDataStream = mContext.getAssets().open(mPath); } catch (java.io.FileNotFoundException ex) { // try the rest files included in the package mDataStream = mContext.getAssets().openNonAsset(mPath); } } else if (mType == TYPE_RES) { // get the resource id from the path. e.g. for the path like // drawable/foo.png, the id is located at field "foo" of class // "<package>.R$drawable" if (mPath == null || mPath.length() == 0) { Log.e(LOGTAG, "Need a path to resolve the res file"); mLoadListener.error(EventHandler.FILE_ERROR, mContext .getString(R.string.httpErrorFileNotFound)); return false; } int slash = mPath.indexOf('/'); int dot = mPath.indexOf('.', slash); if (slash == -1 || dot == -1) { Log.e(LOGTAG, "Incorrect res path: " + mPath); mLoadListener.error(EventHandler.FILE_ERROR, mContext .getString(R.string.httpErrorFileNotFound)); return false; } String subClassName = mPath.substring(0, slash); String fieldName = mPath.substring(slash + 1, dot); String errorMsg = null; try { final Class<?> d = mContext.getApplicationContext() .getClassLoader().loadClass( mContext.getPackageName() + ".R$" + subClassName); final Field field = d.getField(fieldName); final int id = field.getInt(null); TypedValue value = new TypedValue(); mContext.getResources().getValue(id, value, true); if (value.type == TypedValue.TYPE_STRING) { mDataStream = mContext.getAssets().openNonAsset( value.assetCookie, value.string.toString(), AssetManager.ACCESS_STREAMING); } else { errorMsg = "Only support TYPE_STRING for the res files"; } } catch (ClassNotFoundException e) { errorMsg = "Can't find class: " + mContext.getPackageName() + ".R$" + subClassName; } catch (SecurityException e) { errorMsg = "Caught SecurityException: " + e; } catch (NoSuchFieldException e) { errorMsg = "Can't find field: " + fieldName + " in " + mContext.getPackageName() + ".R$" + subClassName; } catch (IllegalArgumentException e) { errorMsg = "Caught IllegalArgumentException: " + e; } catch (IllegalAccessException e) { errorMsg = "Caught IllegalAccessException: " + e; } if (errorMsg != null) { mLoadListener.error(EventHandler.FILE_ERROR, mContext .getString(R.string.httpErrorFileNotFound)); return false; } } else { if (!mAllowFileAccess) { mLoadListener.error(EventHandler.FILE_ERROR, mContext.getString(R.string.httpErrorFileNotFound)); return false; } mDataStream = new FileInputStream(mPath); mContentLength = (new File(mPath)).length(); } mLoadListener.status(1, 1, 200, "OK"); } catch (java.io.FileNotFoundException ex) { mLoadListener.error(EventHandler.FILE_NOT_FOUND_ERROR, errString(ex)); return false; } catch (java.io.IOException ex) { mLoadListener.error(EventHandler.FILE_ERROR, errString(ex)); return false; } return true; } @Override protected void buildHeaders(Headers headers) { // do nothing. } }