/// <summary> Collect stats on outgoing messages </summary> public virtual void messageSent(DMessage msg) { int type = msg.Type; if (type < 0 || type >= DMessage.OutSIZE) type = DMessage.OutSIZE; System.Object outLock = OutLock; lock (outLock) { m_outCounts[type] += 1; System.Threading.Monitor.PulseAll(outLock); // tell anyone who is waiting that a message has been sent } }
/// <summary> Collect stats on outgoing messages </summary> public virtual void messageSent(DMessage msg) { int type = msg.Type; if (type < 0 || type >= DMessage.OutSIZE) { type = DMessage.OutSIZE; } System.Object outLock = OutLock; lock (outLock) { m_outCounts[type] += 1; System.Threading.Monitor.PulseAll(outLock); // tell anyone who is waiting that a message has been sent } }
/// <summary> Main rx loop which waits for commands and then issues them to anyone listening.</summary> internal virtual void listenForMessages() { 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 */ listeners = (DProtocolNotifierIF[])m_listeners.ToArray(typeof(DProtocolNotifierIF)); // 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) { Console.Error.WriteLine("Error in listener parsing incoming message :"); //$NON-NLS-1$ Console.Error.WriteLine(msg.inToString(16)); Console.Error.Write(exc.StackTrace); Console.Error.Flush(); } } msg.reset(); /* allow others to reparse the message */ } /* now dispose with the message */ DMessageCache.free(msg); } //catch (IOException e) //{ // // this is a healthy exception that we simply ignore, since it means we haven't seen // // data for a while; is all. //} finally { } } }
/// <summary> 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. /// </summary> internal virtual void txMessage(DMessage message) { int size = message.Size; int command = message.Type; //System.out.println("txMessage: " + DMessage.outTypeName(command) + " size=" + size); writeDWord(size); writeDWord(command); writeData(message.Data, size); m_out.Flush(); lock (this) { m_msgTx++; } MessageCounter.messageSent(message); }
/// <summary> Collect stats on the messages </summary> public virtual void messageArrived(DMessage msg, DProtocol which) { /* extract type */ int type = msg.Type; // 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; } System.Object inLock = InLock; lock (inLock) { m_inCounts[type] += 1; System.Threading.Monitor.PulseAll(inLock); // tell anyone who is waiting that a message has been received } }
/// <summary> Put a DMessage into the cache for reuse</summary> public static void free(DMessage msg) { int index = size2Index(msg.Size); 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; }
/// <summary> Put a DMessage into the cache for reuse</summary> public static void free(DMessage msg) { int index = size2Index(msg.Size); 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; } }
/// <summary> Get the next message on the input stream, using the context contained within /// the message itself to demark its end /// </summary> private DMessage rxMessage() { long size = readDWord(); long command = readDWord(); //System.out.println("rxMessage: " + DMessage.inTypeName(command) + " size=" + size); if (size < 0 || command < 0) { throw new IOException("socket closed"); //$NON-NLS-1$ } /* * Ask our message cache for a message */ DMessage message = DMessageCache.alloc((int)size); byte[] messageContent = message.Data; int offset = 0; /* block until we get the entire message, which may come in pieces */ while (offset < size) { int count = m_in.Read(messageContent, offset, (int)size - offset); //m_ReceivedLog.Add(messageContent, offset, count); offset += count; } /* now we have the data of the message, set its type and we are done */ message.Type = (int)command; lock (this) { m_msgRx++; } return(message); }
/// <summary> Obtain a DMessage from the cache if possible, otherwise make one for me.</summary> 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; }
/// <summary> Collect stats on the messages </summary> public virtual void messageArrived(DMessage msg, DProtocol which) { /* extract type */ int type = msg.Type; // 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; System.Object inLock = InLock; lock (inLock) { m_inCounts[type] += 1; System.Threading.Monitor.PulseAll(inLock); // tell anyone who is waiting that a message has been received } }
// // Debug purposes only. Dump contents of our messages to the screen // and/or file. // internal virtual void trace(DMessage dm, bool in_Renamed) { lock (this) { try { if (m_debugMsgOn) Console.Out.WriteLine((in_Renamed)?dm.inToString(m_debugMsgSize):dm.outToString(m_debugMsgSize)); if (m_debugMsgFileOn) { traceFile().Write((in_Renamed)?dm.inToString(m_debugMsgFileSize):dm.outToString(m_debugMsgFileSize)); m_trace.Write(s_newline); m_trace.Flush(); } } catch (Exception) { } } }
/// <summary> This is the core routine for decoding incoming messages and deciding what should be /// done with them. We have registered ourself with DProtocol to be notified when any /// incoming messages have been received. /// /// It is important to note that we should not rely on the contents of the message /// since it may be reused after we exit this method. /// </summary> public virtual void messageArrived(DMessage msg, DProtocol which) { if (m_debugMsgOn || m_debugMsgFileOn) trace(msg, true); /* at this point we just open up a big switch statement and walk through all possible cases */ int type = msg.Type; switch (type) { case DMessage.InExit: { m_isConnected = false; break; } case DMessage.InProcessTag: { // need to send a response to this message to keep the player going sendMessage(DMessage.OutProcessedTag); break; } case DMessage.InAskBreakpoints: // case DMessage.InBreakAt: case DMessage.InBreakAtExt: { m_isHalted = true; break; } case DMessage.InContinue: { m_isHalted = false; break; } case DMessage.InOption: { String s = msg.getString(); String v = msg.getString(); // add it to our properties, for DEBUG purposes only m_prefs[s] = v; break; } default: { /* * Simple indicator that we have received a message. We * put this indicator in default so that InProcessTag msgs * wouldn't generate false triggers. Mainly, we want to * reset our timeout counter when we receive trace messages. */ m_incoming = true; break; } } // something came in so assume that we can now talk // to the player m_lastResponse = true; }
// use default timeout internal virtual bool simpleRequestResponseMessage(DMessage msg, int msgType) { return simpleRequestResponseMessage(msg, msgType, - 1); }
/// <summary> Send our message and assume that the next response that is received is /// ours. Primitive but there is no use in setting up a full request / response /// pattern since the player doesn't follow it. /// /// </summary> /// <returns> false is no response. /// </returns> internal virtual bool simpleRequestResponseMessage(DMessage msg, int msgType, int timeout) { bool response = false; // use default or user supplied timeout timeout = (timeout > 0)?timeout:getPreference(SessionManager.PREF_RESPONSE_TIMEOUT); // note the number of messages of this type before our send DMessageCounter msgCounter = MessageCounter; long num = msgCounter.getInCount(msgType); long expect = num + 1; // send the message sendMessage(msg); long startTime = (DateTime.Now.Ticks - 621355968000000000) / 10000; // System.out.println("sending- "+DMessage.outTypeName(msg.getType())+",timeout="+timeout+",start="+start); // now wait till we see a message come in m_incoming = false; lock (msgCounter.InLock) { while ((expect > msgCounter.getInCount(msgType)) && (DateTime.Now.Ticks - 621355968000000000) / 10000 < startTime + timeout && Connected) { // block until the message counter tells us that some message has been received try { System.Threading.Monitor.Wait(msgCounter.InLock, TimeSpan.FromMilliseconds(timeout)); } catch (System.Threading.ThreadInterruptedException e) { // this should never happen Console.Error.Write(e.StackTrace); Console.Error.Flush(); } // if we see incoming messages, then we should reset our timeout lock (this) { if (m_incoming) { startTime = (DateTime.Now.Ticks - 621355968000000000) / 10000; m_incoming = false; } } } } if (msgCounter.getInCount(msgType) >= expect) response = true; else if (timeout <= 0 && Trace.error) Trace.trace("Timed-out waiting for " + DMessage.inTypeName(msgType) + " response to message " + msg.outToString()); //$NON-NLS-1$ //$NON-NLS-2$ // long endTime = System.currentTimeMillis(); // System.out.println(" response- "+response+",timeout="+timeout+",elapsed="+(endTime-startTime)); m_lastResponse = response; return response; }
/// <summary> Send a fully formed message and release it when done</summary> internal virtual void sendMessage(DMessage dm) { lock (this) { try { m_protocol.txMessage(dm); if (m_debugMsgOn || m_debugMsgFileOn) trace(dm, false); } catch (IOException io) { if (Trace.error) { Trace.trace("Attempt to send message " + dm.outToString() + " failed"); //$NON-NLS-1$ //$NON-NLS-2$ Console.Error.Write(io.StackTrace); Console.Error.Flush(); } } DMessageCache.free(dm); } }
internal virtual DVariable extractVariable(DMessage msg) { DVariable v = extractVariable(msg, msg.getString()); return v; }
/// <summary> This is the core routine for decoding incoming messages and deciding what should be /// done with them. We have registered ourself with DProtocol to be notified when any /// incoming messages have been received. /// /// It is important to note that we should not rely on the contents of the message /// since it may be reused after we exit this method. /// </summary> public virtual void messageArrived(DMessage msg, DProtocol which) { /* at this point we just open up a big switch statement and walk through all possible cases */ int type = msg.Type; // System.out.println("manager msg = "+DMessage.inTypeName(type)); switch (type) { case DMessage.InVersion: { long ver = msg.getDWord(); m_playerVersion = (int) ver; break; } case DMessage.InErrorExecLimit: { handleFaultEvent(new RecursionLimitFault()); break; } case DMessage.InErrorWith: { handleFaultEvent(new InvalidWithFault()); break; } case DMessage.InErrorProtoLimit: { handleFaultEvent(new ProtoLimitFault()); break; } case DMessage.InErrorURLOpen: { String url = msg.getString(); handleFaultEvent(new InvalidURLFault(url)); break; } case DMessage.InErrorTarget: { String name = msg.getString(); handleFaultEvent(new InvalidTargetFault(name)); break; } case DMessage.InErrorException: { long offset = msg.getDWord(); // As of FP9, the player will also send the "toString()" message // of the exception. But for backward compatibility with older // players, we won't assume that that is there. String exceptionMessage; if (msg.Remaining > 0) exceptionMessage = msg.getString(); else exceptionMessage = ""; //$NON-NLS-1$ handleFaultEvent(new ExceptionFault(exceptionMessage)); break; } case DMessage.InErrorStackUnderflow: { long offset = msg.getDWord(); handleFaultEvent(new StackUnderFlowFault()); break; } case DMessage.InErrorZeroDivide: { long offset = msg.getDWord(); handleFaultEvent(new DivideByZeroFault()); break; } case DMessage.InErrorScriptStuck: { handleFaultEvent(new ScriptTimeoutFault()); break; } case DMessage.InErrorConsole: { String s = msg.getString(); handleFaultEvent(new ConsoleErrorFault(s)); break; } case DMessage.InTrace: { String text = msg.getString(); addEvent(new TraceEvent(text)); break; } case DMessage.InSquelch: { long state = msg.getDWord(); m_squelchEnabled = (state != 0)?true:false; break; } case DMessage.InParam: { String name = msg.getString(); String value = msg.getString(); // here's where we get movie = URL and password which I'm not sure what to do with? // System.out.println(name+"="+value); m_parms[name] = value; // if string is a "movie", then this is a URL if (name.StartsWith("movie")) //$NON-NLS-1$ m_uri = convertToURI(value); break; } case DMessage.InPlaceObject: { long objId = msg.getDWord(); String path = msg.getString(); // m_bag.placeObject((int)objId, path); break; } case DMessage.InSetProperty: { long objId = msg.getDWord(); int item = msg.getWord(); String value = msg.getString(); break; } case DMessage.InNewObject: { long objId = msg.getDWord(); break; } case DMessage.InRemoveObject: { long objId = msg.getDWord(); // m_bag.removeObject((int)objId); break; } case DMessage.InSetVariable: { long objId = msg.getDWord(); String name = msg.getString(); int dType = msg.getWord(); int flags = (int)msg.getDWord(); String value = msg.getString(); // m_bag.createVariable((int)objId, name, dType, flags, value); break; } case DMessage.InDeleteVariable: { long objId = msg.getDWord(); String name = msg.getString(); // m_bag.deleteVariable((int)objId, name); break; } case DMessage.InScript: { int module = (int)msg.getDWord(); int bitmap = (int)msg.getDWord(); String name = msg.getString(); // in "basepath;package;filename" format String text = msg.getString(); int swfIndex = - 1; /* new in flash player 9: player tells us what swf this is for */ if (msg.Remaining >= 4) swfIndex = (int)msg.getDWord(); lock (m_source) { // create new source file if (putSource(swfIndex, module, bitmap, name, text)) { // have we changed the list since last query if (!m_sourceListModified) addEvent(new FileListModifiedEvent()); m_sourceListModified = true; /* current source list is stale */ } } break; } case DMessage.InRemoveScript: { long module = msg.getDWord(); lock (m_source) { if (removeSource((int) module)) { // have we changed the list since last query if (!m_sourceListModified) addEvent(new FileListModifiedEvent()); m_sourceListModified = true; /* current source list is stale */ } } break; } case DMessage.InAskBreakpoints: { // the player has just loaded a swf and we know the player // has halted, waiting for us to continue. The only caveat // is that it looks like it still does a number of things in // the background which take a few seconds to complete. if (m_suspendInfo == null) m_suspendInfo = new DSuspendInfo(SuspendReason.ScriptLoaded, 0, 0, 0, 0); break; } case DMessage.InBreakAt: { long bp = msg.getDWord(); long id = msg.getDWord(); String stack = msg.getString(); // System.out.println(msg.getInTypeName()+",bp="+(bp&0xffff)+":"+(bp>>16)+",id="+id+",stack=\n"+stack); //System.out.println("InBreakAt"); int module = DLocation.decodeFile(bp); int line = DLocation.decodeLine(bp); addEvent(new BreakEvent(module, line)); break; } case DMessage.InContinue: { /* we are running again so trash all our variable contents */ continuing(); break; } case DMessage.InSetLocalVariables: { long objId = msg.getDWord(); // m_bag.markObjectLocal((int)objId, true); break; } case DMessage.InSetBreakpoint: { long count = msg.getDWord(); while (count-- > 0) { long bp = msg.getDWord(); int fileId = DLocation.decodeFile(bp); int line = DLocation.decodeLine(bp); DModule file = getSource(fileId); DLocation l = new DLocation(file, line); if (file != null) addBreakpoint((int) bp, l); } break; } case DMessage.InNumScript: { /* lets us know how many scripts there are */ int num = (int)msg.getDWord(); DSwfInfo swf; /* * New as of flash player 9: another dword indicating which swf this is for. * That means we don't have to guess whether this is for an old SWF * which has just had some more modules loaded, or for a new SWF! */ if (msg.Remaining >= 4) { int swfIndex = (int)msg.getDWord(); swf = getOrCreateSwfInfo(swfIndex); m_lastSwfInfo = swf; } else { /* This is not flash player 9 (or it is an early build of fp9). * * We use this message as a trigger that a new swf has been loaded, so make sure * we are ready to accept the scripts. */ swf = ActiveSwfInfo; } // It is NOT an error for the player to have sent us a new, // different sourceExpectedCount from whatever we had before! // In fact, this happens all the time, whenever a SWF has more // than one ABC. swf.SourceExpectedCount = num; break; } case DMessage.InRemoveBreakpoint: { long count = msg.getDWord(); while (count-- > 0) { long bp = msg.getDWord(); removeBreakpoint((int) bp); } break; } case DMessage.InBreakAtExt: { long bp = msg.getDWord(); long num = msg.getDWord(); // System.out.println(msg.getInTypeName()+",bp="+(bp&0xffff)+":"+(bp>>16)); /* we have stack info to store away */ clearFrames(); // just in case int depth = 0; while (num-- > 0) { long bpi = msg.getDWord(); long id = msg.getDWord(); String stack = msg.getString(); int module = DLocation.decodeFile(bpi); int line = DLocation.decodeLine(bpi); DModule m = getSource(module); DStackContext c = new DStackContext(module, line, m, (int) id, stack, depth); // If addFrame() returns false, that means it chose to ignore this // frame, so we do NOT want to increment our depth for the next // time through the loop. If it returns true, then we do want to. if (addFrame(c)) ++depth; // System.out.println(" this="+id+",@"+(bpi&0xffff)+":"+(bpi>>16)+",stack="+stack); } mapOldFramesToNew(); break; } case DMessage.InFrame: { // For InFrame the first element is really our frame id DValue frame = null; DVariable child = null; System.Collections.ArrayList v = new System.Collections.ArrayList(); System.Collections.ArrayList registers = new System.Collections.ArrayList(); int depth = (int)msg.getDWord(); // depth of frame // make sure we have a valid depth if (depth > - 1) { // first thing is number of registers int num = (int)msg.getDWord(); for (int i = 0; i < num; i++) registers.Add(extractRegister(msg, i + 1)); } int currentArg = - 1; bool gettingScopeChain = false; // then our frame itself while (msg.Remaining > 0) { long frameId = msg.getDWord(); if (frame == null) { frame = getOrCreateValue(frameId); extractVariable(msg); // put the rest of the info in the trash } else { child = extractVariable(msg); if (currentArg == - 1 && child.getName().Equals(ARGUMENTS_MARKER)) { currentArg = 0; gettingScopeChain = false; } else if (child.getName().Equals(SCOPE_CHAIN_MARKER)) { currentArg = - 1; gettingScopeChain = true; } else if (currentArg >= 0) { // work around a compiler bug: If the variable's name is "undefined", // then change its name to "_argN", where "N" is the argument index, // e.g. _arg1, _arg2, etc. ++currentArg; if (child.getName().Equals("undefined")) //$NON-NLS-1$ child.setName("_arg" + currentArg); //$NON-NLS-1$ } // All args and locals get added as "children" of // the frame; but scope chain entries do not. if (!gettingScopeChain) addVariableMember(frameId, child); // Everything gets added to the ordered list of // variables that came in. v.Add(child); } } // let's transfer our newly gained knowledge into the stack context if (depth == 0) populateRootNode(frame, v); else populateFrame(depth, v); break; } case DMessage.InOption: { String s = msg.getString(); String v = msg.getString(); m_options[s] = v; break; } case DMessage.InGetVariable: { // For InGetVariable the first element is the original entity we requested DValue parent = null; DVariable child = null; String definingClass = null; int level = 0; int highestLevelWithMembers = - 1; System.Collections.IList classes = new System.Collections.ArrayList(); while (msg.Remaining > 0) { long parentId = msg.getDWord(); // build or get parent node if (parent == null) { String name = msg.getString(); // pull the contents of the node which normally are disposed of except if we did a 0,name call m_lastInGetVariable = extractVariable(msg, name); parent = getOrCreateValue(parentId); } else { // extract the child and add it to the parent. child = extractVariable(msg); if (showMember(child)) { if (child.isAttributeSet(VariableAttribute.IS_DYNAMIC)) { // Dynamic attributes always come in marked as a member of // class "Object"; but to the user, it makes more sense to // consider them as members of the topmost class. if (classes.Count > 0) { child.setDefiningClass(0, (String) classes[0]); highestLevelWithMembers = Math.Max(highestLevelWithMembers, 0); } } else { child.setDefiningClass(level, definingClass); if (definingClass != null) { highestLevelWithMembers = Math.Max(highestLevelWithMembers, level); } } addVariableMember(parent.Id, child); } else { if (isTraits(child)) { definingClass = child.QualifiedName; level = classes.Count; // If the traits name end with "$", then it represents a class object -- // in other words, the variables inside it are static variables of that // class. In that case, we need to juggle the information. For example, // if we are told that a variable is a member of "MyClass$", we actually // store it into the information for "MyClass". if (definingClass.EndsWith("$")) { //$NON-NLS-1$ String classWithoutDollar = definingClass.Substring(0, (definingClass.Length - 1) - (0)); int indexOfClass = classes.IndexOf(classWithoutDollar); if (indexOfClass != - 1) { level = indexOfClass; definingClass = classWithoutDollar; } } // It wasn't static -- so, add this class to the end of the list of classes if (level == classes.Count) { classes.Add(definingClass); } } } } } if (parent != null && parent.getClassHierarchy(true) == null) { String[] classesArray = new String[classes.Count]; int index = 0; foreach (String className in classes) { classesArray[index++] = className; } parent.setClassHierarchy(classesArray, highestLevelWithMembers + 1); } break; } case DMessage.InWatch: // for AS2; sends 16-bit ID field case DMessage.InWatch2: // for AS3; sends 32-bit ID field { // This message is sent whenever a watchpoint is added // modified or removed. // // For an addition, flags will be non-zero and // success will be true. // // For a modification flags will be non-zero. // and oldFlags will be non-zero and success // will be true. Additionally oldFlags will not // be equal to flags. // // For a removal flags will be zero. oldFlags // will be non-zero. // // flags identifies the type of watchpoint added, // see WatchKind. // // success indicates whether the operation was successful // // request. It will be associated with the watchpoint. int success = msg.getWord(); int oldFlags = msg.getWord(); int oldTag = msg.getWord(); int flags = msg.getWord(); int tag = msg.getWord(); // for AS2, the ID came in above as a Word. For AS3, the above value is // bogus, and it has been sent again as a DWord. int id = (int)((type == DMessage.InWatch2) ? msg.getDWord() : msg.getWord()); String name = msg.getString(); if (success != 0) { if (flags == 0) { removeWatchpoint(oldTag); } else { // modification or addition is the same to us // a new watch is created and added into the table // while any old entry if it exists is removed. removeWatchpoint(oldTag); DWatch w = new DWatch(id, name, flags, tag); addWatchpoint(w); } } break; } case DMessage.InGetSwf: { // we only house the swf temporarily, PlayerSession then // pieces it back into swfinfo record. Also, we don't // send any extra data in the message so that we need not // copy the bytes. m_swf = msg.Data; break; } case DMessage.InGetSwd: { // we only house the swd temporarily, PlayerSession then // pieces it back into swfinfo record. m_swd = msg.Data; break; } case DMessage.InBreakReason: { // the id map 1-1 with out SuspendReason interface constants int suspendReason = msg.getWord(); int suspendPlayer = msg.getWord(); // item index of player int breakOffset = (int)msg.getDWord(); // current script offset int prevBreakOffset = (int)msg.getDWord(); // prev script offset int nextBreakOffset = (int)msg.getDWord(); // next script offset m_suspendInfo = new DSuspendInfo(suspendReason, suspendPlayer, breakOffset, prevBreakOffset, nextBreakOffset); // augment the current frame with this information. It // should work ok since we only get this message after a // InBreakAtExt message try { DStackContext c = getFrame(0); c.Offset = breakOffset; c.SwfIndex = suspendPlayer; } catch (Exception e) { if (Trace.error) { Trace.trace("Oh my god, gag me with a spoon...getFrame(0) call failed"); //$NON-NLS-1$ Console.Error.Write(e.StackTrace); Console.Error.Flush(); } } break; } // obtain raw action script byte codes case DMessage.InGetActions: { int item = msg.getWord(); int rsvd = msg.getWord(); int at = (int)msg.getDWord(); int len = (int)msg.getDWord(); int i = 0; m_actions = (len <= 0)?null:new byte[len]; while (len-- > 0) m_actions[i++] = (byte)msg.getByte(); break; } // obtain data about a SWF case DMessage.InSwfInfo: { int count = msg.getWord(); for (int i = 0; i < count; i++) { long index = msg.getDWord(); long id = msg.getDWord(); // get it DSwfInfo info = getOrCreateSwfInfo((int) index); // remember which was last seen m_lastSwfInfo = info; if (id != 0) { bool debugComing = (msg.getByte() == 0) ? false : true; byte vmVersion = (byte)msg.getByte(); // AS vm version number (1 = avm+, 0 == avm-) int rsvd1 = msg.getWord(); long swfSize = msg.getDWord(); long swdSize = msg.getDWord(); long scriptCount = msg.getDWord(); long offsetCount = msg.getDWord(); long breakpointCount = msg.getDWord(); long port = msg.getDWord(); String path = msg.getString(); String url = msg.getString(); String host = msg.getString(); // now we read in the swd debugging map (which provides // local to global mappings of the script ids long num = msg.getDWord(); IntMap local2global = new IntMap(); int minId = Int32.MaxValue; int maxId = Int32.MinValue; for (int j = 0; j < num; j++) { long local = msg.getDWord(); long global = msg.getDWord(); local2global.put((int) local, (Int32) global); minId = ((int) global < minId)?(int) global:minId; maxId = ((int) global > maxId)?(int) global:maxId; } // If its a new record then the swf size would have been unknown at creation time bool justCreated = (info.SwfSize == 0); // if we are a avm+ engine then we don't wait for the swd to load if (vmVersion > 0) { debugComing = false; info.VmVersion = vmVersion; info.setPopulated(); // added by mmorearty on 9/5/05 for RSL debugging } // update this swfinfo with the lastest data info.freshen(id, path, url, host, port, debugComing, swfSize, swdSize, breakpointCount, offsetCount, scriptCount, local2global, minId, maxId); // now tie any scripts that have been loaded into this swfinfo object tieScriptsToSwf(info); // notify if its newly created if (justCreated) addEvent(new SwfLoadedEvent(id, (int) index, path, url, host, port, swfSize)); } else { // note our state before marking it bool alreadyUnloaded = info.isUnloaded(); // clear it out info.setUnloaded(); // notify if this information is new. if (!alreadyUnloaded) addEvent(new SwfUnloadedEvent(info.Id, info.Path, (int) index)); } // System.out.println("[SWFLOAD] Loaded "+path+", size="+swfSize+", scripts="+scriptCount); } break; } // obtain the constant pool of some player case DMessage.InConstantPool: { int item = msg.getWord(); int count = (int)msg.getDWord(); String[] pool = new String[count]; for (int i = 0; i < count; i++) { long id = msg.getDWord(); DVariable var = extractVariable(msg); // we only need the contents of the variable pool[i] = var.getValue().ValueAsString; } m_lastConstantPool = pool; break; } // obtain one or more function name line number mappings. case DMessage.InGetFncNames: { long id = msg.getDWord(); // module id long count = msg.getDWord(); // number of entries // get the DModule DModule m = getSource((int) id); if (m != null) { for (int i = 0; i < count; i++) { int offset = (int)msg.getDWord(); int firstLine = (int)msg.getDWord(); int lastLine = (int)msg.getDWord(); String name = msg.getString(); // now add the entries m.addLineFunctionInfo(offset, firstLine, lastLine, name); } } break; } default: { break; } } }
/// <summary> Does the job of pulling together a variable based on /// the type of object encountered. /// </summary> internal virtual DVariable extractAtom(DMessage msg, String name, int oType, int flags) { int vType = VariableType.UNKNOWN; Object value = null; String typeName = ""; //$NON-NLS-1$ String className = ""; //$NON-NLS-1$ /* now we vary depending upon type */ switch (oType) { case DMessage.kNumberType: { String s = msg.getString(); double dval = 0; try { System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo(); dval = Double.Parse(s, nfi); } catch (FormatException) { } value = (double) dval; vType = VariableType.NUMBER; typeName = "Number"; //$NON-NLS-1$ break; } case DMessage.kBooleanType: { int bval = msg.getByte(); value = (bval == 0)?false:true; vType = VariableType.BOOLEAN; typeName = "Boolean"; //$NON-NLS-1$ break; } case DMessage.kStringType: { String s = msg.getString(); value = s; vType = VariableType.STRING; typeName = "String"; //$NON-NLS-1$ break; } case DMessage.kObjectType: case DMessage.kNamespaceType: { long oid = msg.getDWord(); long cType = (oid == -1) ? 0 : msg.getDWord(); int isFnc = (oid == -1) ? 0 : msg.getWord(); int rsvd = (oid == -1) ? 0 : msg.getWord(); typeName = (oid == -1) ? "" : msg.getString(); //$NON-NLS-1$ className = DVariable.classNameFor(cType, false); value = (long) oid; vType = (isFnc == 0)?VariableType.OBJECT:VariableType.FUNCTION; break; } case DMessage.kMovieClipType: { long oid = msg.getDWord(); long cType = (oid == -1) ? 0 : msg.getDWord(); long rsvd = (oid == -1) ? 0 : msg.getDWord(); typeName = (oid == -1) ? "" : msg.getString(); //$NON-NLS-1$ className = DVariable.classNameFor(cType, true); value = (long) oid; vType = VariableType.MOVIECLIP; break; } case DMessage.kNullType: { vType = VariableType.NULL; typeName = "null"; //$NON-NLS-1$ break; } case DMessage.kUndefinedType: { vType = VariableType.UNDEFINED; typeName = "undefined"; //$NON-NLS-1$ break; } case DMessage.kTraitsType: { // 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. vType = VariableType.UNKNOWN; typeName = Value.TRAITS_TYPE_NAME; break; } case DMessage.kReferenceType: case DMessage.kArrayType: case DMessage.kObjectEndType: case DMessage.kStrictArrayType: case DMessage.kDateType: case DMessage.kLongStringType: case DMessage.kUnsupportedType: case DMessage.kRecordSetType: case DMessage.kXMLType: case DMessage.kTypedObjectType: case DMessage.kAvmPlusObjectType: default: { // System.out.println("<unknown>"); break; } } // create the variable based on the content we received. DValue valueObject = null; if (value is Int64) { valueObject = getValue((long) ((Int64) value)); } if (valueObject == null) { valueObject = new DValue(vType, typeName, className, toAttributes(flags), value); if (value is Int64 && (toAttributes(flags) & VariableAttribute.HAS_GETTER) == 0) putValue((long) ((Int64) value), valueObject); } else { valueObject.setType(vType); valueObject.setTypeName(typeName); valueObject.setClassName(className); valueObject.setAttributes(toAttributes(flags)); valueObject.Value = value; } DVariable var = new DVariable(name, valueObject); return var; }
/// <summary> Extracts an builds a register variable</summary> internal virtual DVariable extractRegister(DMessage msg, int number) { int oType = msg.getWord(); return extractAtom(msg, "$" + number, oType, 0); //$NON-NLS-1$ }
/// <summary> Build a variable based on the information we can extract from the messsage</summary> internal virtual DVariable extractVariable(DMessage msg, String name) { int oType = msg.getWord(); int flags = (int)msg.getDWord(); return extractAtom(msg, name, oType, flags); }