[Red5commits] [1660] merged changes from branch "joachim_amf3_integration" back in trunk

jbauch luke at codegent.com
Thu Jan 25 16:40:21 EST 2007


merged changes from branch "joachim_amf3_integration" back in trunk


Timestamp: 01/25/07 16:02:18 EST (less than one hour ago) 
Change: 1660 
Author: jbauch

Files (see diff or trac for details): 
doc/trunk/changelog.txt
java/server/trunk/.classpath
java/server/trunk/build.xml
java/server/trunk/src/org/red5/io/amf/Input.java
java/server/trunk/src/org/red5/io/amf/Output.java
java/server/trunk/src/org/red5/io/amf3/AMF3.java
java/server/trunk/src/org/red5/io/amf3/Input.java
java/server/trunk/src/org/red5/io/amf3/Output.java
java/server/trunk/src/org/red5/io/flv/impl/FLVReader.java
java/server/trunk/src/org/red5/io/mock/Input.java
java/server/trunk/src/org/red5/io/mock/Output.java
java/server/trunk/src/org/red5/io/mp3/impl/MP3Reader.java
java/server/trunk/src/org/red5/io/object/BaseInput.java
java/server/trunk/src/org/red5/io/object/BaseOutput.java
java/server/trunk/src/org/red5/io/object/Deserializer.java
java/server/trunk/src/org/red5/io/object/Input.java
java/server/trunk/src/org/red5/io/object/Output.java
java/server/trunk/src/org/red5/io/object/RecordSet.java
java/server/trunk/src/org/red5/io/object/Serializer.java
java/server/trunk/src/org/red5/io/utils/ObjectMap.java
java/server/trunk/src/org/red5/server/JettyLoader.java
java/server/trunk/src/org/red5/server/net/remoting/RemotingClient.java
java/server/trunk/src/org/red5/server/net/rtmp/BaseRTMPHandler.java
java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventDecoder.java
java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventEncoder.java
java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java
java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolEncoder.java
java/server/trunk/src/org/red5/server/net/rtmp/codec/SharedObjectSerializer.java
java/server/trunk/src/org/red5/server/net/rtmp/event/FlexMessage.java
java/server/trunk/src/org/red5/server/net/rtmp/message/Constants.java
java/server/trunk/src/org/red5/server/so/FlexSharedObjectMessage.java
java/server/trunk/swf/DEV_Source/classes/org/red5/samples/echo
java/server/trunk/swf/DEV_Source/classes/org/red5/samples/echo/EchoClass.as
java/server/trunk/swf/DEV_Source/echotest.mxml
java/server/trunk/webapps/echo
java/server/trunk/webapps/echo/WEB-INF
java/server/trunk/webapps/echo/WEB-INF/log4j.properties
java/server/trunk/webapps/echo/WEB-INF/red5-web.properties
java/server/trunk/webapps/echo/WEB-INF/red5-web.xml
java/server/trunk/webapps/echo/WEB-INF/src
java/server/trunk/webapps/echo/WEB-INF/src/org
java/server/trunk/webapps/echo/WEB-INF/src/org/red5
java/server/trunk/webapps/echo/WEB-INF/src/org/red5/server
java/server/trunk/webapps/echo/WEB-INF/src/org/red5/server/webapp
java/server/trunk/webapps/echo/WEB-INF/src/org/red5/server/webapp/echo
java/server/trunk/webapps/echo/WEB-INF/src/org/red5/server/webapp/echo/Application.java
java/server/trunk/webapps/echo/WEB-INF/web.xml


Trac: http://mirror1.cvsdude.com/trac/osflash/red5/changeset/1660

