⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 browser.java

📁 手机Wap浏览器源码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package com.gameislive.browser;

import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.util.Vector;
import java.util.Stack;
import java.util.Hashtable;

import javax.microedition.lcdui.*;
import javax.microedition.io.HttpConnection;

import com.gameislive.browser.element.*;

/**
 * 
 * @author pan
 *
 */
public class Browser implements Runnable,CommandListener{

	static final byte LOAD_STEP_NOTHING = 0;	
	static final byte LOAD_STEP_CONNECTION = 1;	
	static final byte LOAD_STEP_CONTENT = 2;
	static final byte LOAD_STEP_PARSER = 3;
	
	public int fontHeight;
	
	/**
	 * 当图片无法加载时,显示的图片(表示无效图片)
	 */
    Image noneImage;
	
	Font font;
	
	String urlBase;
    
	String urlRoot;
	
	Cache cache;
	
	/**
	 * browser在canvas中的位置
	 */
	int x,y;

	/**
	 * browser的大小
	 */
	public int width,height;
	
    /**
     * 当前的http请求
     */
    public HttpRequest curRequest;
    /**
     * curRequest请求是否需要发送出去
     */
    private byte loadStep;    
    /**
     * 保存Cookies信息
     */
    private Hashtable cookies = new Hashtable();    
    /**
     * 默认的编码
     */
    private String encoding="UTF-8";

    private Display display;
    
    /**
     * 保存历史请求URL的堆栈
     */
    private Stack historyUrl;
    
    private WapRender wapRender;
    
    private Command inputOk = new Command("确定",Command.OK,0);
    private Command inputBack = new Command("返回",Command.BACK,1);
    private TextBox inputTextBox;
    private List selectList;
    
	public Browser(int x,int y,int w,int h,Display display){
		this.x = x;
		this.y = y;
		this.width = w;
		this.height = h;
		this.display = display;
		
		font = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_PLAIN,Font.SIZE_SMALL);
		fontHeight = font.getHeight();
		Tools.font = font;
		
		try{
			noneImage = Image.createImage("/noneimg.png");
		}catch(Exception e){
			e.printStackTrace();
		}    	
		
		historyUrl = new Stack();		
		wapRender = new WapRender(this);

