Permalink
Browse files

Merge remote-tracking branch 'upstream/master'

  • Loading branch information...
bennettp123 committed Apr 22, 2012
2 parents 5f45c38 + 7ed52f2 commit 3c1cf5240b4f4ca7afc1a27133faf2b092f9ea63
View
@@ -9,6 +9,7 @@
#import <Foundation/Foundation.h>
#import "Kdb.h"
#import "DDXML.h"
+#import "DDXMLElementAdditions.h"
#define KDB4_PRE_SIG1 (0x9AA2D903)
#define KDB4_PRE_SIG2 (0xB54BFB66)
View
@@ -8,6 +8,23 @@
#import "Kdb4Node.h"
+@implementation DDXMLElement (MKPAdditions)
+
+- (void)removeChild:(DDXMLNode *)child {
+ int idx = -1;
+ for (int i = 0; i < [self childCount]; i++) {
+ if ([self childAtIndex:i] == child) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx >= 0) {
+ [self removeChildAtIndex:idx];
+ }
+}
+
+@end
+
@implementation Kdb4Group
@synthesize element;
View
@@ -19,6 +19,30 @@
#import "Kdb4Node.h"
#import "Base64.h"
+@implementation DDXMLDocument (MKPDDXMLDocument_Additions)
+
+- (id)initWithReadIO:(xmlInputReadCallback)ioread closeIO:(xmlInputCloseCallback)ioclose context:(void*)ioctx options:(NSUInteger)mask error:(NSError **)error {
+
+ // Even though xmlKeepBlanksDefault(0) is called in DDXMLNode's initialize method,
+ // it has been documented that this call seems to get reset on the iPhone:
+ // http://code.google.com/p/kissxml/issues/detail?id=8
+ //
+ // Therefore, we call it again here just to be safe.
+ xmlKeepBlanksDefault(0);
+
+ xmlDocPtr doc = xmlReadIO(ioread, ioclose, ioctx, NULL, NULL, mask);
+ if (doc == NULL)
+ {
+ if (error) *error = [NSError errorWithDomain:@"DDXMLErrorDomain" code:1 userInfo:nil];
+
+ return nil;
+ }
+
+ return [self initWithDocPrimitive:doc owner:nil];
+}
+
+@end
+
@interface Kdb4Parser (PrivateMethods)
- (void)decodeProtected:(DDXMLElement*)root;
- (Kdb4Group*)parseGroup:(DDXMLElement*)root;
View
@@ -146,12 +146,8 @@ - (void)writeHeader:(OutputStream*)outputStream {
}
- (void)newFile:(NSString*)fileName withPassword:(KdbPassword*)kdbPassword {
- DDXMLElement *docRoot = [DDXMLNode elementWithName:@"KeePassFile"];
-
- DDXMLElement *rootElement = [DDXMLElement elementWithName:@"Root"];
- [docRoot addChild:rootElement];
-
- DDXMLDocument *document = [[DDXMLDocument alloc] initWithRootElement:docRoot];
+ DDXMLDocument *document = [[DDXMLDocument alloc] initWithXMLString:@"<KeePassFile><Root></Root></KeePassFile>" options:0 error:nil];
+ DDXMLElement *rootElement = [[document rootElement] elementForName:@"Root"];
Kdb4Tree *tree = [[Kdb4Tree alloc] initWithDocument:document];
[document release];
View
@@ -11,6 +11,7 @@
#import "KdbPassword.h"
#import "DDXML.h"
+#import "DDXMLElementAdditions.h"
#import "Base64.h"
@interface KdbPassword (PrivateMethods)
@@ -14,6 +14,9 @@
- (NSString *)xmlns;
- (void)setXmlns:(NSString *)ns;
+- (NSString *)prettyXMLString;
+- (NSString *)compactXMLString;
+
- (void)addAttributeWithName:(NSString *)name stringValue:(NSString *)string;
- (NSDictionary *)attributesAsDictionary;
@@ -86,6 +86,22 @@ - (void)setXmlns:(NSString *)ns
[self addNamespace:[DDXMLNode namespaceWithName:@"" stringValue:ns]];
}
+/**
+ * Shortcut to get a pretty (formatted) string representation of the element.
+**/
+- (NSString *)prettyXMLString
+{
+ return [self XMLStringWithOptions:(DDXMLNodePrettyPrint | DDXMLNodeCompactEmptyElement)];
+}
+
+/**
+ * Shortcut to get a compact string representation of the element.
+**/
+- (NSString *)compactXMLString
+{
+ return [self XMLStringWithOptions:DDXMLNodeCompactEmptyElement];
+}
+
/**
* Shortcut to avoid having to manually create a DDXMLNode everytime.
**/
@@ -1,5 +1,8 @@
#import "NSString+DDXML.h"
+#if ! __has_feature(objc_arc)
+#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
+#endif
@implementation NSString (DDXML)
@@ -17,12 +20,11 @@ - (NSString *)stringByTrimming
- (NSString *)stringByTrimming
{
NSMutableString *mStr = [self mutableCopy];
- CFStringTrimWhitespace((CFMutableStringRef)mStr);
+ CFStringTrimWhitespace((__bridge CFMutableStringRef)mStr);
NSString *result = [mStr copy];
- [mStr release];
- return [result autorelease];
+ return result;
}
#endif
View
@@ -1,4 +1,196 @@
+/**
+ * Welcome to KissXML.
+ *
+ * The project page has documentation if you have questions.
+ * https://github.com/robbiehanson/KissXML
+ *
+ * If you're new to the project you may wish to read the "Getting Started" wiki.
+ * https://github.com/robbiehanson/KissXML/wiki/GettingStarted
+ *
+ * KissXML provides a drop-in replacement for Apple's NSXML class cluster.
+ * The goal is to get the exact same behavior as the NSXML classes.
+ *
+ * For API Reference, see Apple's excellent documentation,
+ * either via Xcode's Mac OS X documentation, or via the web:
+ *
+ * https://github.com/robbiehanson/KissXML/wiki/Reference
+**/
+
#import "DDXMLNode.h"
#import "DDXMLElement.h"
#import "DDXMLDocument.h"
-#import "DDXMLElementAdditions.h"
+
+
+
+#if TARGET_OS_IPHONE && 0 // Disabled by default
+
+// Since KissXML is a drop in replacement for NSXML,
+// it may be desireable (when writing cross-platform code to be used on both Mac OS X and iOS)
+// to use the NSXML prefixes instead of the DDXML prefix.
+//
+// This way, on Mac OS X it uses NSXML, and on iOS it uses KissXML.
+
+#ifndef NSXMLNode
+ #define NSXMLNode DDXMLNode
+#endif
+#ifndef NSXMLElement
+ #define NSXMLElement DDXMLElement
+#endif
+#ifndef NSXMLDocument
+ #define NSXMLDocument DDXMLDocument
+#endif
+
+#ifndef NSXMLInvalidKind
+ #define NSXMLInvalidKind DDXMLInvalidKind
+#endif
+#ifndef NSXMLDocumentKind
+ #define NSXMLDocumentKind DDXMLDocumentKind
+#endif
+#ifndef NSXMLElementKind
+ #define NSXMLElementKind DDXMLElementKind
+#endif
+#ifndef NSXMLAttributeKind
+ #define NSXMLAttributeKind DDXMLAttributeKind
+#endif
+#ifndef NSXMLNamespaceKind
+ #define NSXMLNamespaceKind DDXMLNamespaceKind
+#endif
+#ifndef NSXMLProcessingInstructionKind
+ #define NSXMLProcessingInstructionKind DDXMLProcessingInstructionKind
+#endif
+#ifndef NSXMLCommentKind
+ #define NSXMLCommentKind DDXMLCommentKind
+#endif
+#ifndef NSXMLTextKind
+ #define NSXMLTextKind DDXMLTextKind
+#endif
+#ifndef NSXMLDTDKind
+ #define NSXMLDTDKind DDXMLDTDKind
+#endif
+#ifndef NSXMLEntityDeclarationKind
+ #define NSXMLEntityDeclarationKind DDXMLEntityDeclarationKind
+#endif
+#ifndef NSXMLAttributeDeclarationKind
+ #define NSXMLAttributeDeclarationKind DDXMLAttributeDeclarationKind
+#endif
+#ifndef NSXMLElementDeclarationKind
+ #define NSXMLElementDeclarationKind DDXMLElementDeclarationKind
+#endif
+#ifndef NSXMLNotationDeclarationKind
+ #define NSXMLNotationDeclarationKind DDXMLNotationDeclarationKind
+#endif
+
+#ifndef NSXMLNodeOptionsNone
+ #define NSXMLNodeOptionsNone DDXMLNodeOptionsNone
+#endif
+#ifndef NSXMLNodeExpandEmptyElement
+ #define NSXMLNodeExpandEmptyElement DDXMLNodeExpandEmptyElement
+#endif
+#ifndef NSXMLNodeCompactEmptyElement
+ #define NSXMLNodeCompactEmptyElement DDXMLNodeCompactEmptyElement
+#endif
+#ifndef NSXMLNodePrettyPrint
+ #define NSXMLNodePrettyPrint DDXMLNodePrettyPrint
+#endif
+
+#endif // #if TARGET_OS_IPHONE
+
+
+
+// KissXML has rather straight-forward memory management:
+// https://github.com/robbiehanson/KissXML/wiki/MemoryManagementThreadSafety
+//
+// There are 3 important concepts to keep in mind when working with KissXML:
+//
+//
+// 1.) KissXML provides a light-weight wrapper around libxml.
+//
+// The parsing, creation, storage, etc of the xml tree is all done via libxml.
+// This is a fast low-level C library that's been around for ages, and comes pre-installed on Mac OS X and iOS.
+// KissXML provides an easy-to-use Objective-C library atop libxml.
+// So a DDXMLNode, DDXMLElement, or DDXMLDocument are simply objective-c objects
+// with pointers to the underlying libxml C structure.
+// Then only time you need to be aware of any of this is when it comes to equality.
+// In order to maximize speed and provide read-access thread-safety,
+// the library may create multiple DDXML wrapper objects that point to the same underlying xml node.
+// So don't assume you can test for equality with "==".
+// Instead use the isEqual method (as you should generally do with objects anyway).
+//
+//
+// 2.) XML is implicitly a tree heirarchy, and the XML API's are designed to allow traversal up & down the tree.
+//
+// The tree heirarchy and API contract have an implicit impact concerning memory management.
+//
+// <starbucks>
+// <latte/>
+// </starbucks>
+//
+// Imagine you have a DDXMLNode corresponding to the starbucks node,
+// and you have a DDXMLNode corresponding to the latte node.
+// Now imagine you release the starbucks node, but you retain a reference to the latte node.
+// What happens?
+// Well the latte node is a part of the xml tree heirarchy.
+// So if the latte node is still around, the xml tree heirarchy must stick around as well.
+// So even though the DDXMLNode corresponding to the starbucks node may get deallocated,
+// the underlying xml tree structure won't be freed until the latte node gets dealloacated.
+//
+// In general, this means that KissXML remains thread-safe when reading and processing a tree.
+// If you traverse a tree and fork off asynchronous tasks to process subnodes,
+// the tree will remain properly in place until all your asynchronous tasks have completed.
+// In other words, it just works.
+//
+// However, if you parse a huge document into memory, and retain a single node from the giant xml tree...
+// Well you should see the problem this creates.
+// Instead, in this situation, copy or detach the node if you want to keep it around.
+// Or just extract the info you need from it.
+//
+//
+// 3.) KissXML is read-access thread-safe, but write-access thread-unsafe (designed for speed).
+//
+// <starbucks>
+// <latte/>
+// </starbucks>
+//
+// Imagine you have a DDXMLNode corresponding to the starbucks node,
+// and you have a DDXMLNode corresponding to the latte node.
+// What happens if you invoke [starbucks removeChildAtIndex:0]?
+// Well the undelying xml tree will remove the latte node, and release the associated memory.
+// And what if you still have a reference to the DDXMLNode that corresponds to the latte node?
+// Well the short answer is that you shouldn't use it. At all.
+// This is pretty obvious when you think about it from the context of this simple example.
+// But in the real world, you might have multiple threads running in parallel,
+// and you might accidently modify a node while another thread is processing it.
+//
+// To completely fix this problem, and provide write-access thread-safety, would require extensive overhead.
+// This overhead is completely unwanted in the majority of cases.
+// Most XML usage patterns are heavily read-only.
+// And in the case of xml creation or modification, it is generally done on the same thread.
+// Thus the KissXML library is write-access thread-unsafe, but provides speedier performance.
+//
+// However, when such a bug does creep up, it produces horrible side-effects.
+// Essentially the pointer to the underlying xml structure becomes a dangling pointer,
+// which means that accessing the dangling pointer might give you the correct results, or completely random results.
+// And attempting to make modifications to non-existant xml nodes via the dangling pointer might do nothing,
+// or completely corrupt your heap and cause un-explainable crashes in random parts of your library.
+// Heap corruption is one of the worst problems to track down.
+// So to help out, the library provides a debugging macro to track down these problems.
+// That is, if you invalidate the write-access thread-unsafe rule,
+// this macro will tell you when you're trying to access a now-dangling pointer.
+//
+// How does it work?
+// Well everytime a DDXML wrapper object is created atop a libxml structure,
+// it marks the linkage in a table.
+// And everytime a libxml structure is freed, it destorys all corresponding linkages in the table.
+// So everytime a DDXML wrapper objects is about to dereference it's pointer,
+// it first ensures the linkage still exists in the table.
+//
+// Set to 1 to enable
+// Set to 0 to disable (this is the default)
+//
+// The debugging macro adds a significant amount of overhead, and should NOT be enabled on production builds.
+
+#if DEBUG
+ #define DDXML_DEBUG_MEMORY_ISSUES 0
+#else
+ #define DDXML_DEBUG_MEMORY_ISSUES 0 // Don't change me!
+#endif
Oops, something went wrong.

0 comments on commit 3c1cf52

Please sign in to comment.