initial support for preference based proxy settings
and filtering to stop HTML5 media leakage
This commit is contained in:
parent
81a04cac1f
commit
f70d889c03
@ -449,15 +449,20 @@ public class BrowserActivity extends Activity implements BrowserController {
|
|||||||
getDir("icons", MODE_PRIVATE).getPath());
|
getDir("icons", MODE_PRIVATE).getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean useProxy = mPreferences.getBoolean(PreferenceConstants.USE_PROXY, false);
|
||||||
checkForTor ();
|
|
||||||
|
if (useProxy)
|
||||||
|
initializeTor();
|
||||||
|
else
|
||||||
|
checkForTor();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If Orbot/Tor is installed, prompt the user if they want to enable proxying for this session
|
* If Orbot/Tor is installed, prompt the user if they want to enable proxying for this session
|
||||||
*/
|
*/
|
||||||
public void checkForTor ()
|
public boolean checkForTor ()
|
||||||
{
|
{
|
||||||
|
|
||||||
OrbotHelper oh = new OrbotHelper(this);
|
OrbotHelper oh = new OrbotHelper(this);
|
||||||
@ -468,11 +473,16 @@ public class BrowserActivity extends Activity implements BrowserController {
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
switch (which){
|
switch (which){
|
||||||
case DialogInterface.BUTTON_POSITIVE:
|
case DialogInterface.BUTTON_POSITIVE:
|
||||||
|
|
||||||
|
mPreferences.edit().putBoolean(PreferenceConstants.USE_PROXY, true).apply();
|
||||||
|
|
||||||
initializeTor ();
|
initializeTor ();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DialogInterface.BUTTON_NEGATIVE:
|
case DialogInterface.BUTTON_NEGATIVE:
|
||||||
//No button clicked
|
|
||||||
|
mPreferences.edit().putBoolean(PreferenceConstants.USE_PROXY, false).apply();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -481,7 +491,11 @@ public class BrowserActivity extends Activity implements BrowserController {
|
|||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setMessage(R.string.use_tor_prompt).setPositiveButton(android.R.string.yes, dialogClickListener)
|
builder.setMessage(R.string.use_tor_prompt).setPositiveButton(android.R.string.yes, dialogClickListener)
|
||||||
.setNegativeButton(android.R.string.no, dialogClickListener).show();
|
.setNegativeButton(android.R.string.no, dialogClickListener).show();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -496,7 +510,9 @@ public class BrowserActivity extends Activity implements BrowserController {
|
|||||||
|
|
||||||
WebkitProxy wkp = new WebkitProxy();
|
WebkitProxy wkp = new WebkitProxy();
|
||||||
try {
|
try {
|
||||||
wkp.setProxy("acr.browser.lightning.BrowserApp", getApplicationContext(), "localhost",8118);
|
String host = mPreferences.getString(PreferenceConstants.USE_PROXY_HOST, "localhost");
|
||||||
|
int port = mPreferences.getInt(PreferenceConstants.USE_PROXY_PORT, 8118);
|
||||||
|
wkp.setProxy("acr.browser.lightning.BrowserApp", getApplicationContext(), host, port);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d("Lightning","error enabling web proxying",e);
|
Log.d("Lightning","error enabling web proxying",e);
|
||||||
}
|
}
|
||||||
@ -1000,7 +1016,7 @@ public class BrowserActivity extends Activity implements BrowserController {
|
|||||||
|
|
||||||
private synchronized void newTab(String url, boolean show) {
|
private synchronized void newTab(String url, boolean show) {
|
||||||
mIsNewIntent = false;
|
mIsNewIntent = false;
|
||||||
LightningView startingTab = new LightningView(mActivity, url);
|
LightningView startingTab = new LightningView(mActivity, url, mCookieManager);
|
||||||
if (mIdGenerator == 0) {
|
if (mIdGenerator == 0) {
|
||||||
startingTab.resumeTimers();
|
startingTab.resumeTimers();
|
||||||
}
|
}
|
||||||
|
@ -908,7 +908,7 @@ public class IncognitoActivity extends Activity implements BrowserController {
|
|||||||
|
|
||||||
private synchronized void newTab(String url, boolean show) {
|
private synchronized void newTab(String url, boolean show) {
|
||||||
mIsNewIntent = false;
|
mIsNewIntent = false;
|
||||||
LightningView startingTab = new LightningView(mActivity, url);
|
LightningView startingTab = new LightningView(mActivity, url, mCookieManager);
|
||||||
if (mIdGenerator == 0) {
|
if (mIdGenerator == 0) {
|
||||||
startingTab.resumeTimers();
|
startingTab.resumeTimers();
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,19 @@
|
|||||||
|
|
||||||
package acr.browser.lightning;
|
package acr.browser.lightning;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Proxy;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.apache.http.util.ByteArrayBuffer;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@ -28,10 +36,11 @@ import android.text.TextUtils;
|
|||||||
import android.text.method.PasswordTransformationMethod;
|
import android.text.method.PasswordTransformationMethod;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
|
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
|
||||||
import android.view.View.OnTouchListener;
|
import android.view.View.OnTouchListener;
|
||||||
|
import android.webkit.CookieManager;
|
||||||
import android.webkit.GeolocationPermissions;
|
import android.webkit.GeolocationPermissions;
|
||||||
import android.webkit.HttpAuthHandler;
|
import android.webkit.HttpAuthHandler;
|
||||||
import android.webkit.SslErrorHandler;
|
import android.webkit.SslErrorHandler;
|
||||||
@ -44,7 +53,9 @@ import android.webkit.WebSettings.PluginState;
|
|||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.VideoView;
|
||||||
|
|
||||||
public class LightningView {
|
public class LightningView {
|
||||||
|
|
||||||
@ -62,9 +73,12 @@ public class LightningView {
|
|||||||
private static SharedPreferences mPreferences;
|
private static SharedPreferences mPreferences;
|
||||||
private static boolean mWideViewPort;
|
private static boolean mWideViewPort;
|
||||||
private static AdBlock mAdBlock;
|
private static AdBlock mAdBlock;
|
||||||
|
private CookieManager mCookieManager;
|
||||||
public LightningView(Activity activity, String url) {
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public LightningView(Activity activity, String url, CookieManager cookieManager) {
|
||||||
mActivity = activity;
|
mActivity = activity;
|
||||||
|
mCookieManager = cookieManager;
|
||||||
mWebView = new WebView(activity);
|
mWebView = new WebView(activity);
|
||||||
mTitle = new Title(activity);
|
mTitle = new Title(activity);
|
||||||
mAdBlock = new AdBlock(activity);
|
mAdBlock = new AdBlock(activity);
|
||||||
@ -249,6 +263,7 @@ public class LightningView {
|
|||||||
return Constants.FILE + homepage;
|
return Constants.FILE + homepage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
public synchronized void initializePreferences(Context context) {
|
public synchronized void initializePreferences(Context context) {
|
||||||
mPreferences = context.getSharedPreferences(
|
mPreferences = context.getSharedPreferences(
|
||||||
PreferenceConstants.PREFERENCES, 0);
|
PreferenceConstants.PREFERENCES, 0);
|
||||||
@ -348,7 +363,7 @@ public class LightningView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint({ "SetJavaScriptEnabled", "NewApi" })
|
||||||
public void initializeSettings(WebSettings settings, Context context) {
|
public void initializeSettings(WebSettings settings, Context context) {
|
||||||
if (API < 18) {
|
if (API < 18) {
|
||||||
settings.setAppCacheMaxSize(Long.MAX_VALUE);
|
settings.setAppCacheMaxSize(Long.MAX_VALUE);
|
||||||
@ -357,7 +372,7 @@ public class LightningView {
|
|||||||
settings.setEnableSmoothTransition(true);
|
settings.setEnableSmoothTransition(true);
|
||||||
}
|
}
|
||||||
if (API > 16) {
|
if (API > 16) {
|
||||||
settings.setMediaPlaybackRequiresUserGesture(true);
|
settings.setMediaPlaybackRequiresUserGesture(true);
|
||||||
}
|
}
|
||||||
if (API < 19) {
|
if (API < 19) {
|
||||||
settings.setDatabasePath(context.getFilesDir().getAbsolutePath()
|
settings.setDatabasePath(context.getFilesDir().getAbsolutePath()
|
||||||
@ -450,6 +465,7 @@ public class LightningView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
public synchronized void find(String text) {
|
public synchronized void find(String text) {
|
||||||
if (mWebView != null) {
|
if (mWebView != null) {
|
||||||
if (API > 16) {
|
if (API > 16) {
|
||||||
@ -536,6 +552,7 @@ public class LightningView {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class LightningWebClient extends WebViewClient {
|
public class LightningWebClient extends WebViewClient {
|
||||||
|
|
||||||
Context mActivity;
|
Context mActivity;
|
||||||
@ -548,14 +565,121 @@ public class LightningView {
|
|||||||
public WebResourceResponse shouldInterceptRequest(WebView view,
|
public WebResourceResponse shouldInterceptRequest(WebView view,
|
||||||
String url) {
|
String url) {
|
||||||
if (mAdBlock.isAd(url)) {
|
if (mAdBlock.isAd(url)) {
|
||||||
Log.i("Blocked Domain:", url);
|
|
||||||
ByteArrayInputStream EMPTY = new ByteArrayInputStream(
|
ByteArrayInputStream EMPTY = new ByteArrayInputStream(
|
||||||
"".getBytes());
|
"".getBytes());
|
||||||
WebResourceResponse response = new WebResourceResponse(
|
WebResourceResponse response = new WebResourceResponse(
|
||||||
"text/plain", "utf-8", EMPTY);
|
"text/plain", "utf-8", EMPTY);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
return super.shouldInterceptRequest(view, url);
|
|
||||||
|
boolean useProxy = mPreferences.getBoolean(PreferenceConstants.USE_PROXY, false);
|
||||||
|
boolean mDoLeakHardening = false;
|
||||||
|
|
||||||
|
if (!useProxy)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!mDoLeakHardening)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
//now we are going to proxy!
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
URL uURl = new URL(url);
|
||||||
|
|
||||||
|
Proxy proxy = null;
|
||||||
|
|
||||||
|
String host = mPreferences.getString(PreferenceConstants.USE_PROXY_HOST, "localhost");
|
||||||
|
int port = mPreferences.getInt(PreferenceConstants.USE_PROXY_PORT, 8118);
|
||||||
|
proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
|
||||||
|
|
||||||
|
HttpURLConnection.setFollowRedirects(true);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection)uURl.openConnection(proxy);
|
||||||
|
conn.setInstanceFollowRedirects(true);
|
||||||
|
conn.setRequestProperty("User-Agent", mSettings.getUserAgentString());
|
||||||
|
|
||||||
|
//conn.setRequestProperty("Transfer-Encoding", "chunked");
|
||||||
|
//conn.setUseCaches(false);
|
||||||
|
|
||||||
|
final int bufferSize = 1024 * 32;
|
||||||
|
conn.setChunkedStreamingMode(bufferSize);
|
||||||
|
|
||||||
|
String cType = conn.getContentType();
|
||||||
|
String cEnc = conn.getContentEncoding();
|
||||||
|
int connLen = conn.getContentLength();
|
||||||
|
|
||||||
|
|
||||||
|
if (cType != null)
|
||||||
|
{
|
||||||
|
String[] ctArray = cType.split(";");
|
||||||
|
cType = ctArray[0].trim();
|
||||||
|
|
||||||
|
if (cEnc == null && ctArray.length > 1)
|
||||||
|
{
|
||||||
|
cEnc = ctArray[1];
|
||||||
|
if (cEnc.indexOf('=')!=-1)
|
||||||
|
cEnc = cEnc.split("=")[1].trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connLen <= 0)
|
||||||
|
connLen = 2048;
|
||||||
|
|
||||||
|
if (cType != null && cType.startsWith("text"))
|
||||||
|
{
|
||||||
|
InputStream fStream = null;
|
||||||
|
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
|
||||||
|
ByteArrayBuffer baf = new ByteArrayBuffer(connLen);
|
||||||
|
int read = 0;
|
||||||
|
int bufSize = 2048;
|
||||||
|
byte[] buffer = new byte[bufSize];
|
||||||
|
while(true){
|
||||||
|
read = bis.read(buffer);
|
||||||
|
if(read==-1){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
baf.append(buffer, 0, read);
|
||||||
|
}
|
||||||
|
byte[] plainText = baf.toByteArray();
|
||||||
|
|
||||||
|
fStream = new ByteArrayInputStream(plainText);
|
||||||
|
|
||||||
|
fStream = new ReplacingInputStream(new ByteArrayInputStream(plainText),"poster=".getBytes(),"foo=".getBytes());
|
||||||
|
fStream = new ReplacingInputStream(fStream,"Poster=".getBytes(),"foo=".getBytes());
|
||||||
|
fStream = new ReplacingInputStream(fStream,"Poster=".getBytes(),"foo=".getBytes());
|
||||||
|
fStream = new ReplacingInputStream(fStream,".poster".getBytes(),".foo".getBytes());
|
||||||
|
fStream = new ReplacingInputStream(fStream,"\"poster\"".getBytes(),"\"foo\"".getBytes());
|
||||||
|
|
||||||
|
WebResourceResponse response = new WebResourceResponse(
|
||||||
|
cType, cEnc, fStream);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}/**
|
||||||
|
else if (mDoLeakHardening)
|
||||||
|
{
|
||||||
|
WebResourceResponse response = new WebResourceResponse(
|
||||||
|
cType, cEnc, conn.getInputStream());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
|
||||||
|
}*/
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null; //let webkit handle it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.e("Lightning","Error filtering stream",e);
|
||||||
|
ByteArrayInputStream EMPTY = new ByteArrayInputStream(
|
||||||
|
"".getBytes());
|
||||||
|
WebResourceResponse response = new WebResourceResponse(
|
||||||
|
"text/plain", "utf-8", EMPTY);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -871,9 +995,24 @@ public class LightningView {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onShowCustomView(View view, CustomViewCallback callback) {
|
public void onShowCustomView(View view, CustomViewCallback callback) {
|
||||||
Activity activity = mBrowserController.getActivity();
|
|
||||||
mBrowserController.onShowCustomView(view,
|
if (view instanceof FrameLayout){
|
||||||
activity.getRequestedOrientation(), callback);
|
FrameLayout frame = (FrameLayout) view;
|
||||||
|
if (frame.getFocusedChild() instanceof VideoView){
|
||||||
|
VideoView video = (VideoView) frame.getFocusedChild();
|
||||||
|
video.stopPlayback();
|
||||||
|
frame.removeView(video);
|
||||||
|
video.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Activity activity = mBrowserController.getActivity();
|
||||||
|
mBrowserController.onShowCustomView(view,
|
||||||
|
activity.getRequestedOrientation(), callback);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
super.onShowCustomView(view, callback);
|
super.onShowCustomView(view, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,8 +1020,23 @@ public class LightningView {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public void onShowCustomView(View view, int requestedOrientation,
|
public void onShowCustomView(View view, int requestedOrientation,
|
||||||
CustomViewCallback callback) {
|
CustomViewCallback callback) {
|
||||||
mBrowserController.onShowCustomView(view, requestedOrientation,
|
|
||||||
callback);
|
if (view instanceof FrameLayout){
|
||||||
|
FrameLayout frame = (FrameLayout) view;
|
||||||
|
if (frame.getFocusedChild() instanceof VideoView){
|
||||||
|
VideoView video = (VideoView) frame.getFocusedChild();
|
||||||
|
video.stopPlayback();
|
||||||
|
frame.removeView(video);
|
||||||
|
video.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mBrowserController.onShowCustomView(view, requestedOrientation,
|
||||||
|
callback);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
super.onShowCustomView(view, requestedOrientation, callback);
|
super.onShowCustomView(view, requestedOrientation, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,4 +31,8 @@ public class PreferenceConstants {
|
|||||||
public static final String USER_AGENT = "agentchoose";
|
public static final String USER_AGENT = "agentchoose";
|
||||||
public static final String USER_AGENT_STRING = "userAgentString";
|
public static final String USER_AGENT_STRING = "userAgentString";
|
||||||
public static final String GOOGLE_SEARCH_SUGGESTIONS = "GoogleSearchSuggestions";
|
public static final String GOOGLE_SEARCH_SUGGESTIONS = "GoogleSearchSuggestions";
|
||||||
|
|
||||||
|
public static final String USE_PROXY = "useProxy";
|
||||||
|
public static final String USE_PROXY_HOST = "useProxyHost";
|
||||||
|
public static final String USE_PROXY_PORT = "useProxyPort";
|
||||||
}
|
}
|
||||||
|
91
src/acr/browser/lightning/ReplacingInputStream.java
Normal file
91
src/acr/browser/lightning/ReplacingInputStream.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package acr.browser.lightning;
|
||||||
|
|
||||||
|
import java.io.FilterInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
public class ReplacingInputStream extends FilterInputStream {
|
||||||
|
|
||||||
|
LinkedList<Integer> inQueue = new LinkedList<Integer>();
|
||||||
|
LinkedList<Integer> outQueue = new LinkedList<Integer>();
|
||||||
|
final byte[] search, replacement;
|
||||||
|
|
||||||
|
protected ReplacingInputStream(InputStream in, byte[] search,
|
||||||
|
byte[] replacement) {
|
||||||
|
super(in);
|
||||||
|
this.search = search;
|
||||||
|
this.replacement = replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isMatchFound() {
|
||||||
|
Iterator<Integer> inIter = inQueue.iterator();
|
||||||
|
for (int i = 0; i < search.length; i++)
|
||||||
|
if (!inIter.hasNext() || search[i] != inIter.next())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readAhead() throws IOException {
|
||||||
|
// Work up some look-ahead.
|
||||||
|
while (inQueue.size() < search.length) {
|
||||||
|
int next = super.read();
|
||||||
|
inQueue.offer(next);
|
||||||
|
if (next == -1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read() throws IOException {
|
||||||
|
|
||||||
|
// Next byte already determined.
|
||||||
|
if (outQueue.isEmpty()) {
|
||||||
|
|
||||||
|
readAhead();
|
||||||
|
|
||||||
|
if (isMatchFound()) {
|
||||||
|
for (int i = 0; i < search.length; i++)
|
||||||
|
inQueue.remove();
|
||||||
|
|
||||||
|
for (byte b : replacement)
|
||||||
|
outQueue.offer((int) b);
|
||||||
|
} else
|
||||||
|
outQueue.add(inQueue.remove());
|
||||||
|
}
|
||||||
|
|
||||||
|
return outQueue.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns false. REFilterInputStream does not support mark() and
|
||||||
|
* reset() methods.
|
||||||
|
*/
|
||||||
|
public boolean markSupported() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reads from the stream into the provided array.
|
||||||
|
* @throws IOException */
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
int i;
|
||||||
|
int ok = 0;
|
||||||
|
while (len-- > 0) {
|
||||||
|
i = read();
|
||||||
|
if (i == -1) return (ok == 0) ? -1 : ok;
|
||||||
|
b[off++] = (byte) i;
|
||||||
|
ok++;
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buffer) throws IOException {
|
||||||
|
|
||||||
|
return read(buffer, 0, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user