http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DMessage.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flash/tools/debugger/concrete/DMessage.java 
b/debugger/src/main/java/flash/tools/debugger/concrete/DMessage.java
new file mode 100644
index 0000000..a0658a5
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DMessage.java
@@ -0,0 +1,1016 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 flash.tools.debugger.concrete;
+
+import java.lang.ArrayIndexOutOfBoundsException;
+import java.io.UnsupportedEncodingException;
+
+import flash.tools.debugger.Isolate;
+import flash.util.FieldFormat;
+import flash.util.Trace;
+
+/**
+ * DMessage.java
+ *
+ *    Wraps the contents of a specific message and provides a set of APIs that 
allow for
+ *    typed extraction of fields within the message.
+ *
+ *    No interpretation of the messages contents is performed, this is left to 
the
+ *    user of this class.  The code was constructed in this fashion, so that 
it more
+ *    closely mimics the DataReader/DataWriter classes used in the Player code.
+ *
+ *    The type of the message should be one of the InXXX or OutXXX constant 
integers,
+ *    but no checking of conformance is provided in this class.
+ */
+public class DMessage
+{
+       /**
+     * This set of constants defines the message types RECEIVED from the player
+        * through our debug socket
+        */
+       public static final int InUnknown                                       
= -1;
+       public static final int InSetMenuState                          =  0;
+       public static final int InSetProperty                           =  1;
+       public static final int InExit                                          
=  2;
+       public static final int InNewObject                                     
=  3;
+       public static final int InRemoveObject                          =  4;
+       public static final int InTrace                                         
=  5;
+       public static final int InErrorTarget                           =  6;
+       public static final int InErrorExecLimit                        =  7;
+       public static final int InErrorWith                                     
=  8;
+       public static final int InErrorProtoLimit                       =  9;
+       public static final int InSetVariable                           = 10;
+       public static final int InDeleteVariable                        = 11;
+       public static final int InParam                                         
= 12;
+       public static final int InPlaceObject                           = 13;
+       public static final int InScript                                        
= 14;
+       public static final int InAskBreakpoints                        = 15;
+       public static final int InBreakAt                                       
= 16;
+       public static final int InContinue                                      
= 17;
+       public static final int InSetLocalVariables                     = 18;
+       public static final int InSetBreakpoint                         = 19;
+       public static final int InNumScript                                     
= 20;
+       public static final int InRemoveScript                          = 21;
+       public static final int InRemoveBreakpoint                      = 22;
+       public static final int InNotSynced                                     
= 23;
+       public static final int InErrorURLOpen                          = 24;
+       public static final int InProcessTag                            = 25;
+       public static final int InVersion                                       
= 26;
+       public static final int InBreakAtExt                            = 27;
+       public static final int InSetVariable2                          = 28;
+       public static final int InSquelch                                       
= 29;
+       public static final int InGetVariable                           = 30;
+       public static final int InFrame                                         
= 31;
+       public static final int InOption                                        
= 32;
+    public static final int InWatch                                            
= 33;
+    public static final int InGetSwf                                   = 34;
+    public static final int InGetSwd                                   = 35;
+       public static final int InErrorException                        = 36;
+       public static final int InErrorStackUnderflow           = 37;
+       public static final int InErrorZeroDivide                       = 38;
+       public static final int InErrorScriptStuck                      = 39;
+       public static final int InBreakReason                           = 40;
+       public static final int InGetActions                            = 41;
+       public static final int InSwfInfo                                       
= 42;
+       public static final int InConstantPool                          = 43;
+       public static final int InErrorConsole                          = 44;
+    public static final int InGetFncNames                              = 45;
+       // 46 through 52 are for profiling
+    public static final int InCallFunction                             = 54;
+    public static final int InWatch2                                   = 55;
+    public static final int InPassAllExceptionsToDebugger = 56;
+    public static final int InBinaryOp                                 = 57;
+    public static final int InIsolateCreate                            = 58;
+    public static final int InIsolateExit                      = 59;
+    public static final int InIsolateEnumerate                 = 60;
+    public static final int InSetActiveIsolate                 = 61;
+    public static final int InIsolate                          = 62;
+    public static final int InSetExceptionBreakpoint   = 63;
+    public static final int InRemoveExceptionBreakpoint        = 64;
+    // If you add another message here, adjust the following line
+    // and add a new case to the inTypeName() method below.
+       public static final int InSIZE                                          
= InRemoveExceptionBreakpoint + 1;       /* last ID used +1 */
+
+       /**
+        * This set of constants defines the message types SENT to the player 
from our
+     * debug socket (WARNING: ID space overlaps with InXXX)
+        */
+       public static final int OutUnknown                                      
= -2;
+       public static final int OutZoomIn                                       
=  0;
+       public static final int OutZoomOut                                      
=  1;
+       public static final int OutZoom100                                      
=  2;
+       public static final int OutHome                                         
=  3;
+       public static final int OutSetQuality                           =  4;
+       public static final int OutPlay                                         
=  5;
+       public static final int OutLoop                                         
=  6;
+       public static final int OutRewind                                       
=  7;
+       public static final int OutForward                                      
=  8;
+       public static final int OutBack                                         
=  9;
+       public static final int OutPrint                                        
= 10;
+       public static final int OutSetVariable                          = 11;
+       public static final int OutSetProperty                          = 12;
+       public static final int OutExit                                         
= 13;
+       public static final int OutSetFocus                                     
= 14;
+       public static final int OutContinue                                     
= 15;
+       public static final int OutStopDebug                            = 16;
+       public static final int OutSetBreakpoints                       = 17;
+       public static final int OutRemoveBreakpoints            = 18;
+       public static final int OutRemoveAllBreakpoints         = 19;
+       public static final int OutStepOver                                     
= 20;
+       public static final int OutStepInto                                     
= 21;
+       public static final int OutStepOut                                      
= 22;
+       public static final int OutProcessedTag                         = 23;
+       public static final int OutSetSquelch                           = 24;
+       public static final int OutGetVariable                          = 25;
+       public static final int OutGetFrame                                     
= 26;
+       public static final int OutGetOption                            = 27;
+       public static final int OutSetOption                            = 28;
+       public static final int OutAddWatch                                     
= 29; // 16-bit id; used for as2
+       public static final int OutRemoveWatch                          = 30; 
// 16-bit id; used for as2
+    public static final int OutStepContinue                            = 31;
+    public static final int OutGetSwf                              = 32;
+    public static final int OutGetSwd                              = 33;
+       public static final int OutGetVariableWhichInvokesGetter = 34;
+       public static final int OutGetBreakReason                       = 35;
+       public static final int OutGetActions                           = 36;
+       public static final int OutSetActions                           = 37;
+       public static final int OutSwfInfo                                      
= 38;
+       public static final int OutConstantPool                         = 39;
+    public static final int OutGetFncNames              = 40;
+       // 41 through 47 are for profiling
+    public static final int OutCallFunction                            = 48;
+    public static final int OutAddWatch2                               = 49; 
// 32-bit id; used for as3
+    public static final int OutRemoveWatch2                            = 50; 
// 32-bit id; used for as3
+    public static final int OutPassAllExceptionsToDebugger = 51;
+    public static final int OutBinaryOp                                        
= 52;
+    public static final int OutIsolateEnumerate                        = 53;
+    public static final int OutSetActiveIsolate         = 54;
+    public static final int OutSetExceptionBreakpoint   = 55;
+    public static final int OutRemoveExceptionBreakpoint= 56;
+    // If you add another message here, adjust the following line
+    // and add a new case to the outTypeName() method below.
+       public static final int OutSIZE                                         
= OutRemoveExceptionBreakpoint + 1;      /* last ID used +1 */
+
+       /**
+        * Enums originally extracted from shared_tcserver/tcparser.h; these 
correspond
+        * to Flash player values that are currently in playerdebugger.h, class 
DebugAtomType.
+        */
+       public static final int kNumberType                     = 0;
+       public static final int kBooleanType            = 1;
+       public static final int kStringType                     = 2;
+       public static final int kObjectType                     = 3;
+       public static final int kMovieClipType          = 4;
+       public static final int kNullType                       = 5;
+       public static final int kUndefinedType          = 6;
+       public static final int kReferenceType          = 7;
+       public static final int kArrayType                      = 8;
+       public static final int kObjectEndType          = 9;
+       public static final int kStrictArrayType        = 10;
+       public static final int kDateType                       = 11;
+       public static final int kLongStringType         = 12;
+       public static final int kUnsupportedType        = 13;
+       public static final int kRecordSetType          = 14;
+       public static final int kXMLType                        = 15;
+       public static final int kTypedObjectType        = 16;
+       public static final int kAvmPlusObjectType      = 17;
+       public static final int kNamespaceType          = 18;
+       public static final int kTraitsType                     = 19;   // This 
one is special: When passed to the debugger, it indicates
+                                                                               
                                // that the "variable" is not a variable at 
all, but rather is a
+                                                                               
                                // class name.  For example, if class Y extends 
class X, then
+                                                                               
                                // we will send a kDTypeTraits for class Y; 
then we'll send all the
+                                                                               
                                // members of class Y; then we'll send a 
kDTypeTraits for class X;
+                                                                               
                                // and then we'll send all the members of class 
X.  This is only
+                                                                               
                                // used by the AVM+ debugger.
+
+       /* byte array of our message and current index into it */
+       byte[] m_content;       /* the data bytes of the message */
+       int        m_index;             /* current position within the content 
array */
+       int    m_type;          /* one of OutXXX or InXXX integer constants */
+
+       /**
+        * Pointer size (in bytes) expected by the Flash player; either
+        * 4 for the 32-bit player, or 8 for the 64-bit player.
+        */
+       private static int m_sizeofPtr;
+
+       /* Debugging only: The contents of this message, formatted as a string 
for display */
+       private StringBuilder m_debugFormatted;
+       /* Debugging only: The number of bytes from the input that we have 
formatted into m_debugFormatted */
+       private int m_debugFormattedThroughIndex;
+
+       private int m_targetIsolate;
+       
+       /* used by our cache to create empty DMessages */
+       public DMessage(int size)
+       {
+               m_content = new byte[size];
+               m_debugFormatted = new StringBuilder();
+               m_debugFormattedThroughIndex = 0;
+               m_targetIsolate = Isolate.DEFAULT_ID;
+               clear();
+       }
+
+       /* getters/setters */
+       public int    getType()                         { return m_type; }
+       public String getInTypeName()           { return inTypeName(getType()); 
}
+       public String getOutTypeName()          { return 
outTypeName(getType()); }
+       public byte[] getData()                         { return m_content; }
+       public int    getSize()                         { return (m_content == 
null) ? 0 : m_content.length; }
+       public int    getRemaining()            { return getSize()-m_index; }
+       public int    getPosition()                     { return m_index; }
+       public int getTargetIsolate()      { return m_targetIsolate; }
+       public void   setType(int t)            { m_type = t; }
+       public void setTargetIsolate(int id) {m_targetIsolate = id;}
+
+       /**
+        * Gets pointer size (in bytes) expected by the Flash player; either
+        * 4 for the 32-bit player, or 8 for the 64-bit player.
+        */
+       public static int getSizeofPtr()
+       {
+               assert m_sizeofPtr != 0;
+               return m_sizeofPtr;
+       }
+
+       /**
+        * Sets pointer size (in bytes) expected by the Flash player; either
+        * 4 for the 32-bit player, or 8 for the 64-bit player.
+        */
+       public static void setSizeofPtr(int size)
+       {
+               assert size != 0;
+               m_sizeofPtr = size;
+       }
+
+       /**
+        * Allow the message to be 're-parsed' by someone else
+        */
+       public void reset()
+       {
+               m_index = 0;
+       }
+
+       /**
+        * Allow the message to be reused later
+        */
+       public void clear()
+       {
+               setType(-1);
+               setTargetIsolate(Isolate.DEFAULT_ID);
+               m_debugFormatted.setLength(0);
+               m_debugFormattedThroughIndex = 0;
+               reset();
+       }
+
+       private long get(int bytes) throws ArrayIndexOutOfBoundsException
+       {
+               if (m_index+bytes > m_content.length)
+                       throw new 
ArrayIndexOutOfBoundsException(m_content.length-m_index+" < "+bytes); 
//$NON-NLS-1$
+
+               long value = 0;
+               for (int i=0; i<bytes; ++i) {
+                       long byteValue = m_content[m_index++] & 0xff;
+                       long byteValueShifted = byteValue << (8*i);
+                       value |= byteValueShifted;
+               }
+
+               debugAppendNumber(value, bytes);
+               return value;
+       }
+
+       /**
+        * Extract the next byte
+        */
+       public int getByte() throws ArrayIndexOutOfBoundsException
+       {
+               return (int) get(1);
+       }
+
+       /**
+        * Extract the next 2 bytes, which form a 16b integer, from the message
+        */
+       public int getWord() throws ArrayIndexOutOfBoundsException
+       {
+               return (int) get(2);
+       }
+
+       /**
+        * Extract the next 4 bytes, which form a 32b integer, from the message
+        */
+       public long getDWord() throws ArrayIndexOutOfBoundsException
+       {
+               return get(4);
+       }
+
+       /**
+        * Extract the next 8 bytes, which form a 64b integer, from the message
+        */
+       public long getLong() throws ArrayIndexOutOfBoundsException
+       {
+               return get(8);
+       }
+
+       /**
+        * Extract a pointer from the message -- either 8 bytes or 4 bytes,
+        * depending on how big pointers are in the target Flash player
+        */
+       public long getPtr() throws ArrayIndexOutOfBoundsException
+       {
+               return get(getSizeofPtr());
+       }
+
+       /**
+        * Heart wrenchingly slow but since we don't have a length so we can't
+        * do much better
+        */
+       public String getString() throws ArrayIndexOutOfBoundsException
+       {
+               int startAt = m_index;
+               boolean done = false;
+
+               /* scan looking for a terminating null */
+               while(!done)
+               {
+                   int ch = m_content[m_index++];
+                       if (ch == 0)
+                               done = true;
+                       else if (m_index > m_content.length)
+                               throw new ArrayIndexOutOfBoundsException("no 
string terminator found @"+m_index); //$NON-NLS-1$
+               }
+
+               /* build a new string and return it */
+               String s;
+               try
+               {
+                       // The player uses UTF-8
+                       s = new String(m_content, startAt, m_index-startAt-1, 
"UTF-8"); //$NON-NLS-1$
+               }
+               catch(UnsupportedEncodingException uee)
+               {
+                       // couldn't convert so let's try the default
+                       s = new String(m_content, startAt, m_index-startAt-1);
+               }
+               debugAppendString(s);
+               return s;
+       }
+
+       /**
+        * Appends a number to the end of the message
+        * @param val the number
+        * @param bytes how many bytes should be written
+        */
+       public void put(long val, int bytes) throws 
ArrayIndexOutOfBoundsException
+       {
+               if (m_index+bytes > m_content.length)
+                       throw new 
ArrayIndexOutOfBoundsException(m_content.length-m_index+" < "+bytes); 
//$NON-NLS-1$
+
+               for (int i=0; i<bytes; ++i)
+                       m_content[m_index++] = (byte)(val >> 8*i);
+
+               debugAppendNumber(val, bytes);
+       }
+
+       /**
+        * Appends a byte to the end of the message
+        */
+       public void putByte(byte val) throws ArrayIndexOutOfBoundsException
+       {
+               put(val, 1);
+       }
+
+       /**
+        * Appends 2 bytes, which form a 16b integer, into the message
+        */
+       public void putWord(int val) throws ArrayIndexOutOfBoundsException
+       {
+               put(val, 2);
+       }
+
+       /**
+        * Appends 4 bytes, which form a 32b integer, into the message
+        */
+       public void putDWord(int val) throws ArrayIndexOutOfBoundsException
+       {
+               put(val, 4);
+       }
+
+       /**
+        * Appends 8 bytes, which form a 64b integer, into the message
+        */
+       public void putLong(long val) throws ArrayIndexOutOfBoundsException
+       {
+               put(val, 8);
+       }
+
+       /**
+        * Appends a pointer into the message -- either 8 bytes or 4 bytes,
+        * depending on how big pointers are in the target Flash player
+        */
+       public void putPtr(long val) throws ArrayIndexOutOfBoundsException
+       {
+               put(val, getSizeofPtr());
+       }
+
+       /**
+        * Helper to get the number of bytes that a string will need when it is 
sent
+        * across the socket to the Flash player.  Do *not* use string.length(),
+        * because that will return an incorrect result for strings that have 
non-
+        * ASCII characters.
+        */
+       public static int getStringLength(String s)
+       {
+               try
+               {
+                       return s.getBytes("UTF-8").length; //$NON-NLS-1$
+               }
+               catch (UnsupportedEncodingException e)
+               {
+                       if (Trace.error) Trace.trace(e.toString());
+                       return 0;
+               }
+       }
+
+       /**
+        * Place a string into the message (using UTF-8 encoding)
+        */
+       public void putString(String s) throws ArrayIndexOutOfBoundsException, 
UnsupportedEncodingException
+       {
+               /* convert the string into a byte array */
+               byte[] bytes = s.getBytes("UTF-8"); //$NON-NLS-1$
+               int length = bytes.length;
+               int endAt = m_index + length + 1;
+
+               if (endAt > m_content.length)
+                       throw new ArrayIndexOutOfBoundsException(endAt+" > 
"+m_content.length); //$NON-NLS-1$
+
+               /* copy the string as a byte array */
+               System.arraycopy(bytes, 0, m_content, m_index, length);
+               m_index += length;
+
+               /* now the null terminator */
+               m_content[m_index++] = '\0';
+               
+               debugAppendString(s);
+       }
+
+       // Debugging helper function: we've parsed a number out of the stream 
of input bytes,
+       // so record that as a hex number of the appropriate length, e.g. 
"0x12" or "0x1234"
+       // or "0x12345678", depending on numBytes.
+       private void debugAppendNumber(long value, int numBytes)
+       {
+               if (PlayerSession.m_debugMsgOn || 
PlayerSession.m_debugMsgFileOn)
+               {
+                       StringBuilder sb = new StringBuilder();
+                       sb.append("0x"); //$NON-NLS-1$
+                       FieldFormat.formatLongToHex(sb, value, numBytes * 2, 
true);
+                       debugAppend(sb.toString());
+               }
+       }
+
+       // Debugging helper function: we've parsed a string out of the stream 
of input bytes,
+       // so record it as a quoted string in the formatted debugging output.
+       private void debugAppendString(String s)
+       {
+               if (PlayerSession.m_debugMsgOn || 
PlayerSession.m_debugMsgFileOn)
+                       debugAppend('"' + s + '"');
+       }
+
+       // Debugging helper function: append a string to the formatted 
debugging output.
+       private void debugAppend(String s)
+       {
+               if (PlayerSession.m_debugMsgOn || 
PlayerSession.m_debugMsgFileOn)
+               {
+                       if (m_index > m_debugFormattedThroughIndex)
+                       {
+                               m_debugFormattedThroughIndex = m_index;
+                               if (m_debugFormatted.length() > 0)
+                                       m_debugFormatted.append(' ');
+                               m_debugFormatted.append(s);
+                       }
+               }
+       }
+
+       public String inToString() { return inToString(16); }
+
+       public String inToString(int maxContentBytes)
+       {
+               StringBuilder sb = new StringBuilder();
+               sb.append(getInTypeName());
+               sb.append('[');
+               sb.append(getSize());
+               sb.append("] "); //$NON-NLS-1$
+               if (getSize() > 0)
+                       appendContent(sb, maxContentBytes);
+
+               return sb.toString();
+       }
+
+       public String outToString() { return outToString(16); }
+
+       public String outToString(int maxContentBytes)
+       {
+               StringBuilder sb = new StringBuilder();
+               sb.append(getOutTypeName());
+               sb.append('[');
+               sb.append(getSize());
+               sb.append("] "); //$NON-NLS-1$
+               if (getSize() > 0)
+                       appendContent(sb, maxContentBytes);
+
+               return sb.toString();
+       }
+
+       public StringBuilder appendContent(StringBuilder sb, int max)
+       {
+               int size = getSize();
+               byte[] data = getData();
+               int i = 0;
+
+               // First, output formatted content -- content for which some of 
the other functions
+               // in this class, such as getDWord and getString, did 
formatting.
+               sb.append(m_debugFormatted);
+
+               // Now, for any left-over bytes which no one bothered to parse, 
output them as hex. 
+               for(i=0; i<max && i+m_debugFormattedThroughIndex<size; i++)
+               {
+                       int v = data[i+m_debugFormattedThroughIndex] & 0xff;
+                       sb.append(" 0x"); //$NON-NLS-1$
+                       FieldFormat.formatLongToHex(sb, v, 2, true);
+               }
+
+               if (i+m_debugFormattedThroughIndex < size)
+                       sb.append(" ..."); //$NON-NLS-1$
+
+               return sb;
+       }
+
+       /**
+        * Convenience function for converting a type into a name used mainly 
for debugging
+        * but can also be used during trace facility of command line session
+        */
+       public static String inTypeName(int type)
+       {
+        String s = "InUnknown(" + type + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+
+               switch(type)
+               {
+                       case InSetMenuState:
+                               s = "InSetMenuState"; //$NON-NLS-1$
+                               break;
+
+                       case InSetProperty:
+                               s = "InSetProperty"; //$NON-NLS-1$
+                               break;
+
+                       case InExit:
+                               s = "InExit"; //$NON-NLS-1$
+                               break;
+
+                       case InNewObject:
+                               s = "InNewObject"; //$NON-NLS-1$
+                               break;
+
+                       case InRemoveObject:
+                               s = "InRemoveObject"; //$NON-NLS-1$
+                               break;
+
+                   case InTrace:
+                               s = "InTrace"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorTarget:
+                               s = "InErrorTarget"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorExecLimit:
+                               s = "InErrorExecLimit"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorWith:
+                               s = "InErrorWith"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorProtoLimit:
+                               s = "InErrorProtoLimit"; //$NON-NLS-1$
+                               break;
+
+                       case InSetVariable:
+                               s = "InSetVariable"; //$NON-NLS-1$
+                               break;
+
+                       case InDeleteVariable:
+                               s = "InDeleteVariable"; //$NON-NLS-1$
+                               break;
+
+                       case InParam:
+                               s = "InParam"; //$NON-NLS-1$
+                               break;
+
+                       case InPlaceObject:
+                               s = "InPlaceObject"; //$NON-NLS-1$
+                               break;
+
+                       case InScript:
+                               s = "InScript"; //$NON-NLS-1$
+                               break;
+
+                       case InAskBreakpoints:
+                               s = "InAskBreakpoints"; //$NON-NLS-1$
+                               break;
+
+                       case InBreakAt:
+                               s = "InBreakAt"; //$NON-NLS-1$
+                               break;
+
+                       case InContinue:
+                               s = "InContinue"; //$NON-NLS-1$
+                               break;
+
+                       case InSetLocalVariables:
+                               s = "InSetLocalVariables"; //$NON-NLS-1$
+                               break;
+
+                       case InSetBreakpoint:
+                               s = "InSetBreakpoint"; //$NON-NLS-1$
+                               break;
+
+                       case InNumScript:
+                               s = "InNumScript"; //$NON-NLS-1$
+                               break;
+
+                       case InRemoveScript:
+                               s = "InRemoveScript"; //$NON-NLS-1$
+                               break;
+
+                       case InRemoveBreakpoint:
+                               s = "InRemoveBreakpoint"; //$NON-NLS-1$
+                               break;
+
+                       case InNotSynced:
+                               s = "InNotSynced"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorURLOpen:
+                               s = "InErrorURLOpen"; //$NON-NLS-1$
+                               break;
+
+                       case InProcessTag:
+                               s = "InProcessTag"; //$NON-NLS-1$
+                               break;
+
+                       case InVersion:
+                               s = "InVersion"; //$NON-NLS-1$
+                               break;
+
+                       case InBreakAtExt:
+                               s = "InBreakAtExt"; //$NON-NLS-1$
+                               break;
+
+                       case InSetVariable2:
+                               s = "InSetVariable2"; //$NON-NLS-1$
+                               break;
+
+                       case InSquelch:
+                               s = "InSquelch"; //$NON-NLS-1$
+                               break;
+
+                       case InGetVariable:
+                               s = "InGetVariable"; //$NON-NLS-1$
+                               break;
+
+                       case InFrame:
+                               s = "InFrame"; //$NON-NLS-1$
+                               break;
+
+                       case InOption:
+                               s = "InOption"; //$NON-NLS-1$
+                               break;
+
+                       case InWatch:
+                               s = "InWatch"; //$NON-NLS-1$
+                               break;
+
+                       case InGetSwf:
+                               s = "InGetSwf"; //$NON-NLS-1$
+                               break;
+
+                       case InGetSwd:
+                               s = "InGetSwd"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorException:
+                               s = "InErrorException"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorStackUnderflow:
+                               s = "InErrorStackUnderflow"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorZeroDivide:
+                               s = "InErrorZeroDivide"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorScriptStuck:
+                               s = "InErrorScriptStuck"; //$NON-NLS-1$
+                               break;
+
+                       case InBreakReason:
+                               s = "InBreakReason"; //$NON-NLS-1$
+                               break;
+
+                       case InGetActions:
+                               s = "InGetActions"; //$NON-NLS-1$
+                               break;
+
+                       case InSwfInfo:
+                               s = "InSwfInfo"; //$NON-NLS-1$
+                               break;
+
+                       case InConstantPool:
+                               s = "InConstantPool"; //$NON-NLS-1$
+                               break;
+
+                       case InErrorConsole:
+                               s = "InErrorConsole"; //$NON-NLS-1$
+                               break;
+
+            case InGetFncNames:
+                s = "InGetFncNames"; //$NON-NLS-1$
+                break;
+                
+            case InCallFunction:
+               s = "InCallFunction"; //$NON-NLS-1$
+               break;
+               
+            case InWatch2:
+               s = "InWatch2"; //$NON-NLS-1$
+               break;
+
+            case InPassAllExceptionsToDebugger:
+               s = "InPassAllExceptionsToDebugger"; //$NON-NLS-1$
+               break;
+
+            case InBinaryOp:
+               s = "InBinaryOp"; //$NON-NLS-1$
+               break;
+               
+            case InIsolateCreate:
+               s = "InIsolateCreate"; //$NON-NLS-1$
+               break;
+               
+            case InIsolateExit:
+               s = "InIsolateExit"; //$NON-NLS-1$
+               break;
+               
+            case InIsolateEnumerate:
+               s = "InIsolateEnumerate"; //$NON-NLS-1$
+               break;
+               
+            case InSetActiveIsolate:
+               s = "InSetActiveIsolate"; //$NON-NLS-1$
+               break;
+               
+            case InIsolate:
+               s = "InIsolate"; //$NON-NLS-1$
+               break;
+               
+            case InSetExceptionBreakpoint:
+               s = "InSetExceptionBreakpoint"; //$NON-NLS-1$
+               break;
+               
+            case InRemoveExceptionBreakpoint:
+               s = "InRemoveExceptionBreakpoint"; //$NON-NLS-1$
+               break;
+               }
+               return s;
+       }
+
+       /**
+        * Convenience function for converting a type into a name used mainly 
for debugging
+        * but can also be used during trace facility of command line session
+        */
+       public static String outTypeName(int type)
+       {
+               String s = "OutUnknown(" + type + ")"; //$NON-NLS-1$ 
//$NON-NLS-2$
+
+               switch(type)
+               {
+                       case OutZoomIn:
+                               s = "OutZoomIn"; //$NON-NLS-1$
+                               break;
+
+                       case OutZoomOut:
+                               s = "OutZoomOut"; //$NON-NLS-1$
+                               break;
+
+                       case OutZoom100:
+                               s = "OutZoom100"; //$NON-NLS-1$
+                               break;
+
+                       case OutHome:
+                               s = "OutHome"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetQuality:
+                               s = "OutSetQuality"; //$NON-NLS-1$
+                               break;
+
+                       case OutPlay:
+                               s = "OutPlay"; //$NON-NLS-1$
+                               break;
+
+                       case OutLoop:
+                               s = "OutLoop"; //$NON-NLS-1$
+                               break;
+
+                       case OutRewind:
+                               s = "OutRewind"; //$NON-NLS-1$
+                               break;
+
+                       case OutForward:
+                               s = "OutForward"; //$NON-NLS-1$
+                               break;
+
+                       case OutBack:
+                               s = "OutBack"; //$NON-NLS-1$
+                               break;
+
+                       case OutPrint:
+                               s = "OutPrint"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetVariable:
+                               s = "OutSetVariable"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetProperty:
+                               s = "OutSetProperty"; //$NON-NLS-1$
+                               break;
+
+                       case OutExit:
+                               s = "OutExit"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetFocus:
+                               s = "OutSetFocus"; //$NON-NLS-1$
+                               break;
+
+                       case OutContinue:
+                               s = "OutContinue"; //$NON-NLS-1$
+                               break;
+
+                       case OutStopDebug:
+                               s = "OutStopDebug"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetBreakpoints:
+                               s = "OutSetBreakpoints"; //$NON-NLS-1$
+                               break;
+
+                       case OutRemoveBreakpoints:
+                               s = "OutRemoveBreakpoints"; //$NON-NLS-1$
+                               break;
+
+                       case OutRemoveAllBreakpoints:
+                               s = "OutRemoveAllBreakpoints"; //$NON-NLS-1$
+                               break;
+
+                       case OutStepOver:
+                               s = "OutStepOver"; //$NON-NLS-1$
+                               break;
+
+                       case OutStepInto:
+                               s = "OutStepInto"; //$NON-NLS-1$
+                               break;
+
+                       case OutStepOut:
+                               s = "OutStepOut"; //$NON-NLS-1$
+                               break;
+
+                       case OutProcessedTag:
+                               s = "OutProcessedTag"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetSquelch:
+                               s = "OutSetSquelch"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetVariable:
+                               s = "OutGetVariable"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetFrame:
+                               s = "OutGetFrame"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetOption:
+                               s = "OutGetOption"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetOption:
+                               s = "OutSetOption"; //$NON-NLS-1$
+                               break;
+
+                       case OutAddWatch:
+                               s = "OutAddWatch"; //$NON-NLS-1$
+                               break;
+
+                       case OutRemoveWatch:
+                               s = "OutRemoveWatch"; //$NON-NLS-1$
+                               break;
+
+                       case OutStepContinue:
+                               s = "OutStepContinue"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetSwf:
+                               s = "OutGetSwf"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetSwd:
+                               s = "OutGetSwd"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetVariableWhichInvokesGetter:
+                               s = "OutGetVariableWhichInvokesGetter"; 
//$NON-NLS-1$
+                               break;
+
+                       case OutGetBreakReason:
+                               s = "OutGetBreakReason"; //$NON-NLS-1$
+                               break;
+
+                       case OutGetActions:
+                               s = "OutGetActions"; //$NON-NLS-1$
+                               break;
+
+                       case OutSetActions:
+                               s = "OutSetActions"; //$NON-NLS-1$
+                               break;
+
+                       case OutSwfInfo:
+                               s = "OutSwfInfo"; //$NON-NLS-1$
+                               break;
+
+                       case OutConstantPool:
+                               s = "OutConstantPool"; //$NON-NLS-1$
+                               break;
+
+            case OutGetFncNames:
+                s = "OutGetFncNames"; //$NON-NLS-1$
+                break;
+
+            case OutCallFunction:
+               s = "OutCallFunction"; //$NON-NLS-1$
+               break;
+               
+            case OutAddWatch2:
+               s = "OutAddWatch2"; //$NON-NLS-1$
+               break;
+               
+            case OutRemoveWatch2:
+               s = "OutRemoveWatch2"; //$NON-NLS-1$
+               break;
+
+            case OutPassAllExceptionsToDebugger:
+               s = "OutPassAllExceptionsToDebugger"; //$NON-NLS-1$
+               break;
+
+            case OutBinaryOp:
+               s = "OutBinaryOp"; //$NON-NLS-1$
+               break;
+               
+            case OutIsolateEnumerate:
+               s = "OutIsolateEnumerate"; //$NON-NLS-1$
+               break;
+               
+            case OutSetActiveIsolate:
+               s = "OutSetActiveIsolate"; //$NON-NLS-1$
+               break;
+               
+            case OutSetExceptionBreakpoint:
+               s = "OutSetExceptionBreakpoint"; //$NON-NLS-1$
+               break;
+               
+            case OutRemoveExceptionBreakpoint:
+               s = "OutRemoveExceptionBreakpoint"; //$NON-NLS-1$
+               break;
+               
+               }
+               return s;
+       }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCache.java
----------------------------------------------------------------------
diff --git 
a/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCache.java 
b/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCache.java
new file mode 100644
index 0000000..319235b
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCache.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 flash.tools.debugger.concrete;
+
+/**
+ * This cache directly manages the creation/destruction of DMessages
+ * by allowing DMessages to be re-used.
+ * 
+ * It has been observed that the Player send a tremendous number of
+ * small (< 8Byte of data) messages and that by allocating a fixed
+ * number of these, and then re-using them, we can assist the garbage
+ * collector greatly.
+ * 
+ * The cache is arranged as an array whereby DMessages with 'index'
+ * number of bytes for data are housed.  It is asssumed that at
+ * any moment in time only one DMessage will be required and thus
+ * this technique works.  If DMessages are to be stored for 
+ * later processing (implying that many will exist at any moment)
+ * then we need to implement a more sophisticated cache (probably
+ * storing a Vector of DMessages at each index).
+ *
+ * Very large DMessages are currently not cached.
+ * 
+ * This is class is a singleton.
+ */
+public class DMessageCache
+{
+       public static final int MAX_CACHED_DATA_SIZE            = 128;  /* 
should consume around 4n + n(n+1)/2 bytes */
+
+       /* our cache */
+       static DMessage[] m_cache = new DMessage[MAX_CACHED_DATA_SIZE];
+
+       /**
+        * Obtain a DMessage from the cache if possible, otherwise make one for 
me.
+        */
+       public static DMessage alloc(int size)
+       {
+               DMessage msg;
+
+               int index = size2Index(size);
+
+               /**
+                * We see if this could possibly be found in our cache,
+                * if so, then see if there is one for us to use,
+                * otherwise create a new one 
+                */
+               if (index < 0)
+                       msg = new DMessage(size);
+               else if (m_cache[index] == null)
+                       msg = new DMessage(size);
+        else
+               {
+                       msg = m_cache[index];
+                       m_cache[index] = null;
+               }
+
+//             System.out.println("msgsize="+size+uft());
+               return msg;
+       }
+
+       private static String uft()
+       {
+               Runtime rt = Runtime.getRuntime();
+               long free = rt.freeMemory(), total = rt.totalMemory(), used =  
total - free;
+//             long max = rt.maxMemory();
+               java.text.NumberFormat nf = 
java.text.NumberFormat.getInstance() ;
+//        System.out.println("used: "+nf.format(used)+" free: 
"+nf.format(free)+" total: "+nf.format(total)+" max: "+nf.format(max));
+        return ", used "+nf.format(used)+", free "+nf.format(free)+", total 
"+nf.format(total); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+    }
+
+       /**
+        * Put a DMessage into the cache for reuse
+        */
+       public static void free(DMessage msg)
+       {
+               int index = size2Index(msg.getSize());
+
+               msg.clear(); /* clear stuff up for re-use */
+
+               /** 
+                * If it is too big we don't store cache, assuming
+                * the GC can do a better job than us at reusing the memory,
+                * Otherwise we put it in our cache
+                */
+               if (index < 0)
+                       ;
+               else if (m_cache[index] != null)
+                       ; /* bad => need to use a Vector in the array to house 
multiple DMessages */
+               else
+                       m_cache[index] = msg;
+       }
+
+       public static int size2Index(int size) { return ((size < 
MAX_CACHED_DATA_SIZE) ? size : -1); }
+//     public static int size2Index(int size) { return -1; }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCounter.java
----------------------------------------------------------------------
diff --git 
a/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCounter.java 
b/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCounter.java
new file mode 100644
index 0000000..e13d601
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DMessageCounter.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 flash.tools.debugger.concrete;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import flash.tools.debugger.Isolate;
+
+/**
+ * This class can be to count the number of messages
+ * received during a debug session.
+ *
+ */
+public class DMessageCounter implements DProtocolNotifierIF
+{
+       long[] m_inCounts;
+       long[] m_outCounts;
+       long m_lastIsolate;
+       Object m_isolateLock;
+       boolean m_isolate;
+       
+       Map<Long, DMessageCounter> m_isolateCounterMap;
+
+       public DMessageCounter()
+       {
+               m_inCounts = new long[DMessage.InSIZE+1];
+               m_outCounts = new long[DMessage.OutSIZE+1];
+               m_lastIsolate = 1;
+               m_isolateCounterMap = new HashMap<Long, DMessageCounter>();
+               m_isolateLock = new Object();
+               clearArray(m_inCounts);
+               clearArray(m_outCounts);
+       }
+
+       public void disconnected()
+       {
+               // We're being notified (via the DProtocolNotifierIF interface) 
that
+               // the socket connection has been broken.  If anyone is waiting 
for
+               // a message to come in, they ain't gonna get one.  So, we'll 
notify()
+               // them so that they can wake up and realize that the 
connection has
+               // been broken.
+               Object inLock = getInLock();
+               synchronized (inLock) { inLock.notifyAll(); }
+               Object outLock = getOutLock();
+               synchronized (outLock) { outLock.notifyAll(); }
+       }
+
+       /**
+        * Returns the object on which external code can call "wait" in order
+        * to block until a message is received.
+        */
+       public Object getInLock() { return m_inCounts; }
+
+       /**
+        * Returns the object on which external code can call "wait" in order
+        * to block until a message is sent.
+        */
+       public Object getOutLock() { return m_outCounts; }
+       
+       /**
+        * Collect stats on outgoing messages 
+        */
+       public void messageSent(DMessage msg)
+       {
+           int type = msg.getType();
+               if (type < 0 || type >=DMessage.OutSIZE)
+                       type = DMessage.OutSIZE;
+               long targetIsolate = msg.getTargetIsolate();
+               Object outLock = getOutLock();
+               if (!m_isolate) {
+                       synchronized (m_isolateLock) {
+                               if (m_lastIsolate != Isolate.DEFAULT_ID) {
+                                       DMessageCounter counter = 
m_isolateCounterMap.get(m_lastIsolate);
+                                       outLock = counter.getOutLock();
+                               }
+                       }
+               }
+               synchronized (outLock) {
+                       
+                       if (!m_isolate && targetIsolate != Isolate.DEFAULT_ID) {
+//                             if 
(m_isolateCounterMap.containsKey(targetIsolate)) {
+                                       DMessageCounter counter = 
m_isolateCounterMap.get(targetIsolate);                               
+                                       counter.messageSent(msg);
+                                       m_outCounts[type] += 1;
+                                       outLock.notifyAll(); // tell anyone who 
is waiting that a message has been sent
+                                       //counter.getOutLock().notifyAll();
+//                             }
+//                             else {
+//                                     System.out.println("No counter for 
worker " + targetIsolate);
+//                                     m_outCounts[type] += 1;
+//                                     outLock.notifyAll(); // tell anyone who 
is waiting that a message has been sent
+//                             }
+                       }
+                       else {
+                               m_outCounts[type] += 1;
+                               outLock.notifyAll(); // tell anyone who is 
waiting that a message has been sent
+                       }
+               }
+       }
+       
+       public void setIsolate(boolean value) {
+               m_isolate = value;
+       }
+
+       /** 
+        * Collect stats on the messages 
+        */
+       public void messageArrived(DMessage msg, DProtocol which)
+       {
+               /* extract type */
+               int type = msg.getType();
+
+//             System.out.println("msg counter ="+type);
+
+               /* anything we don't know about goes in a special slot at the 
end of the array. */
+               if (type < 0 || type >= DMessage.InSIZE)
+                       type = DMessage.InSIZE;
+               Object inLock = getInLock();
+               if (!m_isolate) {
+                       synchronized (m_isolateLock) {
+                               if (m_lastIsolate != Isolate.DEFAULT_ID) {
+                                       DMessageCounter counter = 
m_isolateCounterMap.get(m_lastIsolate);
+                                       inLock = counter.getInLock();
+                               }
+                       }
+               }
+               
+               synchronized (inLock) {
+                       if (type == DMessage.InIsolate) {
+                               long isolate = msg.getDWord();                  
        
+                               if (isolate != Isolate.DEFAULT_ID) {
+                                       /** Check if our map has a counter for 
this isolate */
+                                       if 
(!m_isolateCounterMap.containsKey(isolate)) {
+                                               DMessageCounter isolateCounter 
= new DMessageCounter();
+                                               isolateCounter.setIsolate(true);
+                                               
m_isolateCounterMap.put(isolate, isolateCounter);
+                                       }
+                               }
+                               synchronized (m_isolateLock) {
+                                       m_lastIsolate = isolate;
+                               }
+                               m_inCounts[type] += 1;
+                               inLock.notifyAll(); // tell anyone who is 
waiting that a message has been received
+                       }
+                       else if (!m_isolate && m_lastIsolate != 
Isolate.DEFAULT_ID) {
+                               DMessageCounter counter = 
m_isolateCounterMap.get(m_lastIsolate);
+                               counter.messageArrived(msg, which);
+                               synchronized (counter.getInLock()) {
+                                       counter.getInLock().notifyAll();
+                               }
+                               
+                       }
+                       else {
+                               m_inCounts[type] += 1;
+                               inLock.notifyAll(); // tell anyone who is 
waiting that a message has been received
+                       }
+               }
+       }
+
+       /* getters */
+       public long   getInCount(int type)  { synchronized (getInLock()) { 
return m_inCounts[type]; } }
+       public long   getOutCount(int type) { synchronized (getOutLock()) { 
return m_outCounts[type]; } }
+       
+       public long   getIsolateInCount(long isolate, int type)  { 
+               DMessageCounter counter = m_isolateCounterMap.get(isolate);
+               return counter.getInCount(type); 
+       }
+
+       public long getIsolateOutCount(long isolate, int type) { 
+               DMessageCounter counter = m_isolateCounterMap.get(isolate);
+               return counter.getOutCount(type); 
+       }
+
+       public Object getIsolateInLock(long isolate)  { 
+               DMessageCounter counter = m_isolateCounterMap.get(isolate);
+               return counter.getInLock(); 
+       }
+
+
+       /* setters */
+       public void clearInCounts()                     { synchronized 
(getInLock()) { clearArray(m_inCounts); } }
+       public void clearOutCounts()            { synchronized (getOutLock()) { 
clearArray(m_outCounts); } }
+
+       /**
+        * Clear out the array 
+        */
+       void clearArray(long[] ar)
+       {
+               for(int i=0; i<ar.length; i++)
+                       ar[i] = 0;
+       }
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DModule.java
----------------------------------------------------------------------
diff --git a/debugger/src/main/java/flash/tools/debugger/concrete/DModule.java 
b/debugger/src/main/java/flash/tools/debugger/concrete/DModule.java
new file mode 100644
index 0000000..d2577cb
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DModule.java
@@ -0,0 +1,832 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 flash.tools.debugger.concrete;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import flash.tools.debugger.NoResponseException;
+import flash.tools.debugger.Session;
+import flash.tools.debugger.SourceFile;
+import flash.tools.debugger.SourceLocator;
+import flash.tools.debugger.VersionException;
+import flash.util.FileUtils;
+
+/**
+ * A module which is uniquly identified by an id, contains
+ * a short and long name and also a script
+ */
+public class DModule implements SourceFile
+{
+       private ScriptText                      m_script;                       
// lazy-initialized by getScript()
+       private boolean                         m_gotRealScript;
+       private final String            m_rawName;
+       private final String            m_shortName;
+       private final String            m_path;
+       private final String            m_basePath;
+       private final int                       m_id;
+       private final int                       m_bitmap;
+       private final ArrayList<Integer>                m_line2Offset;
+       private final ArrayList<Object>                 m_line2Func;            
// each array is either null, String, or String[]
+       private final HashMap<String, Integer>  m_func2FirstLine;       // maps 
function name (String) to first line of function (Integer)
+       private final HashMap<String, Integer>  m_func2LastLine;        // maps 
function name (String) to last line of function (Integer)
+       private String                          m_packageName;
+       private boolean                         m_gotAllFncNames;
+       private int                                     
m_anonymousFunctionCounter = 0;
+       private SourceLocator           m_sourceLocator;
+       private int                                     
m_sourceLocatorChangeCount;
+       private int m_isolateId;
+       private final static String     m_newline = 
System.getProperty("line.separator"); //$NON-NLS-1$
+
+       /**
+        * @param name filename in "basepath;package;filename" format
+        */
+       public DModule(SourceLocator sourceLocator, int id, int bitmap, String 
name, String script, int isolateId)
+       {
+               // If the caller gave us the script text, then we will create 
m_script
+               // now.  But if the caller gave us an empty string, then we 
won't bother
+               // looking for a disk file until someone actually asks for it.
+               if (script != null && script.length() > 0)
+               {
+                       m_script = new ScriptText(script);
+                       m_gotRealScript = true;
+               }
+
+               NameParser nameParser = new NameParser(name);
+
+               m_sourceLocator = sourceLocator;
+               m_rawName = name;
+               m_basePath = nameParser.getBasePath(); // may be null
+               m_bitmap = bitmap;
+               m_id = id;
+               m_shortName = generateShortName(nameParser);
+               m_path = generatePath(nameParser);
+               m_line2Offset = new ArrayList<Integer>();
+               m_line2Func = new ArrayList<Object>();
+               m_func2FirstLine = new HashMap<String, Integer>();
+               m_func2LastLine = new HashMap<String, Integer>();
+               m_packageName = nameParser.getPackage();
+        m_gotAllFncNames = false;
+        m_isolateId = isolateId;
+       }
+
+       public synchronized ScriptText getScript()
+       {
+               // If we have been using "dummy" source, and the user has 
changed the list of
+               // directories that are searched for source, then we want to 
search again
+               if (!m_gotRealScript &&
+                       m_sourceLocator != null &&
+                       m_sourceLocator.getChangeCount() != 
m_sourceLocatorChangeCount)
+               {
+                       m_script = null;
+               }
+
+               // lazy-initialize m_script, so that we don't read a disk file 
until
+               // someone actually needs to look at the file
+               if (m_script == null)
+               {
+            String script = scriptFromDisk(getRawName());
+                       if (script == null)
+                       {
+                               script = ""; // use dummy source for now 
//$NON-NLS-1$
+                       }
+                       else
+                       {
+                               m_gotRealScript = true; // we got the real 
source
+                       }
+                       m_script = new ScriptText(script);
+               }
+               return m_script;
+       }
+
+       /* getters */
+       public String           getBasePath()                   { return 
m_basePath; }
+       public String           getName()                               { 
return m_shortName; }
+       public String           getFullPath()                   { return 
m_path; }
+       public String       getPackageName()            { return (m_packageName 
== null) ? "" : m_packageName; } //$NON-NLS-1$
+       public String           getRawName()                    { return 
m_rawName; }
+       public int                      getId()                                 
{ return m_id; }
+       public int                      getBitmap()                             
{ return m_bitmap; }
+       public int                      getLineCount()                  { 
return getScript().getLineCount(); }
+       public String           getLine(int i)                  { return (i > 
getLineCount()) ? "// code goes here" : getScript().getLine(i); } //$NON-NLS-1$
+
+       void setPackageName(String name)    { m_packageName = name; }
+
+       /**
+        * @return the offset within the swf for a given line 
+        * of source.  0 if unknown.
+        */
+       public int getOffsetForLine(int line)
+       { 
+               int offset = 0;
+               if (line < m_line2Offset.size())
+               {
+                       Integer i = m_line2Offset.get(line);
+                       if (i != null)
+                               offset = i.intValue();
+               }
+               return offset;
+       }
+
+       public int getLineForFunctionName(Session s, String name)
+       {
+               int value = -1;
+        primeAllFncNames(s);
+               Integer i = m_func2FirstLine.get(name);
+               if (i != null)
+                       value = i.intValue();
+
+               return value;
+       }
+
+    /*
+     * @see 
flash.tools.debugger.SourceFile#getFunctionNameForLine(flash.tools.debugger.Session,
 int)
+     */
+    public String getFunctionNameForLine(Session s, int line)
+    {
+        primeFncName(s, line);
+
+       String[] funcNames = getFunctionNamesForLine(s, line);
+
+       if (funcNames != null && funcNames.length == 1)
+               return funcNames[0];
+       else
+               return null;
+    }
+
+       /**
+        * Return the function names for a given line number, or an empty array
+        * if there are none; never returns <code>null</code>.
+        */
+    private String[] getFunctionNamesForLine(Session s, int line)
+    {
+        primeFncName(s, line);
+
+               if (line < m_line2Func.size())
+               {
+                       Object obj = m_line2Func.get(line);
+                       
+                       if (obj instanceof String)
+                               return new String[] { (String) obj };
+                       else if (obj instanceof String[])
+                               return (String[]) obj;
+               }
+
+               return new String[0];
+    }
+
+       public String[] getFunctionNames(Session s)
+       {
+               /* find out the size of the array */
+        primeAllFncNames(s);
+               int count = m_func2FirstLine.size();
+               return m_func2FirstLine.keySet().toArray(new String[count]);
+       }
+
+       private static String generateShortName(NameParser nameParser)
+       {
+               String name = nameParser.getOriginalName();
+               String s = name;
+
+               if (nameParser.isPathPackageAndFilename()) {
+                       s = nameParser.getFilename();
+               } else {
+                       /* do we have a file name? */
+                       int dotAt = name.lastIndexOf('.');
+                       if (dotAt > 1)
+                       {
+                               /* yes let's strip the directory off */
+                               int lastSlashAt = name.lastIndexOf('\\', dotAt);
+                               lastSlashAt = Math.max(lastSlashAt, 
name.lastIndexOf('/', dotAt));
+       
+                               s = name.substring(lastSlashAt+1);
+                       }
+                       else
+                       {
+                               /* not a file name ... */
+                               s = name;
+                       }
+               }
+               return s.trim();
+       }
+
+       /**
+        * Produce a name that contains a file specification including full 
path.
+        * File names may come in as 'mx.bla : file:/bla.foo.as' or as
+        * 'file://bla.foo.as' or as 'C:\'(?) or as 'basepath;package;filename'
+        */
+       private static String generatePath(NameParser nameParser)
+       {
+               String name = nameParser.getOriginalName();
+               String s = name;
+
+               /* strip off first colon of stuff if package exists */
+               int colonAt = name.indexOf(':');
+               if (colonAt > 1 && !name.startsWith("Actions for")) 
//$NON-NLS-1$
+               {
+                       if (name.charAt(colonAt+1) == ' ')
+                               s = name.substring(colonAt+2);
+               }
+               else if (name.indexOf('.') > -1 && name.charAt(0) != '<' )
+               {
+                       /* some other type of file name */
+                       s = nameParser.recombine();
+               }
+               else
+               {
+                       // no path
+                       s = ""; //$NON-NLS-1$
+               }
+               return s.trim();
+       }
+
+       public void lineMapping(StringBuilder sb)
+       {
+               Map<String, String> args = new HashMap<String, String>();
+               args.put("fileName", getName() ); //$NON-NLS-1$
+               args.put("fileNumber", Integer.toString(getId()) ); 
//$NON-NLS-1$
+        
sb.append(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("functionsInFile",
 args)); //$NON-NLS-1$
+               sb.append(m_newline);
+
+               String[] funcNames = m_func2FirstLine.keySet().toArray(new 
String[m_func2FirstLine.size()]);
+               Arrays.sort(funcNames, new Comparator<String>() {
+
+                       public int compare(String o1, String o2) {
+                               int line1 = m_func2FirstLine.get(o1).intValue();
+                               int line2 = m_func2FirstLine.get(o2).intValue();
+                               return line1 - line2;
+                       }
+                       
+               });
+
+               for (int i=0; i<funcNames.length; ++i)
+               {
+                       String name = funcNames[i];
+                       int firstLine = m_func2FirstLine.get(name).intValue();
+                       int lastLine = m_func2LastLine.get(name).intValue();
+
+                       sb.append(" "); //$NON-NLS-1$
+                       sb.append(name);
+                       sb.append(" "); //$NON-NLS-1$
+                       sb.append(firstLine);
+                       sb.append(" "); //$NON-NLS-1$
+                       sb.append(lastLine);
+                       sb.append(m_newline);
+               }
+       }
+
+    int compareTo(DModule other)
+    {
+        return getName().compareTo(other.getName());
+    }
+
+    /**
+     * Called in order to make sure that we have a function name available
+     * at the given location.  For AVM+ swfs we don't need a swd and therefore
+     * don't have access to function names in the same fashion.
+     * We need to ask the player for a particular function name.
+     */
+    void primeFncName(Session s, int line)
+    {
+               // for now we do all, optimize later
+               primeAllFncNames(s);
+    }
+
+    void primeAllFncNames(Session s)
+    {
+        // send out the request for all functions that the player knows
+        // about for this module
+
+        // we block on this call waiting for an answer and after we get it
+        // the DManager thread should have populated our mapping tables
+        // under the covers.  If its fails then no biggie we just won't
+        // see anything in the tables.
+        PlayerSession ps = (PlayerSession)s;
+        if (!m_gotAllFncNames && ps.playerVersion() >= 9)
+        {
+            try
+            {
+                ps.requestFunctionNames(m_id, -1, m_isolateId);
+            }
+            catch (VersionException e)
+            {
+                ;
+            }
+            catch (NoResponseException e)
+            {
+                ;
+            }
+        }
+        m_gotAllFncNames = true;
+    }
+
+       void addLineFunctionInfo(int offset, int line, String funcName)
+       {
+               addLineFunctionInfo(offset, line, line, funcName);
+       }
+
+       /**
+        * Called by DSwfInfo in order to add function name / line / offset 
mapping
+        * information to the module.  
+        */
+       void addLineFunctionInfo(int offset, int firstLine, int lastLine, 
String funcName)
+       {
+               int line;
+
+               // strip down the function name
+               if (funcName == null || funcName.length() == 0)
+               {
+                       funcName = "<anonymous$" + 
(++m_anonymousFunctionCounter) + ">"; //$NON-NLS-1$ //$NON-NLS-2$
+               }
+               else
+               {
+                       // colons or slashes then this is an AS3 name, strip 
off the core::
+                       int colon = funcName.lastIndexOf(':');
+                       int slash = funcName.lastIndexOf('/');
+                       if (colon > -1 || slash > -1)
+                       {
+                               int greater = Math.max(colon, slash);
+                funcName = funcName.substring(greater+1);
+            }
+            else
+            {
+                       int dot = funcName.lastIndexOf('.');
+                       if (dot > -1)
+                       {
+                    // extract function and package
+                    String pkg = funcName.substring(0, dot);
+                    funcName = funcName.substring(dot+1);
+
+                    // attempt to set the package name while we're in here
+                    setPackageName(pkg);
+//                                     
System.out.println(m_id+"-func="+funcName+",pkg="+pkg);
+                }
+            }
+               }
+
+//             System.out.println(m_id+"@"+offset+"="+getPath()+".adding 
func="+funcName);
+
+               // make sure m_line2Offset is big enough for the lines we're 
about to set
+               m_line2Offset.ensureCapacity(firstLine+1);
+               while (firstLine >= m_line2Offset.size())
+                       m_line2Offset.add(null);
+
+               // add the offset mapping
+               m_line2Offset.set(firstLine, new Integer(offset));
+
+               // make sure m_line2Func is big enough for the lines we're 
about to se
+               m_line2Func.ensureCapacity(lastLine+1);
+               while (lastLine >= m_line2Func.size())
+                       m_line2Func.add(null);
+
+               // offset and byteCode ignored currently, only add the name for 
the first hit
+               for (line = firstLine; line <= lastLine; ++line)
+               {
+                       Object funcs = m_line2Func.get(line);
+                       // A line can correspond to more than one function.  
The most common case
+                       // of that is an MXML tag with two event handlers on 
the same line, e.g.
+                       //              <mx:Button mouseOver="overHandler()" 
mouseOut="outHandler()" />;
+                       // another case is the line that declares an inner 
anonymous function:
+                       //              var f:Function = function() { 
trace('hi') }
+                       // In any such case, we store a list of function names 
separated by commas,
+                       // e.g. "func1, func2"
+                       if (funcs == null)
+                       {
+                               m_line2Func.set(line, funcName);
+                       }
+                       else if (funcs instanceof String)
+                       {
+                               String oldFunc = (String) funcs;
+                               m_line2Func.set(line, new String[] { oldFunc, 
funcName });
+                       }
+                       else if (funcs instanceof String[])
+                       {
+                               String[] oldFuncs = (String[]) funcs;
+                               String[] newFuncs = new String[oldFuncs.length 
+ 1];
+                               System.arraycopy(oldFuncs, 0, newFuncs, 0, 
oldFuncs.length);
+                               newFuncs[newFuncs.length - 1] = funcName;
+                               m_line2Func.set(line, newFuncs);
+                       }
+               }
+
+               // add to our function name list
+               if (m_func2FirstLine.get(funcName) == null)
+               {
+                       m_func2FirstLine.put(funcName, new Integer(firstLine));
+                       m_func2LastLine.put(funcName, new Integer(lastLine));
+               }
+       }
+
+    /**
+     * Scan the disk looking for the location of where the source resides.  May
+     * also peel open a swd file looking for the source file.
+     * @param name original full path name of the source file
+     * @return string containing the contents of the file, or null if not found
+     */
+    private String scriptFromDisk(String name)
+    {
+        // we expect the form of the filename to be in the form
+        // "c:/src/project;debug;myFile.as"
+        // where the semicolons demark the include directory searched by the
+        // compiler followed by package directories then file name.
+        // any slashes are to be forward slash only!
+
+        // translate to neutral form
+        name = name.replace('\\','/');  //@todo remove this when compiler is 
complete
+
+        // pull the name apart
+        final char SEP = ';';
+        String pkgPart = ""; //$NON-NLS-1$
+        String pathPart = ""; //$NON-NLS-1$
+        String namePart = ""; //$NON-NLS-1$
+        int at = name.indexOf(SEP);
+        if (at > -1)
+        {
+            // have at least 2 parts to name
+            int nextAt = name.indexOf(SEP, at+1);
+            if (nextAt > -1)
+            {
+                // have 3 parts
+                pathPart = name.substring(0, at);
+                pkgPart = name.substring(at+1, nextAt);
+                namePart = name.substring(nextAt+1);
+            }
+            else
+            {
+                // 2 parts means no package.
+                pathPart = name.substring(0, at);
+                namePart = name.substring(at+1);
+            }
+        }
+        else
+        {
+            // should not be here....
+            // trim by last slash
+            at = name.lastIndexOf('/');
+            if (at > -1)
+            {
+                               // cheat by looking for dirname "mx" in path
+                               int mx = name.lastIndexOf("/mx/"); //$NON-NLS-1$
+                               if (mx > -1)
+                               {
+                                       pathPart = name.substring(0, mx);
+                                       pkgPart = name.substring(mx+1, at);
+                               }
+                               else
+                               {
+                                       pathPart = name.substring(0, at);
+                               }
+                               
+                namePart = name.substring(at+1);
+            }
+            else
+            {
+                pathPart = "."; //$NON-NLS-1$
+                namePart = name;
+            }
+        }
+
+        String script = null;
+        try
+        {
+            // now try to locate the thing on disk or in a swd.
+               Charset realEncoding = null;
+               Charset bomEncoding = null;
+               InputStream in = locateScriptFile(pathPart, pkgPart, namePart);
+               if (in != null)
+               {
+                       try
+                       {
+                               // Read the file using the appropriate 
encoding, based on
+                               // the BOM (if there is a BOM) or the default 
charset for
+                               // the system (if there isn't a BOM)
+                    BufferedInputStream bis = new BufferedInputStream( in );
+                    bomEncoding = getEncodingFromBOM(bis);
+                               script = pullInSource(bis, bomEncoding);
+
+                               // If the file is an XML file with an <?xml> 
directive,
+                               // it may specify a different directive 
+                               realEncoding = 
getEncodingFromXMLDirective(script);
+                       }
+                       finally
+                       {
+                               try { in.close(); } catch (IOException e) {}
+                       }
+               }
+               
+               // If we found an <?xml> directive with a specified encoding, 
and
+               // it doesn't match the encoding we used to read the file 
initially,
+               // start over.
+               if (realEncoding != null && !realEncoding.equals(bomEncoding))
+               {
+                   in = locateScriptFile(pathPart, pkgPart, namePart);
+                   if (in != null)
+                   {
+                                       try
+                                       {
+                                               // Read the file using the real 
encoding, based on the
+                                               // <?xml...> directive
+                           BufferedInputStream bis = new BufferedInputStream( 
in );
+                           getEncodingFromBOM(bis);
+                                       script = pullInSource(bis, 
realEncoding);
+                                       }
+                                       finally
+                                       {
+                                               try { in.close(); } catch 
(IOException e) {}
+                                       }
+                   }
+               }
+        }
+        catch(FileNotFoundException fnf)
+        {
+            fnf.printStackTrace();  // shouldn't really happen
+        }
+        return script;
+    }
+
+    /**
+     * Logic to poke around on disk in order to find the given
+     * filename.  We look under the mattress and all other possible
+     * places for the silly thing.  We always try locating
+     * the file directly first, if that fails then we hunt out
+     * the swd.
+     */
+    InputStream locateScriptFile(String path, String pkg, String name) throws 
FileNotFoundException
+    {
+               if (m_sourceLocator != null)
+               {
+                       m_sourceLocatorChangeCount = 
m_sourceLocator.getChangeCount();
+                       InputStream is = m_sourceLocator.locateSource(path, 
pkg, name);
+                       if (is != null)
+                               return is;
+               }
+
+        // convert slashes first
+        path = path.replace('/', File.separatorChar);
+        pkg = pkg.replace('/', File.separatorChar);
+        File f;
+
+        // use a package base directory if it exists
+               if (path.length() > 0)
+               {
+               try
+               {
+                               String pkgAndName = ""; //$NON-NLS-1$
+                               if (pkg.length() > 0) // have to do this so we 
don't end up with just "/filename"
+                                       pkgAndName += pkg + File.separatorChar;
+                               pkgAndName += name;
+                   f = new File(path, pkgAndName);
+                   if (f.exists())
+                       return new FileInputStream(f);
+               }
+               catch(NullPointerException npe)
+               {
+                   // skip it.
+               }
+               }
+
+        // try the current directory plus package
+               if (pkg.length() > 0) // new File("", foo) looks in root 
directory!
+               {
+                       f = new File(pkg, name);
+                       if (f.exists())
+                               return new FileInputStream(f);
+               }
+
+        // look in the current directory without the package
+        f = new File(name);
+        if (f.exists())
+            return new FileInputStream(f);
+
+        // @todo try to pry open a swd file...
+               
+        return null;
+    }
+    
+    /**
+     * See if this document starts with a BOM and try to figure
+     * out an encoding from it.
+     * @param bis              BufferedInputStream for document (so that we 
can reset the stream
+     *                                         if we establish that the first 
characters aren't a BOM)
+     * @return                 CharSet from BOM (or system default / null)
+     */
+       private Charset getEncodingFromBOM(BufferedInputStream bis)
+       {
+               Charset bomEncoding = null;
+               bis.mark(3);
+               String bomEncodingString;
+               try
+               {
+                       bomEncodingString = FileUtils.consumeBOM(bis, null);
+               }
+               catch (IOException e)
+               {
+                       bomEncodingString = 
System.getProperty("file.encoding"); //$NON-NLS-1$
+               }
+
+               bomEncoding = Charset.forName(bomEncodingString);
+
+               return bomEncoding;
+       }
+
+    /**
+     * Syntax for an <?xml ...> directive with an encoding (used by 
getEncodingFromXMLDirective)
+     */
+    private static final Pattern sXMLDeclarationPattern = 
Pattern.compile("^<\\?xml[^>]*encoding\\s*=\\s*(\"([^\"]*)\"|'([^']*)')"); 
//$NON-NLS-1$
+    
+    /**
+     * See if this document starts with an <?xml ...> directive and
+     * try to figure out an encoding from it.
+     * @param entireSource             source of document
+     * @return                                 specified Charset (or null)
+     */
+    private Charset getEncodingFromXMLDirective(String entireSource)
+    {
+       String encoding = null;
+       Matcher xmlDeclarationMatcher = 
sXMLDeclarationPattern.matcher(entireSource);
+       if (xmlDeclarationMatcher.find())
+       {
+               encoding = xmlDeclarationMatcher.group(2);
+               if (encoding == null)
+                       encoding = xmlDeclarationMatcher.group(3);
+               
+               try
+               {
+                       return Charset.forName(encoding);
+               }
+               catch (IllegalArgumentException e)
+               {}
+       }
+       return null;
+    }
+
+    /**
+     * Given an input stream containing source file contents, read in each line
+     * @param in                       stream of source file contents (with 
BOM removed)
+     * @param encoding         encoding to use (based on BOM, system default, 
or <?xml...> directive
+     *                                                 if this is null, the 
system default will be used)
+     * @return                         source file contents (as String)
+     */
+    String pullInSource(InputStream in, Charset encoding)
+    {
+        String script = ""; //$NON-NLS-1$
+        BufferedReader f = null;
+        try
+        {
+               StringBuilder sb = new StringBuilder();
+               Reader reader = null;
+               if (encoding == null)
+                       reader = new InputStreamReader(in);
+               else
+                       reader = new InputStreamReader(in, encoding);
+            f = new BufferedReader(reader);
+            String line;
+            while((line = f.readLine()) != null)
+            {
+                sb.append(line);
+                sb.append('\n');
+            }
+            script = sb.toString();
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();  //To change body of catch statement use File 
| Settings | File Templates.
+        }
+        return script;
+    }
+
+    /** for debugging */
+    @Override
+       public String toString()
+    {
+       return getFullPath();
+    }
+ 
+       /**
+        * Given a filename of the form "basepath;package;filename", return an
+        * array of 3 strings, one for each segment.
+        * @param name a string which *may* be of the form 
"basepath;package;filename"
+        * @return an array of 3 strings for the three pieces; or, if 'name' is
+        * not of expected form, returns null
+        */
+       private static class NameParser
+       {
+               private String fOriginalName;
+               private String fBasePath;
+               private String fPackage;
+               private String fFilename;
+               private String fRecombinedName;
+
+               public NameParser(String name)
+               {
+                       fOriginalName = name;
+
+                       /* is it of "basepath;package;filename" format? */
+                       int semicolonCount = 0;
+                       int i = 0;
+                       int firstSemi = -1;
+                       int lastSemi = -1;
+                       while ( (i = name.indexOf(';', i)) >= 0 )
+                       {
+                               ++semicolonCount;
+                               if (firstSemi == -1)
+                                       firstSemi = i;
+                               lastSemi = i;
+                               ++i;
+                       }
+
+                       if (semicolonCount == 2)
+                       {
+                               fBasePath = name.substring(0, firstSemi);
+                               fPackage = name.substring(firstSemi+1, 
lastSemi);
+                               fFilename = name.substring(lastSemi+1);
+                       }
+               }
+
+               public boolean isPathPackageAndFilename()
+               {
+                       return (fBasePath != null);
+               }
+
+               public String getOriginalName()
+               {
+                       return fOriginalName;
+               }
+
+               public String getBasePath()
+               {
+                       return fBasePath;
+               }
+
+               public String getFilename()
+               {
+                       return fFilename;
+               }
+
+               public String getPackage()
+               {
+                       return fPackage;
+               }
+
+               /**
+                * Returns a "recombined" form of the original name.
+                * 
+                * For filenames which came in in the form 
"basepath;package;filename",
+                * the recombined name is the original name with the semicolons 
replaced
+                * by platform-appropriate slash characters.  For any other 
type of original
+                * name, the recombined name is the same as the incoming name.
+                */
+               public String recombine()
+               {
+                       if (fRecombinedName == null)
+                       {
+                               if (isPathPackageAndFilename())
+                               {
+                                       char slashChar;
+                                       if (fOriginalName.indexOf('\\') != -1)
+                                               slashChar = '\\';
+                                       else
+                                               slashChar = '/';
+
+                                       fRecombinedName = 
fOriginalName.replaceAll(";;", ";").replace(';', slashChar); //$NON-NLS-1$ 
//$NON-NLS-2$
+                               }
+                               else
+                               {
+                                       fRecombinedName = fOriginalName;
+                               }
+                       }
+                       return fRecombinedName;
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DProtocol.java
----------------------------------------------------------------------
diff --git 
a/debugger/src/main/java/flash/tools/debugger/concrete/DProtocol.java 
b/debugger/src/main/java/flash/tools/debugger/concrete/DProtocol.java
new file mode 100644
index 0000000..7965acb
--- /dev/null
+++ b/debugger/src/main/java/flash/tools/debugger/concrete/DProtocol.java
@@ -0,0 +1,495 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 flash.tools.debugger.concrete;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.EnumMap;
+
+import flash.tools.debugger.SessionManager;
+import flash.util.Trace;
+
+/**
+ * Implements the lower portion of Flash Player debug protocol.  This class is 
able to
+ * communicate with the Flash Player sending and receiving any and all 
messages neccessary
+ * in order to continue a debug session with the Player.
+ * 
+ * It does not understand the context of messages that it receives and merely 
provides
+ * a channel for formatting and unformatting the messages.
+ *  
+ * The messages are defined on the flash side in core/debugtags.h and handled 
in the 
+ * code under core/playerdebugger.cpp
+ * 
+ * Messages that are received via this class are packaged in a DMessage and 
then
+ * provided to any listeners if requested.   Filtering of incoming messages 
+ * at this level is not supported.
+ */
+public class DProtocol implements Runnable
+{
+       public static final int DEBUG_PORT = 7935;
+       
+       /* We connect to AIR in the case of AIR on Android over USB */
+       public static final int DEBUG_CONNECT_PORT = 7936;
+
+       private final BufferedInputStream       m_in;
+       private final BufferedOutputStream      m_out;
+       private final EnumMap<ListenerIndex, DProtocolNotifierIF> m_listeners; 
// WARNING: accessed from multiple threads
+       private long                                            m_msgRx;        
        // WARNING: accessed from multiple threads; use synchronized (this)
+       private long                                            m_msgTx;        
        // WARNING: accessed from multiple threads; use synchronized (this)
+       private volatile boolean                        m_stopRx;               
// WARNING: accessed from multiple threads
+       private volatile Thread                         m_rxThread;             
// WARNING: accessed from multiple threads
+       private volatile Exception m_disconnectCause;
+       private volatile Socket m_socket;
+       private boolean m_detectBrokenSocket;
+
+       public enum ListenerIndex
+       {
+               PlayerSession,
+
+               /**
+                * The DMessageCounter must always be the LAST listener, so 
that the message has
+                * been fully processed before we wake up any threads that were 
waiting until a
+                * message comes in.
+                */
+               MessageCounter
+       }
+
+       public DProtocol(BufferedInputStream in, BufferedOutputStream out)
+       {
+               m_in = in;
+               m_out = out;
+               m_listeners = new EnumMap<ListenerIndex, 
DProtocolNotifierIF>(ListenerIndex.class);
+               m_msgRx = 0;
+               m_msgTx = 0;
+               m_stopRx = false;
+               m_rxThread = null;
+               m_socket = null;
+               m_detectBrokenSocket = false;
+               // Create a message counter, which will listen to us for 
messages
+               addListener(ListenerIndex.MessageCounter, new 
DMessageCounter());
+       }
+       
+       public DProtocol(BufferedInputStream in, BufferedOutputStream out, 
+                       Socket s, boolean detectBrokenSocket)
+       {
+               this(in, out);
+               m_socket = s;
+               m_detectBrokenSocket = detectBrokenSocket;
+       }
+       
+       
+       /**
+        * Set the base socket options
+        * @throws SocketException
+        */
+       static void applyBaseSocketSettings(Socket s) throws SocketException 
+       {
+               // For performance reasons, it is very important that we 
setTcpNoDelay(true),
+               // thus disabling Nagle's algorithm.  Google for TCP_NODELAY or 
Nagle
+               // for more information.
+               //
+               // In addition, we now use a BufferedOutputStream instead of an 
OutputStream.
+               //
+               // These changes result in a huge speedup on the Mac.
+               s.setTcpNoDelay(true);          
+       }
+       
+       static DProtocol createDProtocolFromSocket(Socket s, boolean 
detectBrokenSocket) throws IOException
+       {
+               BufferedInputStream in = new 
BufferedInputStream(s.getInputStream());
+               BufferedOutputStream out = new 
BufferedOutputStream(s.getOutputStream());
+
+               DProtocol dp = new DProtocol(in, out, s, detectBrokenSocket);
+               return dp;
+       }
+
+       /**
+     * Build a DProtocol object from a the given socket connection.
+     */
+       static DProtocol createFromSocket(Socket s) throws IOException
+       {
+               applyBaseSocketSettings(s);
+               return createDProtocolFromSocket(s, false);
+       }
+       
+       /**
+     * Build a DProtocol object from a the given socket connection
+     * and applies socket specific settings set in SessionManager
+     * like socket timeout.
+     */
+       static DProtocol createFromSocket(Socket s, SessionManager 
sessionManager) throws IOException
+       {
+               applyBaseSocketSettings(s);
+               int socketTimeout = 
sessionManager.getPreference(SessionManager.PREF_SOCKET_TIMEOUT);
+               boolean checkSocket = false;
+               if (socketTimeout > 0)
+               {
+                       s.setSoTimeout(socketTimeout);
+                       checkSocket = true;
+               }
+               return createDProtocolFromSocket(s, checkSocket);
+       }
+
+       /**
+        * Allow outside entities to listen for incoming DMessages.
+        * 
+        * @param index
+        *            the index of this listener. Listeners have a strictly 
defined
+        *            order.
+        * @param n
+        *            the listener
+        */
+       public boolean addListener(ListenerIndex index, DProtocolNotifierIF n)
+       {
+               synchronized (m_listeners)
+               {
+                       m_listeners.put(index, n);
+               }
+               return true;
+       }
+
+       public long messagesReceived()          { synchronized (this) { return 
m_msgRx; } }
+       public long messagesSent()                      { synchronized (this) { 
return m_msgTx; } }
+
+       /**
+        * Entry point for our receive thread 
+        */
+       public void run()
+       {
+               try
+               {
+                       m_stopRx = false;
+                       listenForMessages();
+               }
+               catch(Exception ex) 
+               {  
+                       m_disconnectCause = ex;
+                       if (Trace.error &&
+                               !(ex instanceof SocketException && 
ex.getMessage().equalsIgnoreCase("socket closed"))) // closed-socket is not an 
error //$NON-NLS-1$
+                       {
+                               ex.printStackTrace();
+                       }
+               }
+
+               /* notify our listeners that we are no longer listening;  game 
over */
+               DProtocolNotifierIF[] listeners;
+               synchronized (m_listeners)
+               {
+                       listeners = m_listeners.values().toArray(new 
DProtocolNotifierIF[m_listeners.size()]); // copy the list to avoid 
multithreading problems
+               }
+               for (int i=0; i<listeners.length; ++i)
+               {
+                       DProtocolNotifierIF elem = listeners[i];
+                       try
+                       {
+                               elem.disconnected();
+                       }
+                       catch(Exception exc) /* catch unchecked exceptions */
+                       {
+                               if (Trace.error)
+                                       exc.printStackTrace();
+                       }
+               }
+
+               // final notice that this thread is dead! 
+               m_rxThread = null;
+               m_socket = null;
+       }
+
+       /** 
+        * Create and start up a thread for our receiving messages.  
+        */
+       public boolean bind()
+       {
+               /* create a new thread object for us which just listens to 
incoming messages */
+               boolean worked = true;
+               if (m_rxThread == null)
+               {
+                       getMessageCounter().clearInCounts();
+                       getMessageCounter().clearOutCounts();
+
+                       m_rxThread = new Thread(this, "DJAPI message 
listener"); //$NON-NLS-1$
+                       m_rxThread.setDaemon(true);
+                       m_rxThread.start();
+               }
+               else
+                       worked = false;
+
+               return worked;
+       }
+
+       /**
+        * Shutdown our receive thread 
+        */
+       public boolean unbind()
+       {
+               boolean worked = true;
+               if (m_rxThread == null)
+                       worked = false;
+               else
+                       m_stopRx = true;
+
+               return worked;
+       }
+
+       /**
+        * Main rx loop which waits for commands and then issues them to anyone 
listening.
+     */
+       void listenForMessages() throws IOException
+       {
+               DProtocolNotifierIF[] listeners = new DProtocolNotifierIF[0];
+
+               while(!m_stopRx)
+               {
+                       /* read the data */
+                       try
+                       {
+                               DMessage msg = rxMessage();
+
+                               /* Now traverse our list of interested parties 
and let them deal with the message */
+                               synchronized (m_listeners)
+                               {
+                                       listeners = 
m_listeners.values().toArray(listeners); // copy the array to avoid 
multithreading problems
+                               }
+                               for (int i=0; i<listeners.length; ++i)
+                               {
+                                       DProtocolNotifierIF elem = listeners[i];
+                                       try
+                                       {
+                                               elem.messageArrived(msg, this);
+                                       }
+                                       catch (Exception exc) /* catch 
unchecked exceptions */
+                                       {
+//                                             if (Trace.error) 
+//                                             {
+                                                       
System.err.println("Error in listener parsing incoming message :"); 
//$NON-NLS-1$
+                                                       
System.err.println(msg.inToString(16));
+                                                       exc.printStackTrace(); 
+//                                             }
+                                       }
+                                       msg.reset();  /* allow others to 
reparse the message */
+                               }
+
+                               /* now dispose with the message */
+                               DMessageCache.free(msg);
+                       }
+                       catch(InterruptedIOException iio)
+                       { 
+                               // this is a healthy exception that we simply 
ignore, since it means we haven't seen
+                               // data for a while; is all.
+                       }
+               }
+       }
+
+       /**
+        * Transmit the message down the socket.
+        * 
+        * This function is not synchronized; it is only called from one place, 
which is
+        * PlayerSession.sendMessage().  That function is synchronized.
+        */
+       void txMessage(DMessage message) throws IOException
+       {
+               int size = message.getSize();
+               int command = message.getType();
+
+        //System.out.println("txMessage: " + DMessage.outTypeName(command) + " 
size=" + size);
+
+        writeDWord(size);
+               writeDWord(command);
+               writeData(message.getData(), size);
+
+               m_out.flush();
+               synchronized (this) { m_msgTx++; }
+               getMessageCounter().messageSent(message);
+       }
+
+       class SendThread extends Thread {
+               public IOException exception = null;
+               public volatile boolean completed = false;
+               
+               @Override
+               public void run() {
+                       try {
+                               DMessage dm = DMessageCache.alloc(4);
+                               dm.setType(DMessage.OutSetSquelch);
+                               dm.putDWord(1);
+                               txMessage(dm);
+                               DMessageCache.free(dm);
+                               this.completed = true;
+                       }
+                       catch (IOException e) {
+                               this.exception = e;
+                       }
+               }
+       }
+       /** 
+     * Get the next message on the input stream, using the context contained 
within 
+     * the message itself to demark its end
+     */
+       private DMessage rxMessage() throws IOException
+       {
+        int size = -1;
+               int command = 0;
+
+               try 
+               {
+                       size = (int)readDWord();
+                       command = (int)readDWord();
+               }
+               catch (SocketTimeoutException e) 
+               {
+                       if (!m_detectBrokenSocket)
+                               throw e;
+                       //schedule a simple message to be sent for
+                       //heartbeat check 
+                       /**
+                        * Our logic kicks in after PREF_SOCKET_TIMEOUT 
+                        * milliseconds to try and detect broken connection by 
writing 
+                        * a squelch message to the player. If the write 
+                        * succeeds, we assume everything is normal 
+                        * (we don't wait for an ack). Otherwise, we save the 
error
+                        * that clients of FDB can use.
+                        * 
+                        * On Mac, the write() blocks which is why it must
+                        * be done in a separate thread. The thread may take
+                        * upto five minutes to die even after interrupt().
+                        * 
+                        * On Windows, the write() succeeds, but we later get
+                        * a recv abort.
+                        */
+                       int oldBufferSize = -1;
+                       
+                       if (m_socket != null) {
+                               oldBufferSize = m_socket.getSendBufferSize();
+                               m_socket.setSendBufferSize(1);                  
        
+                       }
+                       
+                       SendThread t = new SendThread();
+                       t.start();
+                       long waitBegin = System.currentTimeMillis();
+                       
+                       while (true) {
+                               try {
+                                       t.join(1000);
+                                       if (t.completed)
+                                               break;
+                               } catch (InterruptedException e1) {
+                                       break;
+                               }
+                               long waitEnd = System.currentTimeMillis();
+                               if (waitEnd - waitBegin > 10000)
+                                       break;
+                       }
+                       boolean success = true;
+                       if (t.isAlive()) {
+                               t.interrupt();
+                               success = false;
+                       }
+                       if (oldBufferSize > 0) {
+                               m_socket.setSendBufferSize(oldBufferSize);
+                       }
+                       if (!t.completed) {
+                               success = false;
+                       }
+                       if (t.exception != null) {
+                               throw t.exception;
+                       }
+                       if (success)
+                               throw e;
+                       else
+                               throw new SocketException("Broken pipe"); 
//$NON-NLS-1$
+               }
+        //System.out.println("rxMessage: " + DMessage.inTypeName(command) + " 
size=" + size);
+
+               if (size < 0)
+                       throw new IOException("socket closed"); //$NON-NLS-1$
+
+//             if (DMessage.inTypeName(command).startsWith("InUnknown")) {
+//                     System.out.println("Ignoring unknown message");
+//                     size = 0; 
+//             }
+               
+               /** 
+                * Ask our message cache for a message
+                */
+               DMessage message = DMessageCache.alloc(size);
+               byte[] messageContent = message.getData();
+               int offset = 0;
+
+               /* block until we get the entire message, which may come in 
pieces */
+               while (offset < size)
+                       offset += m_in.read(messageContent, offset, size - 
offset);
+
+               /* now we have the data of the message, set its type and we are 
done */
+               message.setType(command);
+               synchronized (this) { m_msgRx++; }
+               return message;
+       }
+
+       void writeDWord(long dw) throws IOException
+       {
+               byte b0 = (byte)(dw & 0xff);
+               byte b1 = (byte)((dw >> 8) & 0xff);
+               byte b2 = (byte)((dw >> 16) & 0xff);
+               byte b3 = (byte)((dw >> 24) & 0xff);
+
+               m_out.write(b0);
+               m_out.write(b1);
+               m_out.write(b2);
+               m_out.write(b3);
+       }
+
+       void writeData(byte[] data, long size) throws IOException
+       {
+               if (size > 0)
+                       m_out.write(data, 0, (int)size);
+       }
+
+
+       /**
+        * Extract the next 4 bytes, which form a 32b integer, from the stream
+        */
+       long readDWord() throws IOException
+       {
+               int b0 = m_in.read();
+               int b1 = m_in.read();
+               int b2 = m_in.read();
+               int b3 = m_in.read();
+               
+               long value = ((b3 << 24) & 0xff000000) | ((b2 << 16) & 
0xff0000) | ((b1 << 8) & 0xff00) | (b0 & 0xff);
+               return value;
+       }
+
+       public DMessageCounter getMessageCounter()
+       {
+               synchronized (m_listeners)
+               {
+                       return (DMessageCounter) 
m_listeners.get(ListenerIndex.MessageCounter);
+               }
+       }
+
+       public Exception getDisconnectCause() {
+               return m_disconnectCause;
+       }
+       
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/07f5a7de/debugger/src/main/java/flash/tools/debugger/concrete/DProtocolNotifierIF.java
----------------------------------------------------------------------
diff --git 
a/debugger/src/main/java/flash/tools/debugger/concrete/DProtocolNotifierIF.java 
b/debugger/src/main/java/flash/tools/debugger/concrete/DProtocolNotifierIF.java
new file mode 100644
index 0000000..8144711
--- /dev/null
+++ 
b/debugger/src/main/java/flash/tools/debugger/concrete/DProtocolNotifierIF.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 flash.tools.debugger.concrete;
+
+/**
+ * Interface for receiving DMessages from the DProtocol object 
+ */
+public interface DProtocolNotifierIF
+{
+       /**
+        * Issused when a message has been received from the socket
+        */
+       public void messageArrived(DMessage message, DProtocol which);
+
+       /**
+        * Issued when the socket connection to the player is cut 
+        */
+       public void disconnected();
+}

Reply via email to