Index: /java/server/trunk/src/org/red5/server/so/FlexSharedObjectMessage.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/FlexSharedObjectMessage.java (revision 1660)
+++ /java/server/trunk/src/org/red5/server/so/FlexSharedObjectMessage.java (revision 1660)
@@ -0,0 +1,39 @@
+package org.red5.server.so;
+
+import org.red5.server.api.event.IEventListener;
+
+public class FlexSharedObjectMessage extends SharedObjectMessage {
+
+    /**
+     * Creates Flex2 Shared Object event with given name, version and persistence flag
+     *
+     * @param name          Event name
+     * @param version       SO version
+     * @param persistent    SO persistence flag
+     */
+    public FlexSharedObjectMessage(String name, int version, boolean persistent) {
+		this(null, name, version, persistent);
+	}
+
+    /**
+     * Creates Flex2 Shared Object event with given listener, name, SO version and persistence flag
+     *
+     * @param source         Event listener
+     * @param name           Event name
+     * @param version        SO version
+     * @param persistent     SO persistence flag
+     */
+    public FlexSharedObjectMessage(IEventListener source, String name, int version,
+			boolean persistent) {
+    	super(source, name, version, persistent);
+    	
+    }
+
+	/** {@inheritDoc} */
+    @Override
+	public byte getDataType() {
+		return TYPE_FLEX_SHARED_OBJECT;
+	}
+
+
+}
Index: /java/server/trunk/src/org/red5/server/net/rtmp/event/FlexMessage.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/event/FlexMessage.java (revision 1606)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/event/FlexMessage.java (revision 1660)
@@ -10,7 +10,7 @@
 	}
 	
-	@Override
+	/** {@inheritDoc} */
+    @Override
 	public byte getDataType() {
-		// TODO Auto-generated method stub
 		return TYPE_FLEX_MESSAGE;
 	}
Index: /java/server/trunk/src/org/red5/server/net/rtmp/message/Constants.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/message/Constants.java (revision 1628)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/message/Constants.java (revision 1660)
@@ -69,6 +69,11 @@
     public static final byte TYPE_VIDEO_DATA = 0x09;
 
-	// Unknown: 0x0A ...  0x10
-
+	// Unknown: 0x0A ...  0x0F
+
+    /**
+     * AMF3 shared object
+     */
+    public static final byte TYPE_FLEX_SHARED_OBJECT = 0x10;
+    
     /**
      * AMF3 message
Index: /java/server/trunk/src/org/red5/server/net/rtmp/BaseRTMPHandler.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/BaseRTMPHandler.java (revision 1654)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/BaseRTMPHandler.java (revision 1660)
@@ -163,4 +163,5 @@
 						((IEventDispatcher) stream).dispatchEvent(message);
 					break;
+				case TYPE_FLEX_SHARED_OBJECT:
 				case TYPE_SHARED_OBJECT:
 					onSharedObject(conn, channel, header,
Index: /java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventDecoder.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventDecoder.java (revision 1631)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventDecoder.java (revision 1660)
@@ -60,4 +60,12 @@
 
     /**
+     * Decodes shared object message event from AMF3 encoding
+     * @param in                     Byte buffer to decode
+     * @param rtmp					 RTMP protocol state
+     * @return                       ISharedObjectMessage event
+     */
+	public abstract ISharedObjectMessage decodeFlexSharedObject(ByteBuffer in, RTMP rtmp);
+
+    /**
      * Decodes notification event
      * @param in                     Byte buffer to decode
Index: /java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolEncoder.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolEncoder.java (revision 1654)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolEncoder.java (revision 1660)
@@ -79,17 +79,4 @@
     private Serializer serializer;
 
-    /**
-     * Creates output object from byte buffer
-     * @param buffer
-     * @return
-     */
-    private Output getOutput(RTMP rtmp, ByteBuffer buffer) {
-		if (rtmp.getEncoding() == Encoding.AMF3) {
-			return new org.red5.io.amf3.Output(buffer);
-		} else {
-			return new org.red5.io.amf.Output(buffer);
-		}
-	}
-
 	/** {@inheritDoc} */
     public ByteBuffer encode(ProtocolState state, Object message)
@@ -259,4 +246,6 @@
 			case TYPE_VIDEO_DATA:
 				return encodeVideoData((VideoData) message);
+			case TYPE_FLEX_SHARED_OBJECT:
+				return encodeFlexSharedObject((ISharedObjectMessage) message, rtmp);
 			case TYPE_SHARED_OBJECT:
 				return encodeSharedObject((ISharedObjectMessage) message, rtmp);
@@ -268,4 +257,5 @@
 				return encodeFlexMessage((FlexMessage) message, rtmp);
 			default:
