From 2e6253593b4129747a9a08b61b45e778021777bf Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Sun, 31 Oct 2010 11:24:15 -0400 Subject: [PATCH] Add VariableNode which will replace our use of raw NSXMLElement. --- MacGDBp.xcodeproj/project.pbxproj | 6 ++ Source/VariableNode.h | 59 ++++++++++++ Source/VariableNode.m | 144 ++++++++++++++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 Source/VariableNode.h create mode 100644 Source/VariableNode.m diff --git a/MacGDBp.xcodeproj/project.pbxproj b/MacGDBp.xcodeproj/project.pbxproj index eb94723..1831a96 100644 --- a/MacGDBp.xcodeproj/project.pbxproj +++ b/MacGDBp.xcodeproj/project.pbxproj @@ -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 */; }; @@ -105,6 +106,8 @@ 1EB7BED40ECF3CA90033283A /* StackFrame.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StackFrame.m; path = Source/StackFrame.m; sourceTree = ""; }; 1EBF4D5B0EE35F0700B62769 /* StackController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StackController.h; path = Source/StackController.h; sourceTree = ""; }; 1EBF4D5C0EE35F0700B62769 /* StackController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StackController.m; path = Source/StackController.m; sourceTree = ""; }; + 1EC1337C127DBB00007946FC /* VariableNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VariableNode.h; path = Source/VariableNode.h; sourceTree = ""; }; + 1EC1337D127DBB00007946FC /* VariableNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VariableNode.m; path = Source/VariableNode.m; sourceTree = ""; }; 1EEBFBE40D34C793008F835B /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/Debugger.xib; sourceTree = ""; }; 1EEBFC2A0D358EBD008F835B /* StepIn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = StepIn.png; path = Icons/StepIn.png; sourceTree = ""; }; 1EEBFC360D358F1B008F835B /* StepOut.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = StepOut.png; path = Icons/StepOut.png; sourceTree = ""; }; @@ -264,6 +267,8 @@ 1EB7BED40ECF3CA90033283A /* StackFrame.m */, 1EBF4D5B0EE35F0700B62769 /* StackController.h */, 1EBF4D5C0EE35F0700B62769 /* StackController.m */, + 1EC1337C127DBB00007946FC /* VariableNode.h */, + 1EC1337D127DBB00007946FC /* VariableNode.m */, ); name = Debugger; sourceTree = ""; @@ -426,6 +431,7 @@ 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 index 0000000..0c97dd2 --- /dev/null +++ b/Source/VariableNode.h @@ -0,0 +1,59 @@ +/* + * MacGDBp + * Copyright (c) 2010, Blue Static + * + * 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 + +// 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 index 0000000..23ac627 --- /dev/null +++ b/Source/VariableNode.m @@ -0,0 +1,144 @@ +/* + * MacGDBp + * Copyright (c) 2010, Blue Static + * + * 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 -- 2.22.5