Add VariableNode which will replace our use of raw NSXMLElement.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 31 Oct 2010 15:24:15 +0000 (11:24 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 31 Oct 2010 15:24:15 +0000 (11:24 -0400)
MacGDBp.xcodeproj/project.pbxproj
Source/VariableNode.h [new file with mode: 0644]
Source/VariableNode.m [new file with mode: 0644]

index eb94723826cf36806c6db030df7cd047e7ee1dcf..1831a9620d33a8e80ac954b993d46a8be9a2c209 100644 (file)
@@ -34,6 +34,7 @@
                1E95834C0E2531D5001A3D89 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1E95831F0E2531BD001A3D89 /* Sparkle.framework */; };
                1EB7BED50ECF3CA90033283A /* StackFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EB7BED40ECF3CA90033283A /* StackFrame.m */; };
                1EBF4D5D0EE35F0700B62769 /* StackController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EBF4D5C0EE35F0700B62769 /* StackController.m */; };
+               1EC1337E127DBB00007946FC /* VariableNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EC1337D127DBB00007946FC /* VariableNode.m */; };
                1EEBFBE50D34C793008F835B /* Debugger.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1EEBFBE30D34C793008F835B /* Debugger.xib */; };
                1EEBFC2B0D358EBD008F835B /* StepIn.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EEBFC2A0D358EBD008F835B /* StepIn.png */; };
                1EEBFC370D358F1B008F835B /* StepOut.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EEBFC360D358F1B008F835B /* StepOut.png */; };
                1EB7BED40ECF3CA90033283A /* StackFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StackFrame.m; path = Source/StackFrame.m; sourceTree = "<group>"; };
                1EBF4D5B0EE35F0700B62769 /* StackController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackController.h; path = Source/StackController.h; sourceTree = "<group>"; };
                1EBF4D5C0EE35F0700B62769 /* StackController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StackController.m; path = Source/StackController.m; sourceTree = "<group>"; };
+               1EC1337C127DBB00007946FC /* VariableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VariableNode.h; path = Source/VariableNode.h; sourceTree = "<group>"; };
+               1EC1337D127DBB00007946FC /* VariableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VariableNode.m; path = Source/VariableNode.m; sourceTree = "<group>"; };
                1EEBFBE40D34C793008F835B /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/Debugger.xib; sourceTree = "<group>"; };
                1EEBFC2A0D358EBD008F835B /* StepIn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = StepIn.png; path = Icons/StepIn.png; sourceTree = "<group>"; };
                1EEBFC360D358F1B008F835B /* StepOut.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = StepOut.png; path = Icons/StepOut.png; sourceTree = "<group>"; };
                                1EB7BED40ECF3CA90033283A /* StackFrame.m */,
                                1EBF4D5B0EE35F0700B62769 /* StackController.h */,
                                1EBF4D5C0EE35F0700B62769 /* StackController.m */,
+                               1EC1337C127DBB00007946FC /* VariableNode.h */,
+                               1EC1337D127DBB00007946FC /* VariableNode.m */,
                        );
                        name = Debugger;
                        sourceTree = "<group>";
                                1E67E6FD0F3C052000E68F1B /* PreferencesPathsArrayController.m in Sources */,
                                1E6B5947116106FE001189D2 /* LoggingController.m in Sources */,
                                1E0724E311B47BCC0017AD3C /* DebuggerConnection.m in Sources */,
+                               1EC1337E127DBB00007946FC /* VariableNode.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Source/VariableNode.h b/Source/VariableNode.h
new file mode 100644 (file)
index 0000000..0c97dd2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * MacGDBp
+ * Copyright (c) 2010, Blue Static <http://www.bluestatic.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU 
+ * General Public License as published by the Free Software Foundation; either version 2 of the 
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with this program; if not, 
+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#import <Cocoa/Cocoa.h>
+
+// A VariableNode represents a property in the variable list display. It
+// converts XML response nodes to this format and extracts all the necessary
+// information. The fields of this class are defined by the spec:
+//  http://www.xdebug.org/docs-dbgp.php#properties-variables-and-values
+@interface VariableNode : NSObject
+{
+  NSString* name_;
+  NSString* fullName_;
+  NSString* className_;
+  NSString* type_;
+  NSString* value_;
+  NSMutableArray* children_;
+  NSInteger childCount_;
+}
+
+@property (readonly, copy) NSString* name;
+@property (readonly, copy) NSString* fullName;
+@property (readonly, copy) NSString* className;
+@property (readonly, copy) NSString* type;
+@property (readonly, copy) NSString* value;
+@property (readonly, retain) NSArray* children;
+@property (readonly) NSInteger childCount;
+
+// Creates and initializes a new VariableNode from the XML response from the
+// debugger backend.
+- (id)initWithXMLNode:(NSXMLElement*)node;
+
+// When properties are asynchrnously loaded, this method can be used to set
+// the children on a node from the list of children from the XML response.
+- (void)setChildrenFromXMLChildren:(NSArray*)children;
+
+// Returns the children and requests any unloaded ones.
+- (NSArray*)dynamicChildren;
+
+// Whether or not this is a leaf node (i.e. does not have child properties).
+- (BOOL)isLeaf;
+
+// Returns a formatted type and classname display.
+- (NSString*)displayType;
+
+@end
diff --git a/Source/VariableNode.m b/Source/VariableNode.m
new file mode 100644 (file)
index 0000000..23ac627
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * MacGDBp
+ * Copyright (c) 2010, Blue Static <http://www.bluestatic.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify it under the terms of the GNU 
+ * General Public License as published by the Free Software Foundation; either version 2 of the 
+ * License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along with this program; if not, 
+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#import "VariableNode.h"
+
+#import "AppDelegate.h"
+#include "base64.h"
+
+// Private Properties //////////////////////////////////////////////////////////
+
+@interface VariableNode ()
+
+@property (copy) NSString* name;
+@property (copy) NSString* fullName;
+@property (copy) NSString* className;
+@property (copy) NSString* type;
+@property (copy) NSString* value;
+@property (retain) NSMutableArray* children;
+
+// Takes an XML node and computes the value.
+- (NSString*)decodeValueForNode:(NSXMLElement*)node;
+
+@end
+
+////////////////////////////////////////////////////////////////////////////////
+
+@implementation VariableNode
+
+@synthesize name = name_;
+@synthesize fullName = fullName_;
+@synthesize className = className_;
+@synthesize type = type_;
+@synthesize value = value_;
+@synthesize children = children_;
+@synthesize childCount = childCount_;
+
+- (id)initWithXMLNode:(NSXMLElement*)node
+{
+  if (self = [super init]) {
+    self.name       = [[node attributeForName:@"name"] stringValue];
+    self.fullName   = [[node attributeForName:@"fullName"] stringValue];
+    self.className  = [[node attributeForName:@"className"] stringValue];
+    self.type       = [[node attributeForName:@"type"] stringValue];
+    self.value      = [self decodeValueForNode:node];
+    self.children   = [NSMutableArray array];
+    if ([node children]) {
+      [self setChildrenFromXMLChildren:[node children]];
+    }
+    childCount_     = [[[node attributeForName:@"numchildren"] stringValue] integerValue];
+  }
+  return self;
+}
+
+- (void)dealloc
+{
+  self.name = nil;
+  self.fullName = nil;
+  self.className = nil;
+  self.type = nil;
+  self.value = nil;
+  self.children = nil;
+  [super dealloc];
+}
+
+- (void)setChildrenFromXMLChildren:(NSArray*)children
+{
+  for (NSXMLElement* child in children) {
+    VariableNode* node = [[VariableNode alloc] initWithXMLNode:child];
+    [children_ addObject:[node autorelease]];
+  }
+}
+
+- (NSArray*)dynamicChildren
+{
+  NSArray* children = self.children;
+  if (![self isLeaf] && [children count] < 1) {
+    // If this node has children but they haven't been loaded from the backend,
+    // request them asynchronously.
+    [[AppDelegate instance].debugger fetchProperty:self.fullName forNode:self];
+  }
+  return children;
+}
+
+- (BOOL)isLeaf
+{
+  return (self.childCount == 0);
+}
+
+- (NSString*)displayType
+{
+  if (self.className != nil) {
+    return [NSString stringWithFormat:@"%@ (%@)", self.className, self.type];
+  }
+  return self.type;
+}
+
+// Private /////////////////////////////////////////////////////////////////////
+
+- (NSString*)decodeValueForNode:(NSXMLElement*)node
+{
+  // Non-leaf nodes do not have a value:
+  //   https://www.bluestatic.org/bugs/showreport.php?bugid=168
+  if (![self isLeaf]) {
+    return @"...";
+  }
+
+  // The value of the node is base64 encoded.
+  if ([[[node attributeForName:@"encoding"] stringValue] isEqualToString:@"base64"]) {
+    const char* str = [[node stringValue] UTF8String];
+    int strlen = [[node stringValue] length];
+
+    char* data;
+    size_t datalen;
+
+    if (!base64_decode_alloc(str, strlen, &data, &datalen))
+      NSLog(@"error in converting %@ from base64", self);
+
+    NSString* ret = nil;
+    if (data) {
+      ret = [NSString stringWithUTF8String:data];
+      free(data);
+    }
+
+    return ret;
+  }
+
+  // The value is just a normal string.
+  return [node stringValue];  
+}
+
+@end