+				log.warn("Unknown object type: " + header.getDataType());
 				return null;
 		}
@@ -303,9 +293,29 @@
 
 	/** {@inheritDoc} */
-    public ByteBuffer encodeSharedObject(ISharedObjectMessage so, RTMP rtmp) {
-
+    public ByteBuffer encodeFlexSharedObject(ISharedObjectMessage so, RTMP rtmp) {
 		final ByteBuffer out = ByteBuffer.allocate(128);
 		out.setAutoExpand(true);
-		final Output output = getOutput(rtmp, out);
+		out.put((byte) 0x00);
+    	doEncodeSharedObject(so, rtmp, out);
+    	return out;
+    }
+    
+	/** {@inheritDoc} */
+    public ByteBuffer encodeSharedObject(ISharedObjectMessage so, RTMP rtmp) {
+		final ByteBuffer out = ByteBuffer.allocate(128);
+		out.setAutoExpand(true);
+    	doEncodeSharedObject(so, rtmp, out);
+    	return out;
+    }
+
+    /**
+     * Perform the actual encoding of the shared object contents.
+     * 
+     * @param so
+     * @param rtmp
+     * @param out
+     */
+    public void doEncodeSharedObject(ISharedObjectMessage so, RTMP rtmp, ByteBuffer out) {
+		final Output output = new org.red5.io.amf.Output(out);
 
 		output.putString(so.getName());
@@ -418,5 +428,4 @@
             }
         }
-        return out;
 	}
 
@@ -478,5 +487,9 @@
 			output = new org.red5.io.amf.Output(out);
 		} else {
-			output = getOutput(rtmp, out);
+			if (rtmp.getEncoding() == Encoding.AMF3) {
+				output = new org.red5.io.amf3.Output(out);
+			} else {
+				output = new org.red5.io.amf.Output(out);
+			}
 		}
 		
Index: /java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventEncoder.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventEncoder.java (revision 1631)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/codec/IEventEncoder.java (revision 1660)
@@ -101,3 +101,11 @@
     public abstract ByteBuffer encodeSharedObject(ISharedObjectMessage so, RTMP rtmp);
 
+    /**
+     * Encodes SharedObjectMessage event to byte buffer using AMF3 encoding
+     * @param so                 ISharedObjectMessage event
+     * @param rtmp			 RTMP protocol state
+     * @return                   Byte buffer
+     */
+    public ByteBuffer encodeFlexSharedObject(ISharedObjectMessage so, RTMP rtmp);
+
 }
Index: /java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java (revision 1654)
+++ /java/server/trunk/src/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java (revision 1660)
@@ -56,4 +56,5 @@
 import org.red5.server.service.Call;
 import org.red5.server.service.PendingCall;
+import org.red5.server.so.FlexSharedObjectMessage;
 import org.red5.server.so.ISharedObjectEvent;
 import org.red5.server.so.ISharedObjectMessage;
@@ -87,19 +88,4 @@
     public RTMPProtocolDecoder() {
 
-	}
-
-    /**
-     * Return input (data values provider) object from byte buffer. 
-     *
-     * @param rtmp			RTMP protocol state
-     * @param buffer        Byte buffer
-     * @return              Input object
-     */
-    private Input getInput(RTMP rtmp, ByteBuffer buffer) {
-		if (rtmp.getEncoding() == Encoding.AMF3) {
-			return new org.red5.io.amf3.Input(buffer);
-		} else {
-			return new org.red5.io.amf.Input(buffer);
-		}
 	}
 
@@ -438,4 +424,7 @@
 				message = decodeVideoData(in);
 				break;
+			case TYPE_FLEX_SHARED_OBJECT:
+				message = decodeFlexSharedObject(in, rtmp);
+				break;
 			case TYPE_SHARED_OBJECT:
 				message = decodeSharedObject(in, rtmp);
@@ -451,4 +440,5 @@
 				break;
 			default:
+				log.warn("Unknown object type: " + header.getDataType());
 				message = decodeUnknown(header.getDataType(), in);
 				break;
@@ -488,7 +478,8 @@
 
 	/** {@inheritDoc} */