		// 默认创建64k的缓冲池来保存图片数据
		cache = new Cache(64 * 1024);
	}
	
	public void setEncoding(String enc){
		encoding = enc;
	}
	
	public String getEncoding(){
		return encoding;
	}
	
	/**
	 * 返回上一请求页面
	 * @return
	 */
	public HttpRequest getLastRequest(){
		if(historyUrl.size()>0){
			return (HttpRequest)historyUrl.elementAt(historyUrl.size()-1);
		}
		return null;
	}
	
	/**
	 * 默认的GET请求
	 * @param url
	 */
	public void request(String url){
		if(url!=null && !url.equals("")){
			// 如果旧的请求不为空,则保存之,以便将来可以返回
			if(curRequest!=null){
				historyUrl.push(curRequest);
			}
			curRequest = new HttpRequest(url,HttpConnection.GET,null,null);
			loadStep = LOAD_STEP_CONNECTION;
			
			if(cardid!=null && !cardid.equals("")){
				curRequest.setFragment(cardid);
				cardid = null;
			}
		}
	}
	
	private void request(HttpRequest req){
		curRequest = req;
		loadStep = LOAD_STEP_CONNECTION;
	}
	
	/**
	 * 返回上一请求的页面
	 */
	public void back(){
		if(historyUrl.size()>0){
			request((HttpRequest)historyUrl.pop());
		}
	}
	
	public void execute(){		
		if(loadStep == LOAD_STEP_NOTHING){
			// nothing to do
		}else if(loadStep == LOAD_STEP_PARSER){
			// nothing to do
		}else if(loadStep == LOAD_STEP_CONNECTION){
			// 打开连接线程
			new Thread(this).start();	
		}
	}
	
	/**
	 * 连接线程,请求服务器,加载图片等资源<br>
	 * 有新请求时,该线程才会被打开
	 */
	public void run(){
		
		// 开始请求服务器
		loadStep = LOAD_STEP_CONTENT;
		
		String errorMsg = null;		
		byte[] buffer = null;
		
		try{
			buffer = flushRequest();				
		}catch(Exception e){
			e.printStackTrace();
			errorMsg = e.getMessage();
		}
		
		// 开始渲染
		loadStep = LOAD_STEP_PARSER;
		
		if(buffer==null){
			String str = "Error!<br/>"
				+ "Document <a href=\"" + curRequest.getUrl()
				+ "\">"+curRequest.getUrl()+"</a> Can't found!<br/>"
				+ "<br/>you can use proxy or cmnet and try again.";
				str = str + "<br/>" + errorMsg;
			renderString(str);
		}else{
			// 渲染一个页面
			renderByteArray(buffer,encoding);			
		}
		
		//renderLocalDocument("/info.htm");
		
		// 请求完毕
		loadStep = LOAD_STEP_NOTHING;		
		
		// 处理onevent标记的事件
		if(onEvent)
		{
			executeOnEvent();
			// onevent事件执行完毕,清空onEventParaTable
			onEventParaTable.clear();
			onEventParaTable = null;
			onEvent = false;
		}
	}
	
	/**
	 * 是否执行onevent标记事件
	 */
	private boolean onEvent;	
	/**
	 * 保存onevent标记事件参数的hashtable
	 */
	private Hashtable onEventParaTable;
	
	/**
	 * 提示有onevent事件执行
	 * @param table
	 */
	void onEvent(Hashtable table){
		onEvent = true;
		onEventParaTable = table;
	}
	
	/**
	 * 执行onevent标记的事件,四种:<br>
	 * -onenterbackward<br>
	 * -onenterforward<br>
	 * -onpick<br>
	 * -ontimer
	 */
	void executeOnEvent(){
		// 获得onevent类型
		String type = (String)onEventParaTable.get("type");
		if(type!=null && !type.equals("")){
			if(type.equals("onenterforward")){
				String href = (String)onEventParaTable.get("href");
				request(getUrl(href));				
			}else if(type.equals("onenterbackward")){
				
			}else if(type.equals("ontimer")){
				
			}else if(type.equals("onpick")){
				
			}
		}
	}

	/**
	 * 发送请求,获取服务器响应,并设置可能的cookie
	 * @return
	 * @throws Exception
	 */
	byte[] flushRequest()throws Exception{	
		byte[] buffer = null;		
		getUrlRootAndBase(curRequest.getUrl());		
		// 检查是否返回session id
		String sessionid = null;
		if(urlBase!=null){
			sessionid = (String)cookies.get(urlBase);
			if(sessionid!=null) curRequest.addHeader("Cookie", sessionid);
		}

		buffer = HttpConnector.sendHttpRequest(curRequest, "",this);
		sessionid = HttpConnector.getLastResponseCookie();
		// 设置cookie
		if(sessionid!=null && !sessionid.equals("")){
			cookies.put(urlBase, sessionid);
		}		
		
		return buffer;
	}
	
	/**
	 * 渲染本地文档
	 * @param filename
	 */
	public void renderLocalDocument(String filename){
		try{
			InputStream is = this.getClass().getResourceAsStream(filename);
			byte buffer[] = new byte[is.available()];
			is.read(buffer);
			renderByteArray(buffer,null);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * 渲染一段字符串
	 * @param string
	 */
	public void renderString(String string){
		renderByteArray(string.getBytes(),null);
	}
	
	/**
	 * 用指定的编码格式渲染缓冲区byte[]内的文档
	 * @param buffer
	 * @param encoding
	 */
	void renderByteArray(byte[] buffer,String encoding){
		
		// 将缓冲区内的数据转换成流,以便解释文档
		ByteArrayInputStream bais = null;
		InputStreamReader isr = null;		
		bais = new ByteArrayInputStream(buffer, 0, buffer.length);
		try {
			if(encoding!=null && !encoding.equals("")){
				isr = new InputStreamReader(bais, encoding);
			}else{
				isr = new InputStreamReader(bais);
			}
		} catch (Exception e) {
			e.printStackTrace();
			isr = new InputStreamReader(bais);
		}
		
//		tmpVector保存的已经是wml文档了
//		标准的wml文档格式,如下边:
//		<?xml version="1.0" encoding="utf-8"?>
//		<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
//		<wml>
//		<head>
//		<meta http-equiv="Cache-Control" content="no-cache" />
//		</head>
//		<card id="forward" title="">
//		<onevent type="onenterforward">
//		<go href="signonForm.do" />
//		</onevent>
//		<p align="left">
//		... 
//		</p>
//		</card>
//		</wml>
		Vector tmpVector = Tools.ToDocument(isr);
		
		//#if DEBUG
		//# System.out.println("==============[WML Document]============");
		//# for(int i=0;i<tmpVector.size();i++){
			//# System.out.println((String)tmpVector.elementAt(i));
		//# }
		//# System.out.println("========================================");
		//#endif

		renderVector(tmpVector);
	}
	
	/**
	 * vector里保存的是整理好的标准wml文档
	 * @param vector
	 */
	void renderVector(Vector vector){
		Vector pendingRenderTag = null;
		try{
			pendingRenderTag = Tag.Tree(vector);
			//#if DEBUG
			//# for(int i=0;i<pendingRenderTag.size();i++ ){
				//# Object obj =pendingRenderTag.elementAt(i);
				//# System.out.println(obj.toString());
			//# }
			//#endif
			maxElementNum = pendingRenderTag.size();			
		}catch(Exception e){
			e.printStackTrace();
		}
		
		// 渲染前先重设Render
		wapRender.reset();
		
		if(curRequest!=null){
			wapRender.explainTag(pendingRenderTag,curRequest.getFragment());
		}else{
			wapRender.explainTag(pendingRenderTag,null);
		}
		
	}
	
	/**
	 * 获得请求的URL的base和root,以便以后及载如图片之类的资源<br>
	 * 例如,url为 http://zg.gameislive.com/cn/gamedev/pan/t1.wml<br>
	 * 那么将获得:<br>
	 * URL root: http://zg.gameislive.com/<br>
	 * URL base: http://zg.gameislive.com/cn/gamedev/pan/<br>
	 * @param url
	 */
	void getUrlRootAndBase(String url){
		urlRoot = Tools.GetURLRoot(url);
		String tempURL = "";
		int commaIndex = url.indexOf('?');
		if (commaIndex != -1) {
			tempURL = url.substring(0, commaIndex);
		} else {
			tempURL = url;
		}
		//commaIndex = tempURL.lastIndexOf('/');
		//urlBase = tempURL.substring(0, commaIndex + 1);
		
		urlBase = Tools.GetURLBase(tempURL);
		
		//#if DEBUG
		//# System.out.println("[URL root]: "+urlRoot);
		//# System.out.println("[URL base]: "+urlBase);
		//#endif
	}
	
	private String cardid;
	
	/**
	 * 当请求的地址不完整时(可能是相对路径),可通过该方法补充完整的URL<br>
	 * 注意,需要和urlBase,urlRoot一起使用<br>
	 * 使用时必须先getUrlRootAndBase(String)
	 * @param s
	 * @return
	 */
	public String getUrl(String s) {
		if (s.startsWith("http://")) {
			return s;
		}
		int index = s.indexOf('#');
		if (index!=-1) {
			cardid = s.substring(index+1);
			return curRequest.getUrl();
		}
		if (s.startsWith("/") || s.startsWith("\\")) {
			s = s.substring(1);
			return urlRoot + s;
		} else {
			return urlBase + s;
		}
	}
	
    /**
     * 发送一个HTTP请求,加载图片,目前支持三种图片格式: <br/>
     * -image/png <br/>
     * -image/gif <br/>
     * -image/jpeg <br/>
     * @param s url
     */
    Image loadImage(String s) {
        try {
        	Image image = null;
        	// read local resource
        	if(s.startsWith("res:")){
            	String filename = Tools.RepString(s, "res:", "");
            	image = Image.createImage(filename);
            	return image;
            }
        	
            byte buffer[] = null;
            s = Tools.RepString(s, "&amp;", "&");
            s = getUrl(s);
            String type = null;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -