/// <summary> /// Retrieve the source code to the specified file. /// </summary> public string Source(string URI) { string remoteURI = "file://"; string s; if (URI[0] != '/') { remoteURI += "/"; } remoteURI += System.Web.HttpUtility.UrlPathEncode(URI); XDebug.Command c = new Command("source", "-f " + remoteURI); XDebug.Response r = this.SendCommand(c); if (r == null) { throw new Exception("Parse error"); } if (r.XmlMessage.InnerText == "can not open file") { MessageBox.Show("Could not load source file. Possibly the source file is empty. Continuing with empty file...", "Source file"); s = ""; } else { s = r.XmlMessage.InnerText; } return(base64ToASCII(s)); }
/// <summary> /// Get the callstack up to this point. /// </summary> public List <StackEntry> GetCallStack(int Depth) { string options = ""; if (Depth != -1) { options = "-d " + Depth; } XDebug.Command c = new Command("stack_get", options); XDebug.Response m = this.SendCommand(c); List <StackEntry> CallStack = new List <StackEntry>(); foreach (XmlElement n in m.XmlMessage.DocumentElement.ChildNodes) { if (n.Name.ToLower() == "stack") { StackEntry se = new StackEntry(); se.fileName = this.getLocalFilename(n.Attributes["filename"].Value); se.lineNumber = System.Convert.ToInt32(n.Attributes["lineno"].Value); se.level = System.Convert.ToInt32(n.Attributes["level"].Value); se.location = n.Attributes["where"].Value; // TODO redundant? just remove the old one? /* Linenumbers have to be zero based. Xdebug uses 1-based. */ se.Location.filename = se.fileName; se.Location.line = se.lineNumber - 1; CallStack.Add(se); } } return(CallStack); }
public static XDebug.Response Parse(String xml) { System.Xml.XmlDocument d = new XmlDocument(); d.LoadXml(xml); XDebug.Response m = new XDebug.Response(); m.RawMessage = xml; m.XmlMessage = d; string messageType = d.DocumentElement.Name.ToLower(); switch (messageType) { case "init": m.MessageType = XDebug.Response.MSG_INIT; string fileUri = d.DocumentElement.Attributes["fileuri"].Value; m.Attributes.Add("file", fileUri); break; case "response": bool isError = false; //d.DocumentElement.FirstChild.Name.ToLower() == "error"; if (isError) { m.MessageType = XDebug.Response.MSG_ERROR; m.Attributes.Add( "ErrorMessage", d.DocumentElement.FirstChild.InnerText ); return(m); } m.MessageType = XDebug.Response.MSG_RESPONSE; // m.TransactionID = d.DocumentElement.Attributes["transaction_id"].Value; if (d.DocumentElement.Attributes["status"] != null) { m.Attributes.Add( "status", d.DocumentElement.Attributes["status"].Value ); } break; default: throw new Exception("Unknown message type: " + messageType); } return(m); }
/// <summary> /// Tell xdebug to remove a line-based breakpoint. Other types /// not yet supported. /// </summary> public void RemoveBreakpoint(Breakpoint brk) { XDebug.Command c = new Command( "breakpoint_remove", String.Format("-d {0}", brk.xdebugId) ); XDebug.Response resp = this.SendCommand(c); }
public static XDebug.Response Parse(String xml) { System.Xml.XmlDocument d = new XmlDocument(); d.LoadXml(xml); XDebug.Response m = new XDebug.Response(); m.RawMessage = xml; m.XmlMessage = d; string messageType = d.DocumentElement.Name.ToLower(); switch (messageType) { case "init": m.MessageType = XDebug.Response.MSG_INIT; string fileUri = d.DocumentElement.Attributes["fileuri"].Value; m.Attributes.Add("file", fileUri); break; case "response": bool isError = false; //d.DocumentElement.FirstChild.Name.ToLower() == "error"; if (isError) { m.MessageType = XDebug.Response.MSG_ERROR; m.Attributes.Add( "ErrorMessage", d.DocumentElement.FirstChild.InnerText ); return m; } m.MessageType = XDebug.Response.MSG_RESPONSE; // m.TransactionID = d.DocumentElement.Attributes["transaction_id"].Value; if (d.DocumentElement.Attributes["status"] != null) { m.Attributes.Add( "status", d.DocumentElement.Attributes["status"].Value ); } break; default: throw new Exception("Unknown message type: " + messageType); } return m; }
/// <summary> /// Tell xdebug to set a line-based breakpoint. Other types /// not yet supported. /// </summary> public void AddBreakpoint(Breakpoint brk) { string filename = "file://"; if (brk.filename[0] != '/') { filename += "/"; } filename += System.Web.HttpUtility.UrlPathEncode(brk.filename); XDebug.Command c = new Command( "breakpoint_set", String.Format( "-t line -f {0} -n {1}", filename, brk.LineNumber_XDebug) ); XDebug.Response resp = this.SendCommand(c); brk.xdebugId = resp.XmlMessage.DocumentElement.Attributes["id"].Value; }
/// <summary> /// Tells XDebug our preferences. /// </summary> public bool Initialize() { /* As soon as we've been connected we'll receive the DBGP init * message. Parse it into a XDebugMessage and pass it to the GUI so * it can load the initial file. */ XDebug.Response initMessage = this.ReceiveMessage(); /* This might throw a NullReference exception. */ try { if (this.handleInitMessage(initMessage)) { if (xdc.Properties.Settings.Default.break_on_fatal_errors) { /* We'd like to know when Fatal errors occur */ XDebug.Command c = new Command("breakpoint_set", "-t exception -x \"Fatal error\""); XDebug.Response r = this.SendCommand(c); } if (xdc.Properties.Settings.Default.break_on_notices) { /* We'd like to know when Notices occur */ XDebug.Command c2 = new Command("breakpoint_set", "-t exception -x \"Notice\""); XDebug.Response r2 = this.SendCommand(c2); } return(true); } } catch (Exception e) { throw new Exception("Initialization failed: " + e.Message); } return(false); }
/// <summary> /// Deal with the init-message xdebug sends us: /// - See if we seem to be compatible language wise /// - See if we're compatible protocol wise /// - Find the initial file and fire off a ConnectionInitialized "event" /// /// Returns true/false /// </summary> private bool handleInitMessage(XDebug.Response initMessage) { if (initMessage == null) { throw new Exception("Init message was empty."); } /* parse out the filename and check wether the version is * compatible with XdebugClient */ XmlElement d = initMessage.XmlMessage.DocumentElement; if (d.Attributes["protocol_version"] != null) { string remoteVersion = d.Attributes["protocol_version"].Value; if (remoteVersion != supportedProtocolVersion) { throw new Exception( String.Format( "Expected version '{0}' but got version '{1}' which is not supported.'", supportedProtocolVersion, remoteVersion ) ); } } if (d.Attributes["language"] != null) { string remoteLanguage = d.Attributes["language"].Value; if (remoteLanguage.ToLower() != supportedLanguage) { throw new Exception( String.Format( "Expected language '{0}' but got '{1}' which is not supported.", supportedLanguage, remoteLanguage ) ); } } if (d.Attributes["fileuri"] != null) { string absoluteFilename = this.getLocalFilename(d.Attributes["fileuri"].Value); XDebugEventArgs xea = new XDebugEventArgs(); xea.Filename = absoluteFilename; xea.EventType = XDebugEventType.ConnectionInitialized; if (this.EventCallback(xea)) { _State = XdebugClientState.Initialized; } else { return(false); } } else { throw new Exception("Missing 'fileuri' attribute."); } return(true); }
/// <summary> /// Parse a response by XDebug. Xdebug sends messages in 2 parts terminated /// by \0. The first part of the message is the length of the second part /// of the message. /// </summary> private XDebug.Response ReceiveMessage() { List <byte> MessageLengthList = new List <byte>(); Byte[] c = new Byte[1]; /* Determine the length of the message byte-by-byte */ do { int bc = _client.Receive(c, 1, SocketFlags.None); if (bc == 0) { // peer close, abort throw new Exception("Socket read error"); } if (c[0] != (byte)0x00) { MessageLengthList.Add(c[0]); } } while (c[0] != (byte)0x00); /* Turn the MessageLengthList into a number by merging it * into a byte array, casting it to a string and then parsing * the integer from it. I wonder if there's a better way to do this.*/ byte[] lengthBytes = MessageLengthList.ToArray(); string lengthStr = System.Text.Encoding.ASCII.GetString(lengthBytes); int length = Convert.ToInt32(lengthStr); /* The message length doesn't include the trailing NULL byte. Add it here */ length++; byte[] messageBytes = new byte[length]; int bytesRead = 0, totalBytesRead = 0, currentByte = 0; do { byte[] xmlMessageBytes = new byte[length]; bytesRead = _client.Receive(xmlMessageBytes, length, SocketFlags.None); if (bytesRead == 0 || bytesRead < 0) { throw new Exception("Socket read error"); } Buffer.BlockCopy(xmlMessageBytes, 0, messageBytes, totalBytesRead, bytesRead); totalBytesRead += bytesRead; //for (int i = 0; i < bytesRead; i++) //{ // messageBytes[currentByte++] = xmlMessageBytes[i]; //} } while (totalBytesRead < length); string xmlMessage = System.Text.Encoding.ASCII.GetString(messageBytes); XDebug.Response resp = XDebug.Response.Parse(xmlMessage); if (resp != null) { if (resp.MessageType == XDebug.Response.MSG_ERROR) { throw new Exception(resp.Attributes["ErrorMessage"]); } XDebugEventArgs xev = new XDebugEventArgs(); xev.Message = resp; xev.EventType = XDebugEventType.MessageReceived; this.EventCallback(xev); } return(resp); }
/// <summary> /// Send a run, step_over or step_in command. /// </summary> public void Run(string command) { XDebug.Command c = new Command(command, ""); XDebug.Response resp = this.SendCommand(c); string status = resp.XmlMessage.DocumentElement.Attributes["status"].Value; string reason = resp.XmlMessage.DocumentElement.Attributes["reason"].Value; this.StackDepth = 0; XDebugEventArgs e; if (reason == "exception") { XmlNode ErrorNode = resp.XmlMessage.DocumentElement.FirstChild; this._State = XdebugClientState.Stopped; e = new XDebugEventArgs(); e.EventType = XDebugEventType.ErrorOccured; e.ErrorMessage = ErrorNode.InnerText; switch (ErrorNode.Attributes["exception"].Value) { case Client.FatalErrorExceptionName: e.ErrorType = XDebugErrorType.FatalError; break; case Client.NoticeExceptionName: e.ErrorType = XDebugErrorType.Warning; break; default: throw new Exception("Unknown exception type"); } this.EventCallback(e); return; } else { switch (status) { case "break": /* execution stopped: breakpoint, step_over/step_in result, etc. */ this._State = XdebugClientState.Break; List <StackEntry> CallStack = this.GetCallStack(0); e = new XDebugEventArgs(); e.CurrentLocation = CallStack[0].Location; e.EventType = XDebugEventType.BreakpointHit; this.EventCallback(e); break; case "stopped": case "stopping": /* Script's done. */ this.Disconnect(); e = new XDebugEventArgs(); e.EventType = XDebugEventType.ScriptFinished; this.EventCallback(e); break; default: throw new Exception("Unknown status: " + status); } } }