-	public ISharedObjectMessage decodeSharedObject(ByteBuffer in, RTMP rtmp) {
-
-		final Input input = getInput(rtmp, in);
+	public ISharedObjectMessage decodeFlexSharedObject(ByteBuffer in, RTMP rtmp) {
+		// Unknown byte, always 0?
+		in.skip(1);
+		final Input input = new org.red5.io.amf.Input(in);
 		String name = input.getString();
 		// Read version of SO to modify
@@ -499,7 +490,35 @@
 		in.skip(4);
 
-		final SharedObjectMessage so = new SharedObjectMessage(null, name,
+		final SharedObjectMessage so = new FlexSharedObjectMessage(null, name,
 				version, persistent);
-
+		doDecodeSharedObject(so, in, input);
+		return so;
+	}
+	
+	/** {@inheritDoc} */
+	public ISharedObjectMessage decodeSharedObject(ByteBuffer in, RTMP rtmp) {
+		final Input input = new org.red5.io.amf.Input(in);
+		String name = input.getString();
+		// Read version of SO to modify
+		int version = in.getInt();
+		// Read persistence informations
+		boolean persistent = in.getInt() == 2;
+		// Skip unknown bytes
+		in.skip(4);
+
+		final SharedObjectMessage so = new FlexSharedObjectMessage(null, name,
+				version, persistent);
+		doDecodeSharedObject(so, in, input);
+		return so;
+	}
+
+	/**
+	 * Perform the actual decoding of the shared object contents.
+	 * 
+	 * @param so
+	 * @param in
+	 * @param rtmp
+	 */
+	protected void doDecodeSharedObject(SharedObjectMessage so, ByteBuffer in, Input input) {
 		// Parse request body
 		while (in.hasRemaining()) {
@@ -554,5 +573,4 @@
 			so.addEvent(type, key, value);
 		}
-		return so;
 	}
 
@@ -598,5 +616,9 @@
 		// TODO: we should use different code depending on server or client mode
 		int start = in.position();
-		Input input = getInput(rtmp, in);
+		Input input;
+		if (rtmp.getEncoding() == Encoding.AMF3)
+			input = new org.red5.io.amf3.Input(in);
+		else
+			input = new org.red5.io.amf.Input(in);
 
 		String action = (String) deserializer.deserialize(input);
Index: /va/server/trunk/src/org/red5/server/net/rtmp/codec/SharedObjectSerializer.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/rtmp/codec/SharedObjectSerializer.java (revision 1406)
+++  (revision )
@@ -1,77 +1,0 @@
-package org.red5.server.net.rtmp.codec;
-
-/*
- * RED5 Open Source Flash Server - http://www.osflash.org/red5
- * 
- * Copyright (c) 2006 by respective authors (see below). All rights reserved.
- * 
- * This library is free software; you can redistribute it and/or modify it under the 
- * terms of the GNU Lesser General Public License as published by the Free Software 
- * Foundation; either version 2.1 of the License, or (at your option) any later 
- * version. 
- * 
- * This library is distributed in the hope that it will be useful, but WITHOUT ANY 
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public License along 
- * with this library; if not, write to the Free Software Foundation, Inc., 
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
- */
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.collections.BeanMap;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.red5.io.object.Output;
-import org.red5.io.object.Serializer;
-
-/**
- * Data serializer for shared objects.
- * 
- * @author The Red5 Project (red5 at osflash.org)
- * @author Joachim Bauch (jojo at struktur.de)
- */
-public class SharedObjectSerializer extends Serializer {
-
-	// Initialize Logging
-	protected static Log log = LogFactory.getLog(SharedObjectSerializer.class
-			.getName());
-
-	/**
-	 * Writes a map to the output.
-	 * 
-	 * @param out
-	 * 			output stream
-	 * @param map
-	 * 			Map object to serialize
-	 */
-	@Override
-	public void writeMap(Output out, Map map) {
-		if (log.isDebugEnabled()) {
-			log.debug("writeMap");
-		}
-
-		final Set set = map.entrySet();
-		// NOTE: we need to encode maps as objects for shared objects
-		out.writeStartObject(null);
-		Iterator it = set.iterator();
-		boolean isBeanMap = (map instanceof BeanMap);
-		while (it.hasNext()) {
-			Map.Entry entry = (Map.Entry) it.next();
-			if (isBeanMap && ((String) entry.getKey()).equals("class")) {
-				continue;
-			}
-			out.writeItemKey(entry.getKey().toString());
-			serialize(out, entry.getValue());
-			if (it.hasNext()) {
-				out.markPropertySeparator();
-			}
-		}
-		out.markEndObject();
-	}
-
-}
Index: /java/server/trunk/src/org/red5/server/net/remoting/RemotingClient.java
===================================================================
--- /java/server/trunk/src/org/red5/server/net/remoting/RemotingClient.java (revision 1654)
+++ /java/server/trunk/src/org/red5/server/net/remoting/RemotingClient.java (revision 1660)
@@ -149,10 +149,5 @@
 		tmp.setAutoExpand(true);
 		Output tmpOut = new Output(tmp);
-		Serializer serializer = new Serializer();
-		tmpOut.writeStartArray(params.length);
-		for (Object param : params) {
-			serializer.serialize(tmpOut, param);
-		}
-		tmpOut.markEndArray();
+		tmpOut.writeArray(params, new Serializer());
 		tmp.flip();
 
Index: /java/server/trunk/src/org/red5/server/JettyLoader.java
===================================================================
--- /java/server/trunk/src/org/red5/server/JettyLoader.java (revision 1654)
+++ /java/server/trunk/src/org/red5/server/JettyLoader.java (revision 1660)
@@ -20,6 +20,4 @@
  */
 
-import java.io.IOException;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -34,4 +32,6 @@
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.io.IOException;
 
 /**
Index: /java/server/trunk/src/org/red5/io/amf3/Input.java
===================================================================
--- /java/server/trunk/src/org/red5/io/amf3/Input.java (revision 1654)
+++ /java/server/trunk/src/org/red5/io/amf3/Input.java (revision 1660)
@@ -21,9 +21,11 @@
 
 import java.io.IOException;
-import java.util.Calendar;
+import java.util.ArrayList;
 import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.beanutils.BeanUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -31,4 +33,8 @@
 import org.red5.io.amf.AMF;
 import org.red5.io.object.DataTypes;
+import org.red5.io.object.Deserializer;
+import org.red5.io.object.RecordSet;
+import org.red5.io.object.RecordSetPage;
+import org.red5.io.utils.ObjectMap;
 
 /**
@@ -44,4 +50,12 @@
      */
 	protected static Log log = LogFactory.getLog(Input.class.getName());
+	/**
+	 * Set to a value above <tt>0</tt> to enforce AMF3 decoding mode.
+	 */
+	private int amf3_mode;
+	/**
+	 * List of string values found in the input stream.
+	 */
+	private List<String> stringReferences;
 
 	/**
@@ -52,4 +66,6 @@
 	public Input(ByteBuffer buf) {
 		super(buf);
+		amf3_mode = 0;
+		stringReferences = new ArrayList<String>();
 	}
 
@@ -71,5 +87,5 @@
 		if (currentDataType == AMF.TYPE_AMF3_OBJECT) {
 			currentDataType = buf.get();
-		} else {
+		} else if (amf3_mode == 0) {
 			// AMF0 object
 			return readDataType(currentDataType);
@@ -168,10 +184,11 @@
 	public String readString() {
 		int len = readAMF3Integer();
-		if (len == 0)
+		if (len == 1)
+			// Empty string
 			return "";
 		
 		if ((len & 1) == 0) {
 			// Reference
-			return (String) getReference(len >> 1);
+			return stringReferences.get(len >> 1);
 		}
 		len >>= 1;
@@ -181,5 +198,5 @@
 		final String string = AMF3.CHARSET.decode(strBuf).toString();
 		buf.limit(limit); // Reset the limit
-		storeReference(string);
+		stringReferences.add(string);
 		return string;
 	}
@@ -192,20 +209,13 @@
 	@Override
 	public Date readDate() {
-		/*
-		 * Date: 0x0B T7 T6 .. T0 Z1 Z2 T7 to T0 form a 64 bit Big Endian number
-		 * that specifies the number of nanoseconds that have passed since
-		 * 1/1/1970 0:00 to the specified time. This format is ÒUTC 1970Ó. Z1 an
-		 * Z0 for a 16 bit Big Endian number indicating the indicated timeÕs
-		 * timezone in minutes.
-		 */
+		int ref = readAMF3Integer();
+		if ((ref & 1) == 0) {
+			// Reference to previously found date
+			return (Date) getReference(ref >> 1);
+		}
+		
 		long ms = (long) buf.getDouble();
-		short clientTimeZoneMins = buf.getShort();
-		ms += clientTimeZoneMins * 60 * 1000;
-		Calendar cal = new GregorianCalendar();
-		cal.setTime(new Date(ms - TimeZone.getDefault().getRawOffset()));
-		Date date = cal.getTime();
-		if (cal.getTimeZone().inDaylightTime(date)) {
-			date.setTime(date.getTime() - cal.getTimeZone().getDSTSavings());
-		}
+		Date date = new Date(ms);
+		storeReference(date);
 		return date;
 	}
@@ -218,137 +228,125 @@
 	 * @return int        Length of array
 	 */
-	@Override
-	public int readStartArray() {
-		System.err.println("MISSING: readStartArray");
-		return buf.getInt();
-	}
-
-	/**
-	 * Skips elements TODO
-	 */
-	@Override
-	public void skipElementSeparator() {
-		// SKIP
-	}
-
-	/**
-	 * Skips end array TODO
-	 */
-	@Override
-	public void skipEndArray() {
-		// SKIP
-	}
-
+    public Object readArray(Deserializer deserializer) {
+		int count = readAMF3Integer();
+		if ((count & 1) == 0) {
+			// Reference
+			return getReference(count >> 1);
+		}
+		
+		count = (count >> 1);
+		String key = readString();
+		amf3_mode += 1;
+		Object result = null;
+		if (key.equals("")) {
+			// normal array
+			List<Object> resultList = new ArrayList<Object>(count);
+			storeReference(resultList);
+			for (int i=0; i<count; i++) {
+				final Object value = deserializer.deserialize(this);
+				resultList.add(value);
+			}
+			result = resultList;
+		} else {
+			// associative array
+			Map<Object, Object> resultMap = new HashMap<Object, Object>();
+			storeReference(resultMap);
+			while (!key.equals("")) {
+				final Object value = deserializer.deserialize(this);
+				resultMap.put(key, value);
+				key = readString();
+			}
+			for (int i=0; i<count; i++) {
+				final Object value = deserializer.deserialize(this);
+				resultMap.put(i, value);
+			}
+			result = resultMap;
+		}
+		amf3_mode -= 1;
+		return result;			
+	}
+
+    public Object readMap(Deserializer deserializer) {
+    	throw new RuntimeException("AMF3 doesn't support maps.");
+    }
+    
 	// Object
 
-	/**
-	 * Reads start list
-	 * 
-	 * @return int        Size of map
-	 */
-	@Override
-	public int readStartMap() {
-		System.err.println("MISSING: readStartMap");
-		return buf.getInt();
-	}
-
-	/**
-	 * Returns a boolean stating whether this has more items
-	 * 
-	 * @return boolean    <code>true</code> if this Input's buffer has more items, <code>false</code> otherwise
-	 */
-	@Override
-	public boolean hasMoreItems() {
-		return hasMoreProperties();
-	}
-
-	/**
-	 * Reads the item index
-	 * 
-	 * @return int        Array item index
-	 */
-	@Override
-	public String readItemKey() {
-		return readString();
-	}
-
-	/**
-	 * Skips item seperator
-	 */
-	@Override
-	public void skipItemSeparator() {
-		// SKIP
-	}
-
-	/**
-	 * Skips end list
-	 */
-	@Override
-	public void skipEndMap() {
-		skipEndObject();
-	}
-
-	// Object
-
-	/**
-	 * Reads start object
-	 * 
-	 * @return String
-	 */
-	@Override
-	public String readStartObject() {
-		System.err.println("MISSING: readStartObject");
-		return null;
-	}
-
-	/**
-	 * Returns a boolean stating whether there are more properties
-	 * 
-	 * @return boolean       <code>true</code> if there are more properties to read, <code>false</code> otherwise
-	 */
-	@Override
-	public boolean hasMoreProperties() {
-		boolean isEnd = (buf.get() == 0);
-		buf.position(buf.position()-1);
-		return isEnd;
-	}
-
-	/**
-	 * Reads property name
-	 * 
-	 * @return String       Object property name
-	 */
-	@Override
-	public String readPropertyName() {
-		return readString();
-	}
-
-	/**
-	 * Skips property seperator
-	 */
-	@Override
-	public void skipPropertySeparator() {
-		// SKIP
-	}
-
-	/**
-	 * Skips end object
-	 */
-	@Override
-	public void skipEndObject() {
-		buf.skip(1);
-	}
-
+    public Object readObject(Deserializer deserializer) {
+		int type = readAMF3Integer();
+		if ((type & 1) == 0) {
+			// Reference
+			return getReference(type >> 1);
+		}
+		
+		type >>= 1;
+		boolean inlineClass = (type & 1) == 1;
+		if (!inlineClass) {
+			throw new RuntimeException("Class references not supported yet.");
+		}
+		
+		type >>= 1;
+		String className = readString();
+		Object result = null;
+		amf3_mode += 1;
+		// Load object properties into map
+		Map<String, Object> properties = new ObjectMap<String, Object>();
+		switch (type & 0x03) {
+		case AMF3.TYPE_OBJECT_PROPERTY:
+			int count = type >> 2;
+			List<String> propertyNames = new ArrayList<String>(count);
+			for (int i=0; i<count; i++) {
+				propertyNames.add(readString());					
+			}
+			for (int i=0; i<count; i++) {
+				properties.put(propertyNames.get(i), deserializer.deserialize(this));
+			}
+			break;
+		case AMF3.TYPE_OBJECT_ANONYMOUS_PROPERTY:
+			properties.put("", deserializer.deserialize(this));
+			break;
+		case AMF3.TYPE_OBJECT_VALUE:
+			String key = readString();
+			while (!"".equals(key)) {
+				Object value = deserializer.deserialize(this);
+				properties.put(key, value);
+				key = readString();
+			}
+			break;
+		default:
+		case AMF3.TYPE_OBJECT_UNKNOWN:
+			throw new RuntimeException("Unknown object type: " + (type & 0x03));
+		}
+		amf3_mode -= 1;
+		
+		// Create result object based on classname
+		if ("".equals(className)) {
+			// "anonymous" object, load as Map
+			storeReference(properties);
+			result = properties;
+		} else if ("RecordSet".equals(className)) {
+			// TODO: how are RecordSet objects encoded?
+			throw new RuntimeException("Objects of type " + className + " not supported yet.");
+		} else if ("RecordSetPage".equals(className)) {
+			// TODO: how are RecordSetPage objects encoded?
+			throw new RuntimeException("Objects of type " + className + " not supported yet.");
+		} else {
+			// Apply properties to object
+			result = newInstance(className);
+			if (result != null) {
+				storeReference(properties);
+				for (Map.Entry<String, Object> entry: properties.entrySet()) {
+					try {
+						BeanUtils.setProperty(result, entry.getKey(), entry.getValue());
+					} catch (Exception e) {
+						log.error("Error mapping property: " + entry.getKey() + " (" + entry.getValue() + ")");
+					}
+				}
+			} // else fall through
+		}
+		return result;
+    }
+    
 	// Others
-
-	/**
-	 * Reads xml
-	 * 
-	 * @return String     XML as String
-	 */
-	@Override
-	public String readXML() {
-		return readString();
-	}
 
 	/**
@@ -363,4 +361,9 @@
 	}
 
+	/** {@inheritDoc} */
+	public Object readReference() {
+		throw new RuntimeException("AMF3 doesn't support direct references.");
+	}
+
 	/**
 	 * Resets map
@@ -368,5 +371,6 @@
 	@Override
 	public void reset() {
-		this.clearReferences();
+		super.reset();
+		stringReferences.cle

Note:
Diffs are chopped if more than 25k.
This is to get past the limit on the mailing list.



More information about the Red5commits mailing list