/// <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> Frame stack management related stuff</summary> /// <returns> true if we added this frame; false if we ignored it /// </returns> internal virtual bool addFrame(DStackContext ds) { m_frames.Add(ds); return true; }