view core/src/luan/modules/PickleCon.java @ 216:a1b142f9c5c0

make Utils.toUrl() check for "index.html" or "index.html.luan" in dirs for jars (hack) git-svn-id: https://luan-java.googlecode.com/svn/trunk@217 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Mon, 14 Jul 2014 06:11:55 +0000
parents 75750ceb45ee
children ec016471c6eb
line wrap: on
line source

package luan.modules;

import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.IdentityHashMap;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import luan.Luan;
import luan.LuanTable;
import luan.LuanState;
import luan.LuanFunction;
import luan.LuanJavaFunction;
import luan.LuanException;


public final class PickleCon {
	final LuanState luan;
	private final DataInputStream in;
	private final LuanFunction _read_binary;
	private final DataOutputStream out;
	private final List<byte[]> binaries = new ArrayList<byte[]>();
	String src;
	final LuanTable env = new LuanTable();

	PickleCon(LuanState luan,DataInputStream in,DataOutputStream out) {
		this.in = in;
		this.luan = luan;
		try {
			this._read_binary = new LuanJavaFunction(
				PickleCon.class.getMethod( "_read_binary", Integer.TYPE ), this
			);
		} catch(NoSuchMethodException e) {
			throw new RuntimeException(e);
		}

		this.out = out;
	}

	public byte[] _read_binary(int size) throws IOException, LuanException {
		byte[] a = new byte[size];
		int i = 0;
		while( i < size ) {
			int n = in.read(a,i,size-i);
			if( n == -1 )
				throw luan.exception( "end of stream" );
			i += n;
		}
		return a;
	}

	public Object read() throws IOException, LuanException {
		env.put("_read_binary",_read_binary);
		try {
			src = in.readUTF();
			LuanFunction fn = BasicLuan.load(luan,src,"pickle-reader",env,false);
			return luan.call(fn);
		} finally {
			env.put("_binaries",null);
			env.put("_read_binary",null);
		}
	}

	public String pickle(Object obj) throws LuanException {
		if( obj == null )
			return "nil";
		if( obj instanceof Boolean )
			return Luan.toString((Boolean)obj);
		if( obj instanceof Number )
			return Luan.toString((Number)obj);
		if( obj instanceof String )
			return "\"" + Luan.stringEncode((String)obj) + "\"";
		if( obj instanceof LuanTable )
			return pickle( (LuanTable)obj, Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) );
		if( obj instanceof byte[] ) {
			byte[] a = (byte[])obj;
			binaries.add(a);
			return "_binaries[" + binaries.size() + "]";
		}
		throw luan.exception( "invalid type: " + obj.getClass() );
	}

	private String pickle(Object obj,Set<LuanTable> set) throws LuanException {
		return obj instanceof LuanTable ? pickle((LuanTable)obj,set) : pickle(obj);
	}

	private String pickle(LuanTable tbl,Set<LuanTable> set) throws LuanException {
		if( !set.add(tbl) ) {
			throw luan.exception( "circular reference in table" );
		}
		StringBuilder sb = new StringBuilder();
		sb.append( "{" );
		for( Map.Entry<Object,Object> entry : tbl ) {
			sb.append( "[" );
			sb.append( pickle(entry.getKey(),set) );
			sb.append( "]=" );
			sb.append( pickle(entry.getValue(),set) );
			sb.append( ", " );
		}
		sb.append( "}" );
		return sb.toString();
	}

	public void write(Object... args) throws LuanException, IOException {
		StringBuilder sb = new StringBuilder();
		if( !binaries.isEmpty() ) {
			sb.append( "_binaries = {}\n" );
			for( byte[] a : binaries ) {
				sb.append( "_binaries[#_binaries+1] = _read_binary(" + a.length + ")\n" );
			}
		}
		for( Object obj : args ) {
			sb.append( luan.toString(obj) );
		}
		out.writeUTF( sb.toString() );
		for( byte[] a : binaries ) {
			out.write(a);
		}
		out.flush();
		binaries.clear();
	}

	public void close() throws IOException {
		in.close();
		out.close();
	}
}