├── .clang-format ├── LICENSE ├── README.md ├── Storytime-Viewer ├── Storytime-Viewer.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Storytime-Viewer │ ├── AboutViewController.h │ ├── AboutViewController.m │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ ├── About.imageset │ │ │ ├── 1547-question@2x.png │ │ │ ├── 1547-question@3x.png │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon.png │ │ │ ├── icon_20pt.png │ │ │ ├── icon_20pt@2x-1.png │ │ │ ├── icon_20pt@2x.png │ │ │ ├── icon_20pt@3x.png │ │ │ ├── icon_29pt.png │ │ │ ├── icon_29pt@2x-1.png │ │ │ ├── icon_29pt@2x.png │ │ │ ├── icon_29pt@3x.png │ │ │ ├── icon_40pt.png │ │ │ ├── icon_40pt@2x-1.png │ │ │ ├── icon_40pt@2x.png │ │ │ ├── icon_40pt@3x.png │ │ │ ├── icon_60pt@2x.png │ │ │ ├── icon_60pt@3x.png │ │ │ ├── icon_76pt.png │ │ │ ├── icon_76pt@2x.png │ │ │ └── icon_83.5@2x.png │ │ ├── Close.imageset │ │ │ ├── 1572-arrow-down@2x.png │ │ │ ├── 1572-arrow-down@3x.png │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── Logo.imageset │ │ │ ├── Contents.json │ │ │ ├── icon_40pt.png │ │ │ ├── icon_40pt@2x.png │ │ │ └── icon_40pt@3x.png │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Document.h │ ├── Document.m │ ├── DocumentBrowserViewController.h │ ├── DocumentBrowserViewController.m │ ├── DocumentViewController.h │ ├── DocumentViewController.m │ ├── Info.plist │ └── main.m └── Storytime-ViewerTests │ ├── Info.plist │ └── Storytime_ViewerTests.m ├── Storytime.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── hezi.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Storytime ├── CXMLElement+Storytime.h ├── CXMLElement+Storytime.m ├── Info.plist ├── STTBarButtonItem.h ├── STTBarButtonItem.m ├── STTBoard.h ├── STTBoard.m ├── STTCSS.h ├── STTCSS.m ├── STTElement.h ├── STTNavigationItem.h ├── STTNavigationItem.m ├── STTScene.h ├── STTScene.m ├── STTTableView.h ├── STTTableView.m ├── STTView.h ├── STTView.m ├── STTViewController.h ├── STTViewController.m ├── Storytime.h ├── TouchXML │ ├── CXMLDocument_CreationExtensions.h │ ├── CXMLDocument_CreationExtensions.m │ ├── CXMLNode_CreationExtensions.h │ └── CXMLNode_CreationExtensions.m ├── ratchet-theme-ios.min.css ├── ratchet.css └── template.html ├── StorytimeTests ├── Info.plist └── StorytimeTests.m ├── StorytimeiOS ├── Info.plist └── StorytimeiOS.h ├── StorytimeiOSTests ├── Info.plist └── StorytimeiOSTests.m ├── Vendor └── TouchXML │ ├── .gitignore │ ├── .travis.yml │ ├── CXHTMLDocument.h │ ├── CXHTMLDocument.m │ ├── CXMLDocument.h │ ├── CXMLDocument.m │ ├── CXMLDocument_PrivateExtensions.h │ ├── CXMLDocument_PrivateExtensions.m │ ├── CXMLElement.h │ ├── CXMLElement.m │ ├── CXMLElement_CreationExtensions.h │ ├── CXMLElement_CreationExtensions.m │ ├── CXMLElement_ElementTreeExtensions.h │ ├── CXMLElement_ElementTreeExtensions.m │ ├── CXMLNamespaceNode.h │ ├── CXMLNamespaceNode.m │ ├── CXMLNode.h │ ├── CXMLNode.m │ ├── CXMLNode_PrivateExtensions.h │ ├── CXMLNode_PrivateExtensions.m │ ├── CXMLNode_XPathExtensions.h │ ├── CXMLNode_XPathExtensions.m │ ├── CXMLUnsupportedNode.h │ ├── CXMLUnsupportedNode.m │ ├── Tidy │ ├── CTidy.h │ └── CTidy.m │ └── TouchXML.h ├── fix_format.sh ├── readme └── appstore-badge.svg └── screenshot.png /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: WebKit 3 | BreakBeforeBraces: Attach 4 | TabWidth: '4' 5 | UseTab: Never 6 | PointerBindsToType: false 7 | AllowShortIfStatementsOnASingleLine: false 8 | AllowShortFunctionsOnASingleLine: false 9 | AllowShortLoopsOnASingleLine: false 10 | 11 | ... 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Jorge Cohen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Storytime 2 | 3 | 4 | 5 | Storytime is a framework to parse and render Interface Builder Storyboard files. 6 | Support for more components and output formats soon. 7 | 8 | 9 | 10 | By [Jorge Cohen](http://twitter.com/jorgewritescode), See the LICENSE file for license info (it's the MIT license). 11 | 12 | If you find this useful please consider [buying me a beer](http://paypal.me/jorgecohen) :) 13 | 14 | ## Motivation 15 | If you've ever developed for iOS/macOS you've probably tried to QuickLook into a storyboard file only to be disappointed. 16 | I've created Storytime as a way to visually display storyboards outside of Interface Builder, This could be QuickLook, Git Client, etc. 17 | 18 | ## Internals 19 | Storyboards a actually very simple XML files so parsing them is pretty stright forward. 20 | Initially I tried using XSLT to transform the Storyboard into HTML but ran into some issues. 21 | 22 | This version parses the storyboard into classes conforming to a protocol `STTElement` which defines the `-htmlRepesentation` method. 23 | Using the Ratchet CSS framework and the html produced by the various elements you get a pretty (although not 100%) accurate visual representation of the storyboard. 24 | 25 | ## Known Issues 26 | There are a lot of them! 27 | 28 | 1. Views (`-htmlRepresentation`) are coupled with the models (`STTElement`) which is due to me being in a hurry to get this working 29 | 2. Various rendering issues 30 | 3. CSS coupled with HTML template 31 | 4. etc. 32 | 33 | Feel free to create issues when you find them. 34 | 35 | ## Questions 36 | 37 | ### Why Objective-C? 38 | It's what I like using, also, it's required if you want to create a QuickLook generator. 39 | 40 | ### Why is the code like this? 41 | Well, this started out as a quick hack and I got excited when things first started showing up so I wanted to release it as fast as possible :) 42 | 43 | ## Acknowledgement 44 | 45 | * [Ratchet](https://github.com/twbs/ratchet) 46 | * [TouchXML](https://github.com/TouchCode/TouchXML) 47 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/AboutViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AboutViewController.h 3 | // Storytime-Viewer 4 | // 5 | // Created by Hezi Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AboutViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/AboutViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AboutViewController.m 3 | // Storytime-Viewer 4 | // 5 | // Created by Hezi Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "AboutViewController.h" 10 | 11 | @interface AboutViewController () 12 | @property (nonatomic) NSArray *aboutURLS; 13 | @end 14 | 15 | @implementation AboutViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | self.aboutURLS = @[ 21 | [NSURL URLWithString:@"http://twitter.com/jorgewritecode"], 22 | [NSURL URLWithString:@"http://jorgecohen.codes"], 23 | [NSURL URLWithString:@"https://github.com/twbs/ratchet"], 24 | [NSURL URLWithString:@"https://github.com/TouchCode/TouchXML"], 25 | [NSURL URLWithString:@"http://www.glyphish.com/"] 26 | ]; 27 | } 28 | 29 | - (void)didReceiveMemoryWarning { 30 | [super didReceiveMemoryWarning]; 31 | // Dispose of any resources that can be recreated. 32 | } 33 | 34 | - (IBAction)dismiss:(id)sender { 35 | [self dismissViewControllerAnimated:YES completion:nil]; 36 | } 37 | 38 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 39 | [[UIApplication sharedApplication] openURL:_aboutURLS[(indexPath.section * 2) + indexPath.row] options:@{} completionHandler:nil]; 40 | } 41 | 42 | /* 43 | #pragma mark - Navigation 44 | 45 | // In a storyboard-based application, you will often want to do a little preparation before navigation 46 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 47 | // Get the new view controller using [segue destinationViewController]. 48 | // Pass the selected object to the new view controller. 49 | } 50 | */ 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "Document.h" 11 | #import "DocumentBrowserViewController.h" 12 | #import "DocumentViewController.h" 13 | 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 21 | // Override point for customization after application launch. 22 | return YES; 23 | } 24 | 25 | - (void)applicationWillResignActive:(UIApplication *)application { 26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | - (void)applicationWillEnterForeground:(UIApplication *)application { 36 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | - (void)applicationDidBecomeActive:(UIApplication *)application { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | } 42 | 43 | - (void)applicationWillTerminate:(UIApplication *)application { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | - (BOOL)application:(UIApplication *)app openURL:(NSURL *)inputURL options:(NSDictionary *)options { 48 | // Ensure the URL is a file URL 49 | if (!inputURL.isFileURL) { 50 | return NO; 51 | } 52 | 53 | // Reveal / import the document at the URL 54 | DocumentBrowserViewController *documentBrowserViewController = (DocumentBrowserViewController *)self.window.rootViewController; 55 | [documentBrowserViewController revealDocumentAtURL:inputURL 56 | importIfNeeded:YES 57 | completion:^(NSURL *_Nullable revealedDocumentURL, NSError *_Nullable error) { 58 | if (error) { 59 | // Handle the error appropriately 60 | NSLog(@"Failed to reveal the document at URL %@ with error: '%@'", inputURL, error); 61 | return; 62 | } 63 | 64 | // Present the Document View Controller for the revealed URL 65 | [documentBrowserViewController presentDocumentAtURL:revealedDocumentURL]; 66 | }]; 67 | return YES; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/About.imageset/1547-question@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/About.imageset/1547-question@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/About.imageset/1547-question@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/About.imageset/1547-question@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/About.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "1547-question@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "1547-question@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "icon_20pt@2x-1.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "icon_20pt@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon_29pt@2x-1.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "icon_29pt@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon_40pt@2x-1.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "icon_40pt@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon_60pt@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon_60pt@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "icon_20pt.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "icon_20pt@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "icon_29pt.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "icon_29pt@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "icon_40pt.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "icon_40pt@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "icon_76pt.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "icon_76pt@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "icon_83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "Icon.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/Icon.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x-1.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_20pt@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x-1.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_29pt@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x-1.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_40pt@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_60pt@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_60pt@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_76pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_76pt.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_76pt@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/AppIcon.appiconset/icon_83.5@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Close.imageset/1572-arrow-down@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Close.imageset/1572-arrow-down@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Close.imageset/1572-arrow-down@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Close.imageset/1572-arrow-down@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Close.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "1572-arrow-down@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "1572-arrow-down@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "icon_40pt.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "icon_40pt@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "icon_40pt@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/icon_40pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/icon_40pt.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/icon_40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/icon_40pt@2x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/icon_40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/Storytime-Viewer/Storytime-Viewer/Assets.xcassets/Logo.imageset/icon_40pt@3x.png -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Document.h: -------------------------------------------------------------------------------- 1 | // 2 | // Document.h 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Document : UIDocument 12 | @property (nonatomic) NSString *htmlString; 13 | @end 14 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Document.m: -------------------------------------------------------------------------------- 1 | // 2 | // Document.m 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "Document.h" 10 | #import 11 | #import 12 | 13 | @implementation Document 14 | 15 | - (id)contentsForType:(NSString *)typeName error:(NSError **)errorPtr { 16 | // Encode your document with an instance of NSData or NSFileWrapper 17 | return [[NSData alloc] init]; 18 | } 19 | 20 | - (BOOL)readFromURL:(NSURL *)url error:(NSError *_Nullable __autoreleasing *)outError { 21 | // Hack so we don't open non storyboard files (as document type in Info.plist is set to all files) 22 | 23 | if ([[url pathExtension] isEqualToString:@"storyboard"]) { 24 | return [super readFromURL:url error:outError]; 25 | } 26 | 27 | return NO; 28 | } 29 | 30 | - (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)errorPtr { 31 | NSString *uti = (__bridge NSString *)(UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef _Nonnull)(self.fileURL.pathExtension), nil)); 32 | 33 | NSLog(@"%@", uti); 34 | NSData *data = contents; 35 | NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 36 | 37 | STTBoard *board = [[STTBoard alloc] initWithXMLString:string]; 38 | self.htmlString = board.htmlRepresentation; 39 | return YES; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/DocumentBrowserViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentBrowserViewController.h 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DocumentBrowserViewController : UIDocumentBrowserViewController 12 | 13 | - (void)presentDocumentAtURL:(NSURL *)documentURL; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/DocumentBrowserViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentBrowserViewController.m 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "DocumentBrowserViewController.h" 10 | #import "Document.h" 11 | #import "DocumentViewController.h" 12 | 13 | @interface DocumentBrowserViewController () 14 | 15 | @end 16 | 17 | @implementation DocumentBrowserViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.delegate = self; 22 | self.allowsDocumentCreation = NO; 23 | self.allowsPickingMultipleItems = NO; 24 | 25 | self.additionalLeadingNavigationBarButtonItems = @[ [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"About"] style:(UIBarButtonItemStylePlain)target:self action:@selector(presentAbout:)] ]; 26 | } 27 | 28 | - (IBAction)presentAbout:(id)sender { 29 | UIViewController *aboutViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"AboutViewController"]; 30 | 31 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:aboutViewController]; 32 | 33 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 34 | navController.modalPresentationStyle = UIModalPresentationPopover; 35 | [self presentViewController:navController animated:YES completion:nil]; 36 | navController.popoverPresentationController.barButtonItem = sender; 37 | 38 | } else { 39 | [self presentViewController:navController animated:YES completion:nil]; 40 | } 41 | } 42 | 43 | #pragma mark UIDocumentBrowserViewControllerDelegate 44 | 45 | - (void)documentBrowser:(UIDocumentBrowserViewController *)controller didPickDocumentURLs:(NSArray *)documentURLs { 46 | 47 | #if TARGET_OS_SIMULATOR 48 | [self presentDocumentAtURL:[NSURL fileURLWithPath:@"/Users/hezi/Development/Storytime/Storytime-Viewer/Storytime-Viewer/Base.lproj/Main.storyboard"]]; 49 | #endif 50 | 51 | NSURL *sourceURL = documentURLs.firstObject; 52 | if (!sourceURL) { 53 | return; 54 | } 55 | 56 | // Present the Document View Controller for the first document that was picked. 57 | // If you support picking multiple items, make sure you handle them all. 58 | [self presentDocumentAtURL:sourceURL]; 59 | } 60 | 61 | - (void)documentBrowser:(UIDocumentBrowserViewController *)controller didImportDocumentAtURL:(NSURL *)sourceURL toDestinationURL:(NSURL *)destinationURL { 62 | // Present the Document View Controller for the new newly created document 63 | [self presentDocumentAtURL:destinationURL]; 64 | } 65 | 66 | - (void)documentBrowser:(UIDocumentBrowserViewController *)controller failedToImportDocumentAtURL:(NSURL *)documentURL error:(NSError *_Nullable)error { 67 | // Make sure to handle the failed import appropriately, e.g., by presenting an error message to the user. 68 | } 69 | 70 | // MARK: Document Presentation 71 | 72 | - (void)presentDocumentAtURL:(NSURL *)documentURL { 73 | UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 74 | DocumentViewController *documentViewController = [storyBoard instantiateViewControllerWithIdentifier:@"DocumentViewController"]; 75 | documentViewController.document = [[Document alloc] initWithFileURL:documentURL]; 76 | 77 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:documentViewController]; 78 | 79 | [self presentViewController:navController animated:YES completion:nil]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/DocumentViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentViewController.h 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "Document.h" 10 | #import 11 | 12 | @interface DocumentViewController : UIViewController 13 | 14 | @property (strong) Document *document; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/DocumentViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DocumentViewController.m 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "DocumentViewController.h" 10 | #import 11 | 12 | @interface DocumentViewController () 13 | @property (weak, nonatomic) IBOutlet WKWebView *webView; 14 | @end 15 | 16 | @implementation DocumentViewController 17 | 18 | - (void)viewWillAppear:(BOOL)animated { 19 | [super viewWillAppear:animated]; 20 | } 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | [self.document openWithCompletionHandler:^(BOOL success) { 25 | if (success) { 26 | // Display the content of the document, e.g.: 27 | self.title = [self.document.fileURL lastPathComponent]; 28 | [self.webView loadHTMLString:self.document.htmlString baseURL:[[NSBundle bundleForClass:self.class] bundleURL]]; 29 | } else { 30 | // Make sure to handle the failed import appropriately, e.g., by presenting an error message to the user. 31 | [self dismissViewControllerAnimated:YES completion:nil]; 32 | } 33 | }]; 34 | } 35 | 36 | - (IBAction)presentAbout:(id)sender { 37 | UIViewController *aboutViewController = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"AboutViewController"]; 38 | 39 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:aboutViewController]; 40 | 41 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 42 | navController.modalPresentationStyle = UIModalPresentationPopover; 43 | [self presentViewController:navController animated:YES completion:nil]; 44 | navController.popoverPresentationController.barButtonItem = sender; 45 | 46 | } else { 47 | [self presentViewController:navController animated:YES completion:nil]; 48 | } 49 | } 50 | 51 | - (IBAction)dismissDocumentViewController { 52 | [self dismissViewControllerAnimated:YES 53 | completion:^{ 54 | [self.document closeWithCompletionHandler:nil]; 55 | }]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Storytime 9 | CFBundleDocumentTypes 10 | 11 | 12 | CFBundleTypeIconFiles 13 | 14 | CFBundleTypeName 15 | All Files 16 | CFBundleTypeRole 17 | Viewer 18 | LSHandlerRank 19 | Alternate 20 | LSItemContentTypes 21 | 22 | public.item 23 | 24 | 25 | 26 | CFBundleExecutable 27 | $(EXECUTABLE_NAME) 28 | CFBundleIdentifier 29 | $(PRODUCT_BUNDLE_IDENTIFIER) 30 | CFBundleInfoDictionaryVersion 31 | 6.0 32 | CFBundleName 33 | $(PRODUCT_NAME) 34 | CFBundlePackageType 35 | APPL 36 | CFBundleShortVersionString 37 | 1.0 38 | CFBundleVersion 39 | 2 40 | LSRequiresIPhoneOS 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | UISupportsDocumentBrowser 64 | 65 | UTImportedTypeDeclarations 66 | 67 | 68 | UTTypeIdentifier 69 | dyn.age81g7dtsm60e55bsmwa 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-Viewer/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Storytime-Viewer 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import 11 | 12 | int main(int argc, char *argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-ViewerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Storytime-Viewer/Storytime-ViewerTests/Storytime_ViewerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Storytime_ViewerTests.m 3 | // Storytime-ViewerTests 4 | // 5 | // Created by Jorge Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Storytime_ViewerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Storytime_ViewerTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Storytime.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Storytime.xcodeproj/xcuserdata/hezi.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Storytime.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | StorytimeiOS.xcscheme 13 | 14 | orderHint 15 | 1 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Storytime/CXMLElement+Storytime.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSXMLElement+Storytime.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "CXMLElement.h" 10 | #import 11 | 12 | @interface CXMLElement (Storytime) 13 | - (CXMLElement *)elementForName:(NSString *)name; 14 | - (NSString *)stringAttributeForName:(NSString *)name; 15 | - (NSNumber *)numberAttributeForName:(NSString *)name; 16 | 17 | - (CGPoint)pointValue; 18 | - (CGRect)rectValue; 19 | @end 20 | -------------------------------------------------------------------------------- /Storytime/CXMLElement+Storytime.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSXMLElement+Storytime.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "CXMLElement+Storytime.h" 10 | 11 | @implementation CXMLElement (Storytime) 12 | - (CXMLElement *)elementForName:(NSString *)name { 13 | NSArray *elements = [self elementsForName:name]; 14 | 15 | if (elements.count > 0) 16 | return elements[0]; 17 | 18 | return nil; 19 | } 20 | 21 | - (NSString *)stringAttributeForName:(NSString *)name { 22 | return [self attributeForName:name].stringValue; 23 | } 24 | 25 | - (NSNumber *)numberAttributeForName:(NSString *)name { 26 | return (NSNumber *)@([self attributeForName:name].stringValue.floatValue); 27 | } 28 | 29 | - (CGPoint)pointValue { 30 | NSNumber *x = [self numberAttributeForName:@"x"]; 31 | NSNumber *y = [self numberAttributeForName:@"y"]; 32 | 33 | return CGPointMake(x.floatValue, y.floatValue); 34 | } 35 | 36 | - (CGRect)rectValue { 37 | NSNumber *x = [self numberAttributeForName:@"x"]; 38 | NSNumber *y = [self numberAttributeForName:@"y"]; 39 | NSNumber *width = [self numberAttributeForName:@"width"]; 40 | NSNumber *height = [self numberAttributeForName:@"height"]; 41 | 42 | return CGRectMake(x.floatValue, y.floatValue, width.floatValue, height.floatValue); 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Storytime/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2018 Jorge Cohen. All rights reserved. 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Storytime/STTBarButtonItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTBarButtonItem.h 3 | // Storytime 4 | // 5 | // Created by Hezi Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTElement.h" 10 | #import 11 | 12 | typedef enum : NSUInteger { 13 | STTBarButtonPositionLeft, 14 | STTBarButtonPositionRight 15 | } STTBarButtonPosition; 16 | 17 | @interface STTBarButtonItem : NSObject 18 | @property (nonatomic, assign) STTBarButtonPosition position; 19 | @property (nonatomic) NSString *title; 20 | @end 21 | -------------------------------------------------------------------------------- /Storytime/STTBarButtonItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTBarButtonItem.m 3 | // Storytime 4 | // 5 | // Created by Hezi Cohen on 3/26/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTBarButtonItem.h" 10 | #import "CXMLElement+Storytime.h" 11 | 12 | @implementation STTBarButtonItem 13 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 14 | self = [super init]; 15 | if (self) { 16 | self.title = [element stringAttributeForName:@"title"] ?: @""; 17 | if ([[element stringAttributeForName:@"key"] isEqualToString:@"leftBarButtonItem"]) { 18 | self.position = STTBarButtonPositionLeft; 19 | } else { 20 | self.position = STTBarButtonPositionRight; 21 | } 22 | } 23 | 24 | return self; 25 | } 26 | 27 | - (NSString *)htmlRepresentation { 28 | NSString *class; 29 | if (self.position == STTBarButtonPositionRight) { 30 | class = @"btn btn-link btn-nav pull-right"; 31 | } else { 32 | class = @"btn btn-link btn-nav pull-left"; 33 | } 34 | 35 | return [NSString stringWithFormat:@"", class, self.title]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Storytime/STTBoard.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTBoard.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTElement.h" 10 | #import 11 | 12 | @interface STTBoard : NSObject 13 | - (instancetype)initWithURL:(NSURL *)url; 14 | - (instancetype)initWithXMLString:(NSString *)xmlString; 15 | - (NSString *)htmlRepresentation; 16 | @property (nonatomic, assign) CGPoint origin; 17 | @property (nonatomic, readonly) NSString *initialViewController; 18 | @property (nonatomic, readonly) NSArray *scenes; 19 | @end 20 | -------------------------------------------------------------------------------- /Storytime/STTBoard.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTBoard.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTBoard.h" 10 | #import "CXMLDocument.h" 11 | #import "CXMLElement+Storytime.h" 12 | #import "CXMLElement.h" 13 | #import "STTScene.h" 14 | 15 | @interface STTBoard () 16 | @property (nonatomic) NSString *initialViewController; 17 | @property (nonatomic) NSMutableArray *scenes; 18 | @end 19 | 20 | @implementation STTBoard 21 | @synthesize scenes; 22 | 23 | - (instancetype)initWithURL:(NSURL *)url { 24 | self = [super init]; 25 | if (self) { 26 | self.origin = (CGPoint){ CGFLOAT_MAX, CGFLOAT_MAX }; 27 | 28 | NSError *error; 29 | CXMLDocument *storyboardXML = [[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:&error]; 30 | 31 | [self parseWithDocument:storyboardXML]; 32 | } 33 | return self; 34 | } 35 | 36 | - (instancetype)initWithXMLString:(NSString *)xmlString { 37 | self = [super init]; 38 | if (self) { 39 | self.origin = (CGPoint){ CGFLOAT_MAX, CGFLOAT_MAX }; 40 | 41 | NSError *error; 42 | CXMLDocument *storyboardXML = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:&error]; 43 | 44 | [self parseWithDocument:storyboardXML]; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)parseWithDocument:(CXMLDocument *)document { 50 | NSError *error; 51 | CXMLElement *rootElement = [document rootElement]; 52 | self.initialViewController = [rootElement stringAttributeForName:@"initialViewController"]; 53 | 54 | NSArray *sceneElements = [document nodesForXPath:@".//scenes/scene" error:&error]; 55 | NSMutableArray *scenes = [NSMutableArray arrayWithCapacity:sceneElements.count]; 56 | 57 | for (CXMLElement *scene in sceneElements) { 58 | [scenes addObject:[[STTScene alloc] initWithXMLElement:scene board:self]]; 59 | } 60 | 61 | self.scenes = scenes; 62 | } 63 | 64 | - (NSString *)htmlRepresentation { 65 | NSString *bodyStyle = [NSString stringWithFormat:@"position:absolute; top:%f; left:%f", self.origin.y * -1, self.origin.x * -1]; 66 | 67 | NSString *template = [NSString stringWithContentsOfURL:[[NSBundle bundleForClass:self.class] URLForResource:@"template" withExtension:@"html"] 68 | encoding:NSUTF8StringEncoding 69 | error:nil]; 70 | 71 | NSString *css1 = [NSString stringWithContentsOfURL:[[NSBundle bundleForClass:self.class] URLForResource:@"ratchet" withExtension:@"css"] 72 | encoding:NSUTF8StringEncoding 73 | error:nil]; 74 | 75 | NSString *css2 = [NSString stringWithContentsOfURL:[[NSBundle bundleForClass:self.class] URLForResource:@"ratchet-theme-ios.min" withExtension:@"css"] 76 | encoding:NSUTF8StringEncoding 77 | error:nil]; 78 | 79 | NSString *cssImports = [NSString stringWithFormat:@"%@ \n \n %@", css1, css2]; 80 | 81 | NSMutableString *scenesHTML = [NSMutableString string]; 82 | for (STTScene *scene in self.scenes) { 83 | [scenesHTML appendString:[scene htmlRepresentation]]; 84 | } 85 | 86 | template = [template stringByReplacingOccurrencesOfString:@"%INITIAL%" withString:self.initialViewController]; 87 | template = [template stringByReplacingOccurrencesOfString:@"%CSS_IMPORTS%" withString:cssImports]; 88 | template = [template stringByReplacingOccurrencesOfString:@"%BODY_STYLE%" withString:bodyStyle]; 89 | template = [template stringByReplacingOccurrencesOfString:@"%BODY%" withString:scenesHTML]; 90 | 91 | return template; 92 | } 93 | @end 94 | -------------------------------------------------------------------------------- /Storytime/STTCSS.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTCoreGraphicsCSS.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | FOUNDATION_EXTERN NSString *STTPointToCSS(CGPoint point); 13 | FOUNDATION_EXTERN NSString *STTSizeToCSS(CGSize size); 14 | FOUNDATION_EXTERN NSString *STTRectToCSS(CGRect rect); 15 | -------------------------------------------------------------------------------- /Storytime/STTCSS.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTCoreGraphicsCSS.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTCSS.h" 10 | 11 | NSString *STTPointToCSS(CGPoint point) { 12 | return [NSString stringWithFormat:@"top:%fpx; left:%fpx;", point.y, point.x]; 13 | } 14 | 15 | NSString *STTSizeToCSS(CGSize size) { 16 | return [NSString stringWithFormat:@"width:%fpx; height:%fpx;", size.width, size.height]; 17 | } 18 | 19 | NSString *STTRectToCSS(CGRect rect) { 20 | return [NSString stringWithFormat:@"%@ %@", STTPointToCSS(rect.origin), STTSizeToCSS(rect.size)]; 21 | } 22 | -------------------------------------------------------------------------------- /Storytime/STTElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTElement.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class STTBoard; 13 | 14 | @protocol STTElement 15 | - (instancetype)initWithXMLElement:(id)element board:(STTBoard *)board; 16 | - (NSString *)htmlRepresentation; 17 | @end 18 | -------------------------------------------------------------------------------- /Storytime/STTNavigationItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTNavigationItem.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTElement.h" 10 | #import 11 | 12 | @interface STTNavigationItem : NSObject 13 | @property (nonatomic) NSString *title; 14 | @property (nonatomic) NSArray *buttons; 15 | @end 16 | -------------------------------------------------------------------------------- /Storytime/STTNavigationItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTNavigationItem.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTNavigationItem.h" 10 | #import "CXMLElement+Storytime.h" 11 | #import "STTBarButtonItem.h" 12 | 13 | @implementation STTNavigationItem 14 | 15 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 16 | self = [super init]; 17 | if (self) { 18 | self.title = [element stringAttributeForName:@"title"] ?: @""; 19 | NSArray *buttonElements = [element elementsForName:@"barButtonItem"]; 20 | 21 | NSMutableArray *buttons = [NSMutableArray arrayWithCapacity:[buttonElements count]]; 22 | for (CXMLElement *buttonElement in buttonElements) { 23 | if ([buttonElement isKindOfClass:[CXMLElement class]]) { 24 | [buttons addObject:[[STTBarButtonItem alloc] initWithXMLElement:buttonElement board:board]]; 25 | } 26 | } 27 | 28 | self.buttons = buttons; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (NSString *)htmlRepresentation { 35 | NSMutableString *html = [NSMutableString string]; 36 | 37 | [html appendString:@"
"]; 38 | 39 | for (STTBarButtonItem *button in self.buttons) { 40 | [html appendString:[button htmlRepresentation]]; 41 | } 42 | 43 | [html appendFormat:@"

%@

", self.title]; 44 | [html appendString:@"
"]; 45 | 46 | return html; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Storytime/STTScene.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTScene.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTElement.h" 10 | #import 11 | 12 | @class STTBoard; 13 | 14 | @interface STTScene : NSObject 15 | @property (nonatomic, assign) CGPoint origin; 16 | @end 17 | -------------------------------------------------------------------------------- /Storytime/STTScene.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTScene.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTScene.h" 10 | #import "CXMLElement+Storytime.h" 11 | #import "STTBoard.h" 12 | #import "STTCSS.h" 13 | #import "STTViewController.h" 14 | 15 | @interface STTScene () 16 | @property (nonatomic) NSMutableArray *viewControllers; 17 | @end 18 | 19 | @implementation STTScene 20 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 21 | self = [super init]; 22 | if (self) { 23 | CGPoint point = [[element elementForName:@"point"] pointValue]; 24 | self.origin = point; 25 | 26 | // Storyboards can sometimes contain scenes with minus coordinates (e.g. {-165, -234}) 27 | // It's not an issue for IB, since it always centers the canvas. In our HTML/CSS combo 28 | // scenes were being placed outside of the viewport, so by keeping track of the min. origin point 29 | // we can later apply css to translate the whole thing so it's properly shown. 30 | board.origin = CGPointMake(MIN(point.x, board.origin.x), MIN(point.y, board.origin.y)); 31 | 32 | NSError *error; 33 | NSArray *viewControllerElements = [element nodesForXPath:@"objects/viewController | objects/tableViewController | objects/navigationController" error:&error]; 34 | NSMutableArray *viewControllers = [NSMutableArray arrayWithCapacity:viewControllerElements.count]; 35 | 36 | for (CXMLElement *vc in viewControllerElements) { 37 | [viewControllers addObject:[[STTViewController alloc] initWithXMLElement:vc board:board]]; 38 | } 39 | 40 | self.viewControllers = viewControllers; 41 | } 42 | return self; 43 | } 44 | 45 | - (NSString *)htmlRepresentation { 46 | NSMutableString *html = [NSMutableString string]; 47 | [html appendFormat:@"
", STTPointToCSS(self.origin)]; 48 | 49 | for (STTViewController *vc in self.viewControllers) { 50 | [html appendString:[vc htmlRepresentation]]; 51 | } 52 | 53 | [html appendString:@"
"]; 54 | 55 | return html; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Storytime/STTTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTTableView.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTView.h" 10 | 11 | @interface STTTableView : STTView 12 | @property (nonatomic) NSMutableArray *sections; 13 | @end 14 | -------------------------------------------------------------------------------- /Storytime/STTTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTTableView.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTTableView.h" 10 | #import "CXMLElement+Storytime.h" 11 | #import "STTCSS.h" 12 | #import "STTView.h" 13 | 14 | @interface STTTableViewCell : NSObject 15 | @property (nonatomic) STTView *contentView; 16 | @property (nonatomic, assign) CGRect rect; 17 | @end 18 | 19 | @implementation STTTableViewCell 20 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 21 | self = [super init]; 22 | if (self) { 23 | self.rect = [[element elementForName:@"rect"] rectValue]; 24 | self.contentView = [STTView viewWithXMLElement:[element elementForName:@"tableViewCellContentView"] board:board]; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | - (NSString *)htmlRepresentation { 31 | NSMutableString *html = [NSMutableString string]; 32 | 33 | [html appendFormat:@"
  • ", STTSizeToCSS(self.rect.size)]; 34 | [html appendString:[self.contentView htmlRepresentation]]; 35 | [html appendString:@"
  • "]; 36 | 37 | return html; 38 | } 39 | @end 40 | 41 | @interface STTTableViewSection : NSObject 42 | @property (nonatomic) NSString *headerTitle; 43 | @property (nonatomic) NSString *footerTitle; 44 | @property (nonatomic) NSMutableArray *cells; 45 | @end 46 | 47 | @implementation STTTableViewSection 48 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 49 | self = [super init]; 50 | if (self) { 51 | self.headerTitle = [element stringAttributeForName:@"headerTitle"]; 52 | self.footerTitle = [element stringAttributeForName:@"footerTitle"]; 53 | 54 | NSMutableArray *cells = [NSMutableArray arrayWithCapacity:[[[element elementForName:@"cells"] children] count]]; 55 | for (CXMLElement *cellElement in [[element elementForName:@"cells"] children]) { 56 | if ([cellElement isKindOfClass:[CXMLElement class]]) { 57 | [cells addObject:[[STTTableViewCell alloc] initWithXMLElement:cellElement board:board]]; 58 | } 59 | } 60 | 61 | self.cells = cells; 62 | } 63 | 64 | return self; 65 | } 66 | 67 | - (NSString *)htmlRepresentation { 68 | NSMutableString *html = [NSMutableString string]; 69 | if (self.headerTitle) { 70 | [html appendFormat:@"
  • %@
  • ", self.headerTitle]; 71 | } 72 | 73 | for (STTTableViewCell *cell in self.cells) { 74 | [html appendString:[cell htmlRepresentation]]; 75 | } 76 | 77 | if (self.footerTitle) { 78 | [html appendFormat:@"", self.footerTitle]; 79 | } 80 | 81 | return html; 82 | } 83 | @end 84 | 85 | @implementation STTTableView 86 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 87 | self = [super initWithXMLElement:element board:board]; 88 | if (self) { 89 | NSArray *sectionElements = [[element elementForName:@"sections"] elementsForName:@"tableViewSection"]; 90 | NSMutableArray *sections = [NSMutableArray arrayWithCapacity:[sectionElements count]]; 91 | for (CXMLElement *sectionElement in sectionElements) { 92 | [sections addObject:[[STTTableViewSection alloc] initWithXMLElement:sectionElement board:board]]; 93 | } 94 | 95 | self.sections = sections; 96 | } 97 | 98 | return self; 99 | } 100 | 101 | - (NSString *)htmlRepresentation { 102 | NSMutableString *html = [NSMutableString string]; 103 | [html appendString:@"
      "]; 104 | 105 | for (STTTableViewSection *section in self.sections) { 106 | [html appendString:[section htmlRepresentation]]; 107 | } 108 | 109 | [html appendString:@"
    "]; 110 | return html; 111 | } 112 | @end 113 | -------------------------------------------------------------------------------- /Storytime/STTView.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTView.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTElement.h" 10 | #import 11 | 12 | @interface STTView : NSObject 13 | + (STTView *)viewWithXMLElement:(id)element board:(STTBoard *)board; 14 | @property (nonatomic, assign) CGRect rect; 15 | @property (nonatomic) NSArray *subviews; 16 | @property (nonatomic) NSString *typeName; 17 | @end 18 | -------------------------------------------------------------------------------- /Storytime/STTView.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTView.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTView.h" 10 | #import "CXMLElement+Storytime.h" 11 | #import "STTCSS.h" 12 | #import "STTTableView.h" 13 | 14 | @interface STTPlaceholderView : STTView 15 | @end 16 | 17 | @implementation STTPlaceholderView 18 | - (NSString *)htmlRepresentation { 19 | return [NSString stringWithFormat: 20 | @"
    " 21 | @"
    %@
    " 22 | @"
    ", 23 | STTRectToCSS(self.rect), STTSizeToCSS(self.rect.size), self.rect.size.height, self.typeName]; 24 | } 25 | @end 26 | 27 | @interface STTLabelView : STTView 28 | @property (nonatomic) NSString *text; 29 | @property (nonatomic) NSString *fontName; 30 | @property (nonatomic, assign) CGFloat fontSize; 31 | @end 32 | 33 | @implementation STTLabelView 34 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 35 | self = [super initWithXMLElement:element board:board]; 36 | if (self) { 37 | self.text = [element stringAttributeForName:@"text"]; 38 | self.fontSize = [[[element elementForName:@"fontDescription"] numberAttributeForName:@"pointSize"] floatValue]; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (NSString *)htmlRepresentation { 45 | return [NSString stringWithFormat:@"
    %@
    ", STTRectToCSS(self.rect), self.fontSize, self.rect.size.height, self.text]; 46 | } 47 | @end 48 | 49 | @interface STTButtonView : STTView 50 | @property (nonatomic) NSString *title; 51 | @end 52 | 53 | @implementation STTButtonView 54 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 55 | self = [super initWithXMLElement:element board:board]; 56 | if (self) { 57 | self.title = [[element elementForName:@"state"] stringAttributeForName:@"title"]; 58 | } 59 | 60 | return self; 61 | } 62 | 63 | - (NSString *)htmlRepresentation { 64 | return [NSString stringWithFormat:@"", STTRectToCSS(self.rect), self.title]; 65 | } 66 | @end 67 | 68 | @interface STTStepperView : STTView 69 | @end 70 | 71 | @implementation STTStepperView 72 | - (NSString *)htmlRepresentation { 73 | return [NSString stringWithFormat:@"
    " 74 | @"-" 75 | @"+" 76 | @"
    ", 77 | STTRectToCSS(self.rect)]; 78 | } 79 | @end 80 | 81 | @interface STTSegmentedControlView : STTView 82 | @property (nonatomic) NSArray *segments; 83 | @property (nonatomic) NSUInteger selectedSegmentIndex; 84 | @end 85 | 86 | @implementation STTSegmentedControlView 87 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 88 | self = [super initWithXMLElement:element board:board]; 89 | if (self) { 90 | self.selectedSegmentIndex = [[element numberAttributeForName:@"selectedSegmentIndex"] integerValue]; 91 | 92 | NSMutableArray *segments = [NSMutableArray arrayWithCapacity:[element elementForName:@"segments"].children.count]; 93 | 94 | for (CXMLElement *segmentElement in [element elementForName:@"segments"].children) { 95 | if ([segmentElement isKindOfClass:[CXMLElement class]]) { 96 | [segments addObject:[segmentElement stringAttributeForName:@"title"]]; 97 | } 98 | } 99 | 100 | self.segments = segments; 101 | } 102 | 103 | return self; 104 | } 105 | 106 | - (NSString *)htmlRepresentation { 107 | NSMutableString *html = [NSMutableString string]; 108 | [html appendFormat:@"
    ", STTRectToCSS(self.rect)]; 109 | 110 | for (NSString *segment in self.segments) { 111 | [html appendFormat:@"%@", [self.segments indexOfObject:segment] == self.selectedSegmentIndex ? @"active" : @"", segment]; 112 | } 113 | [html appendString:@"
    "]; 114 | 115 | return html; 116 | } 117 | @end 118 | 119 | @interface STTSwitchView : STTView 120 | @end 121 | 122 | @implementation STTSwitchView 123 | - (NSString *)htmlRepresentation { 124 | return [NSString stringWithFormat:@"
    " 125 | @"
    " 126 | @"
    " 127 | @"
    " 128 | @"
    ", 129 | STTRectToCSS(self.rect)]; 130 | } 131 | @end 132 | 133 | @implementation STTView 134 | + (STTView *)viewWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 135 | if ([element.name isEqualToString:@"view"] || [element.name isEqualToString:@"tableViewCellContentView"]) { 136 | return [[STTView alloc] initWithXMLElement:element board:board]; 137 | } else if ([element.name isEqualToString:@"tableView"]) { 138 | return [[STTTableView alloc] initWithXMLElement:element board:board]; 139 | } else if ([element.name isEqualToString:@"label"]) { 140 | return [[STTLabelView alloc] initWithXMLElement:element board:board]; 141 | } else if ([element.name isEqualToString:@"button"]) { 142 | return [[STTButtonView alloc] initWithXMLElement:element board:board]; 143 | } else if ([element.name isEqualToString:@"imageView1"]) { 144 | return [[STTPlaceholderView alloc] initWithXMLElement:element board:board]; 145 | } else if ([element.name isEqualToString:@"stepper"]) { 146 | return [[STTStepperView alloc] initWithXMLElement:element board:board]; 147 | } else if ([element.name isEqualToString:@"segmentedControl"]) { 148 | return [[STTSegmentedControlView alloc] initWithXMLElement:element board:board]; 149 | } else if ([element.name isEqualToString:@"switch"]) { 150 | return [[STTSwitchView alloc] initWithXMLElement:element board:board]; 151 | } 152 | 153 | return [[STTPlaceholderView alloc] initWithXMLElement:element board:board]; 154 | } 155 | 156 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 157 | self = [super init]; 158 | if (self) { 159 | self.rect = [[element elementForName:@"rect"] rectValue]; 160 | self.typeName = element.name; 161 | 162 | NSMutableArray *subviews = [NSMutableArray arrayWithCapacity:[[[element elementForName:@"subviews"] children] count]]; 163 | for (CXMLElement *subviewElement in [[element elementForName:@"subviews"] children]) { 164 | if ([subviewElement isKindOfClass:[CXMLElement class]]) { 165 | [subviews addObject:[STTView viewWithXMLElement:subviewElement board:board]]; 166 | } 167 | } 168 | 169 | self.subviews = subviews; 170 | } 171 | 172 | return self; 173 | } 174 | 175 | - (NSString *)htmlRepresentation { 176 | NSMutableString *html = [NSMutableString string]; 177 | [html appendFormat:@"
    ", STTRectToCSS(self.rect)]; 178 | 179 | for (STTView *view in self.subviews) { 180 | [html appendString:[view htmlRepresentation]]; 181 | } 182 | 183 | [html appendString:@"
    "]; 184 | 185 | return html; 186 | } 187 | @end 188 | -------------------------------------------------------------------------------- /Storytime/STTViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // STTViewController.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTElement.h" 10 | #import 11 | 12 | @class STTBoard, STTNavigationItem, STTView; 13 | 14 | @interface STTViewController : NSObject 15 | @property (nonatomic) NSString *typeName; 16 | @property (nonatomic) NSString *identifier; 17 | @property (nonatomic) NSString *className; 18 | @property (nonatomic, assign) CGRect rect; 19 | @property (nonatomic) STTNavigationItem *navigationItem; 20 | @property (nonatomic) STTView *rootView; 21 | @end 22 | -------------------------------------------------------------------------------- /Storytime/STTViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // STTViewController.m 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTViewController.h" 10 | #import "CXMLElement+Storytime.h" 11 | #import "STTBoard.h" 12 | #import "STTCSS.h" 13 | #import "STTNavigationItem.h" 14 | #import "STTScene.h" 15 | #import "STTView.h" 16 | 17 | @interface STTViewController () 18 | 19 | @end 20 | 21 | @implementation STTViewController 22 | 23 | - (instancetype)initWithXMLElement:(CXMLElement *)element board:(STTBoard *)board { 24 | self = [super init]; 25 | if (self) { 26 | self.identifier = [element stringAttributeForName:@"id"]; 27 | self.className = [element stringAttributeForName:@"customClass"]; 28 | self.typeName = element.name; 29 | 30 | CXMLElement *viewElement = ([element elementForName:@"view"] ?: [element elementForName:@"tableView"]); 31 | self.rect = [[viewElement elementForName:@"rect"] rectValue]; 32 | 33 | CXMLElement *navItemElement = [element elementForName:@"navigationItem"]; 34 | 35 | if (navItemElement) { 36 | self.navigationItem = [[STTNavigationItem alloc] initWithXMLElement:navItemElement board:board]; 37 | } 38 | 39 | self.rootView = [STTView viewWithXMLElement:viewElement board:board]; 40 | } 41 | return self; 42 | } 43 | 44 | - (NSString *)htmlRepresentation { 45 | NSMutableString *html = [NSMutableString string]; 46 | [html appendFormat:@"
    ", self.className, self.identifier, self.typeName, STTSizeToCSS(self.rect.size)]; 47 | 48 | if (self.navigationItem) { 49 | [html appendString:[self.navigationItem htmlRepresentation]]; 50 | } 51 | 52 | if (self.rootView) { 53 | [html appendString:[self.rootView htmlRepresentation]]; 54 | } 55 | 56 | [html appendString:@"
    "]; 57 | 58 | return html; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Storytime/Storytime.h: -------------------------------------------------------------------------------- 1 | // 2 | // Storytime.h 3 | // Storytime 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTBoard.h" 10 | #import 11 | 12 | //! Project version number for Storytime. 13 | FOUNDATION_EXPORT double StorytimeVersionNumber; 14 | 15 | //! Project version string for Storytime. 16 | FOUNDATION_EXPORT const unsigned char StorytimeVersionString[]; 17 | 18 | // In this header, you should import all the public headers of your framework using statements like #import 19 | -------------------------------------------------------------------------------- /Storytime/TouchXML/CXMLDocument_CreationExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLDocument_CreationExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 11/11/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLDocument.h" 33 | 34 | @interface CXMLDocument (CXMLDocument_CreationExtensions) 35 | 36 | //- (void)setVersion:(NSString *)version; //primitive 37 | //- (void)setStandalone:(BOOL)standalone; //primitive 38 | //- (void)setDocumentContentKind:(CXMLDocumentContentKind)kind; //primitive 39 | //- (void)setMIMEType:(NSString *)MIMEType; //primitive 40 | //- (void)setDTD:(CXMLDTD *)documentTypeDeclaration; //primitive 41 | //- (void)setRootElement:(CXMLNode *)root; 42 | - (void)insertChild:(CXMLNode *)child atIndex:(NSUInteger)index; 43 | //- (void)insertChildren:(NSArray *)children atIndex:(NSUInteger)index; 44 | //- (void)removeChildAtIndex:(NSUInteger)index; //primitive 45 | //- (void)setChildren:(NSArray *)children; //primitive 46 | - (void)addChild:(CXMLNode *)child; 47 | //- (void)replaceChildAtIndex:(NSUInteger)index withNode:(CXMLNode *)node; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Storytime/TouchXML/CXMLDocument_CreationExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLDocument_CreationExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 11/11/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLDocument_CreationExtensions.h" 33 | 34 | #import "CXMLDocument_PrivateExtensions.h" 35 | #import "CXMLElement.h" 36 | #import "CXMLNode_PrivateExtensions.h" 37 | 38 | @implementation CXMLDocument (CXMLDocument_CreationExtensions) 39 | 40 | - (void)insertChild:(CXMLNode *)child atIndex:(NSUInteger)index { 41 | [self.nodePool addObject:child]; 42 | 43 | CXMLNode *theCurrentNode = [self.children objectAtIndex:index]; 44 | xmlAddPrevSibling(theCurrentNode->_node, child->_node); 45 | } 46 | 47 | - (void)addChild:(CXMLNode *)child { 48 | [self.nodePool addObject:child]; 49 | 50 | xmlAddChild(self->_node, child->_node); 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Storytime/TouchXML/CXMLNode_CreationExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode_CreationExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/01/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode.h" 33 | 34 | @class CXMLElement; 35 | 36 | @interface CXMLNode (CXMLNode_CreationExtensions) 37 | 38 | //- (id)initWithKind:(NSXMLNodeKind)kind; 39 | //- (id)initWithKind:(NSXMLNodeKind)kind options:(NSUInteger)options; //primitive 40 | + (id)document; 41 | + (id)documentWithRootElement:(CXMLElement *)element; 42 | + (id)elementWithName:(NSString *)name; 43 | + (id)elementWithName:(NSString *)name URI:(NSString *)URI; 44 | + (id)elementWithName:(NSString *)name stringValue:(NSString *)string; 45 | //+ (id)elementWithName:(NSString *)name children:(NSArray *)children attributes:(NSArray *)attributes; 46 | //+ (id)attributeWithName:(NSString *)name stringValue:(NSString *)stringValue; 47 | //+ (id)attributeWithName:(NSString *)name URI:(NSString *)URI stringValue:(NSString *)stringValue; 48 | + (id)namespaceWithName:(NSString *)name stringValue:(NSString *)stringValue; 49 | + (id)processingInstructionWithName:(NSString *)name stringValue:(NSString *)stringValue; 50 | //+ (id)commentWithStringValue:(NSString *)stringValue; 51 | //+ (id)textWithStringValue:(NSString *)stringValue; 52 | //+ (id)DTDNodeWithXMLString:(NSString *)string; 53 | 54 | - (void)setStringValue:(NSString *)inStringValue; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Storytime/TouchXML/CXMLNode_CreationExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode_CreationExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/01/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode_CreationExtensions.h" 33 | 34 | #import "CXMLDocument.h" 35 | #import "CXMLDocument_PrivateExtensions.h" 36 | #import "CXMLElement.h" 37 | #import "CXMLNamespaceNode.h" 38 | #import "CXMLNode_PrivateExtensions.h" 39 | 40 | @implementation CXMLNode (CXMLNode_CreationExtensions) 41 | 42 | + (id)document; 43 | { 44 | xmlDocPtr theDocumentNode = xmlNewDoc((const xmlChar *)"1.0"); 45 | NSAssert(theDocumentNode != NULL, @"xmlNewDoc failed"); 46 | CXMLDocument *theDocument = [[CXMLDocument alloc] initWithLibXMLNode:(xmlNodePtr)theDocumentNode freeOnDealloc:NO]; 47 | return (theDocument); 48 | } 49 | 50 | + (id)documentWithRootElement:(CXMLElement *)element; 51 | { 52 | xmlDocPtr theDocumentNode = xmlNewDoc((const xmlChar *)"1.0"); 53 | NSAssert(theDocumentNode != NULL, @"xmlNewDoc failed"); 54 | xmlDocSetRootElement(theDocumentNode, element.node); 55 | CXMLDocument *theDocument = [[CXMLDocument alloc] initWithLibXMLNode:(xmlNodePtr)theDocumentNode freeOnDealloc:NO]; 56 | [theDocument.nodePool addObject:element]; 57 | return (theDocument); 58 | } 59 | 60 | + (id)elementWithName:(NSString *)name { 61 | xmlNodePtr theElementNode = xmlNewNode(NULL, (const xmlChar *)[name UTF8String]); 62 | CXMLElement *theElement = [[CXMLElement alloc] initWithLibXMLNode:(xmlNodePtr)theElementNode freeOnDealloc:NO]; 63 | return (theElement); 64 | } 65 | 66 | + (id)elementWithName:(NSString *)name URI:(NSString *)URI { 67 | xmlNodePtr theElementNode = xmlNewNode(NULL, (const xmlChar *)[name UTF8String]); 68 | xmlNsPtr theNSNode = xmlNewNs(theElementNode, (const xmlChar *)[URI UTF8String], NULL); 69 | theElementNode->ns = theNSNode; 70 | 71 | CXMLElement *theElement = [[CXMLElement alloc] initWithLibXMLNode:(xmlNodePtr)theElementNode freeOnDealloc:NO]; 72 | return (theElement); 73 | } 74 | 75 | + (id)elementWithName:(NSString *)name stringValue:(NSString *)string { 76 | xmlNodePtr theElementNode = xmlNewNode(NULL, (const xmlChar *)[name UTF8String]); 77 | CXMLElement *theElement = [[CXMLElement alloc] initWithLibXMLNode:(xmlNodePtr)theElementNode freeOnDealloc:NO]; 78 | theElement.stringValue = string; 79 | return (theElement); 80 | } 81 | 82 | + (id)namespaceWithName:(NSString *)name stringValue:(NSString *)stringValue { 83 | return [[CXMLNamespaceNode alloc] initWithPrefix:name URI:stringValue parentElement:nil]; 84 | } 85 | 86 | + (id)processingInstructionWithName:(NSString *)name stringValue:(NSString *)stringValue; 87 | { 88 | xmlNodePtr theNode = xmlNewPI((const xmlChar *)[name UTF8String], (const xmlChar *)[stringValue UTF8String]); 89 | NSAssert(theNode != NULL, @"xmlNewPI failed"); 90 | CXMLNode *theNodeObject = [[CXMLNode alloc] initWithLibXMLNode:theNode freeOnDealloc:NO]; 91 | return (theNodeObject); 92 | } 93 | 94 | - (void)setStringValue:(NSString *)inStringValue { 95 | NSAssert(_node->type == XML_TEXT_NODE, @"CNode setStringValue only implemented for text nodes"); 96 | xmlNodeSetContent(_node, (const xmlChar *)[inStringValue UTF8String]); 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Storytime/ratchet-theme-ios.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * ===================================================== 3 | * Ratchet v2.0.2 (http://goratchet.com) 4 | * Copyright 2014 Connor Sears 5 | * Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE) 6 | * 7 | * v2.0.2 designed by @connors. 8 | * ===================================================== 9 | */a{color:#007aff}a:active{color:#0062cc}.content{background-color:#efeff4}.h5,.h6,h5,h6,p{color:#8f8f94}.h5,.h6,h5,h6{font-weight:400;text-transform:uppercase}.btn{color:#929292;background-color:rgba(247,247,247,.98);border:1px solid #929292;-webkit-transition:all;-moz-transition:all;transition:all;-webkit-transition-timing-function:linear;-moz-transition-timing-function:linear;transition-timing-function:linear;-webkit-transition-duration:.2s;-moz-transition-duration:.2s;transition-duration:.2s}.btn.active,.btn:active{color:#fff;background-color:#929292}.btn-primary{color:#fff;background-color:#007aff;border:1px solid #007aff}.btn-primary.active,.btn-primary:active{background-color:#0062cc;border:1px solid #0062cc}.btn-positive{color:#fff;background-color:#4cd964;border:1px solid #4cd964}.btn-positive.active,.btn-positive:active{background-color:#2ac845;border:1px solid #2ac845}.btn-negative{color:#fff;background-color:#dd524d;border:1px solid #dd524d}.btn-negative.active,.btn-negative:active{background-color:#cf2d28;border:1px solid #cf2d28}.btn-outlined{background-color:transparent}.btn-outlined.btn-primary{color:#007aff}.btn-outlined.btn-positive{color:#4cd964}.btn-outlined.btn-negative{color:#dd524d}.btn-outlined.btn-negative:active,.btn-outlined.btn-positive:active,.btn-outlined.btn-primary:active{color:#fff}.btn-link{color:#007aff;background-color:transparent;border:none}.btn-link.active,.btn-link:active{color:#0062cc;background-color:transparent}.btn .badge{background-color:rgba(0,0,0,.15)}.btn .badge.badge-inverted{background-color:transparent}.btn:active .badge{color:#fff}.bar{background-color:rgba(247,247,247,.98);border-bottom:0;-webkit-box-shadow:0 0 1px rgba(0,0,0,.85);box-shadow:0 0 1px rgba(0,0,0,.85)}.bar.bar-header-secondary{top:44px}.bar.bar-footer-secondary{bottom:44px}.bar.bar-footer-secondary-tab{bottom:50px}.bar-tab,.bar.bar-footer,.bar.bar-footer-secondary,.bar.bar-footer-secondary-tab{border-top:0}.tab-item{color:#929292}.bar-nav .btn-link,.tab-item.active,.tab-item:active{color:#007aff}.bar-nav .btn-link:active{color:#007aff;opacity:.6}.badge.badge-inverted{color:#929292;background-color:transparent}.badge-primary{color:#fff;background-color:#007aff}.badge-primary.badge-inverted{color:#007aff;background-color:transparent}.badge-positive{color:#fff;background-color:#4cd964}.badge-positive.badge-inverted{color:#4cd964;background-color:transparent}.badge-negative{color:#fff;background-color:#dd524d}.badge-negative.badge-inverted{color:#dd524d;background-color:transparent}.card .table-view,.card .table-view-cell:last-child{background-image:none}.table-view{background-image:url("data:image/svg+xml;utf8,"),url("data:image/svg+xml;utf8,");background-repeat:no-repeat;background-position:0 100%,0 0;border-top:0;border-bottom:0}.table-view .table-view-cell{background-image:url("data:image/svg+xml;utf8,");background-repeat:no-repeat;background-position:15px 100%;border-bottom:0}.table-view .table-view-cell:last-child{background-image:none}.table-view .table-view-cell>a:not(.btn):active{color:inherit}.table-view .table-view-divider{background-image:url("data:image/svg+xml;utf8,"),url("data:image/svg+xml;utf8,");background-repeat:no-repeat;background-position:0 100%,0 0;border-top:0;border-bottom:0}.input-group,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{height:40px;padding:10px 15px;border:1px solid rgba(0,0,0,.2)}input[type=search]{height:34px;text-align:center;background-color:rgba(0,0,0,.1);border:0;border-radius:6px}input[type=search]:focus{text-align:left}.input-group,select,textarea{height:auto}.input-group{padding:0;background-image:url("data:image/svg+xml;utf8,"),url("data:image/svg+xml;utf8,");background-repeat:no-repeat;background-position:0 100%,0 0;border:0}.input-group input{background-image:url("data:image/svg+xml;utf8,");background-repeat:no-repeat;background-position:15px 100%;border:0}.input-group input:last-child{background-image:none}.input-row{background-image:url("data:image/svg+xml;utf8,");background-repeat:no-repeat;background-position:15px 100%;border-bottom:0}.input-row label+input,.input-row:last-child{background-image:none}.segmented-control{background-color:transparent;border:1px solid #929292}.segmented-control .control-item{color:#929292;border-color:#929292;-webkit-transition:background-color .1s linear;-moz-transition:background-color .1s linear;transition:background-color .1s linear}.segmented-control .control-item:active{background-color:#ebebeb}.segmented-control .control-item.active{color:#fff;background-color:#929292}.segmented-control-primary{border:1px solid #007aff}.segmented-control-primary .control-item{color:#007aff;border-color:inherit}.segmented-control-primary .control-item:active{background-color:#b3d7ff}.segmented-control-primary .control-item.active{color:#fff;background-color:#007aff}.segmented-control-positive{border:1px solid #4cd964}.segmented-control-positive .control-item{color:#4cd964;border-color:inherit}.segmented-control-positive .control-item:active{background-color:#dff8e3}.segmented-control-positive .control-item.active{color:#fff;background-color:#4cd964}.segmented-control-negative{border:1px solid #dd524d}.segmented-control-negative .control-item{color:#dd524d;border-color:inherit}.segmented-control-negative .control-item:active{background-color:#fae4e3}.segmented-control-negative .control-item.active{color:#fff;background-color:#dd524d}.popover{border-radius:12px;-webkit-transition:-webkit-transform .2s ease-in-out,opacity .2s ease-in-out;-moz-transition:-webkit-transform .2s ease-in-out,opacity .2s ease-in-out;transition:-webkit-transform .2s ease-in-out,opacity .2s ease-in-out}.popover:before{border-bottom:15px solid rgba(247,247,247,.98)}.popover .bar{-webkit-box-shadow:none;box-shadow:none}.popover .bar-nav{border-bottom:1px solid rgba(0,0,0,.15)}.popover .table-view{background-image:none;border-radius:12px}.modal,.modal.active{-webkit-transition-timing-function:cubic-bezier(.1,.5,.1,1);-moz-transition-timing-function:cubic-bezier(.1,.5,.1,1);transition-timing-function:cubic-bezier(.1,.5,.1,1)}.toggle{width:47px;border:2px solid #e6e6e6;-webkit-box-shadow:inset 0 0 0 0 #e1e1e1;box-shadow:inset 0 0 0 0 #e1e1e1;-webkit-transition-duration:.2s;-moz-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:box-shadow,border;-moz-transition-property:box-shadow,border;transition-property:box-shadow,border}.toggle .toggle-handle{border:1px solid rgba(0,0,0,.2);-webkit-box-shadow:0 3px 3px rgba(0,0,0,.08);box-shadow:0 3px 3px rgba(0,0,0,.08);-webkit-transition-property:-webkit-transform,border,width;-moz-transition-property:-moz-transform,border,width;transition-property:transform,border,width}.toggle:before{display:none}.toggle.active{background-color:transparent;border:2px solid #4cd964;-webkit-box-shadow:inset 0 0 0 13px #4cd964;box-shadow:inset 0 0 0 13px #4cd964}.toggle.active .toggle-handle{-webkit-transform:translate3d(17px,0,0);-ms-transform:translate3d(17px,0,0);transform:translate3d(17px,0,0);border-color:#4cd964}.content.fade{-webkit-transition:opacity .2s ease-in-out;-moz-transition:opacity .2s ease-in-out;transition:opacity .2s ease-in-out}.content.sliding{-webkit-transition-timing-function:cubic-bezier(.1,.5,.1,1);-moz-transition-timing-function:cubic-bezier(.1,.5,.1,1);transition-timing-function:cubic-bezier(.1,.5,.1,1)}.content.sliding.right:not([class*=sliding-in]),.content.sliding.sliding-in{-webkit-animation-name:fadeOverlay;-moz-animation-name:fadeOverlay;animation-name:fadeOverlay;-webkit-animation-duration:.4s;-moz-animation-duration:.4s;animation-duration:.4s}.content.sliding.right:not([class*=sliding-in]){-webkit-animation-direction:reverse;-moz-animation-direction:reverse;animation-direction:reverse}.content.sliding.left{-webkit-transform:translate3d(-20%,0,0);-ms-transform:translate3d(-20%,0,0);transform:translate3d(-20%,0,0)}@-webkit-keyframes fadeOverlay{from{-webkit-box-shadow:0 0 10px transparent,-320px 0 0 transparent;box-shadow:0 0 10px transparent,-320px 0 0 transparent}to{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3),-320px 0 0 rgba(0,0,0,.1);box-shadow:0 0 10px rgba(0,0,0,.3),-320px 0 0 rgba(0,0,0,.1)}} -------------------------------------------------------------------------------- /Storytime/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Storyboard 4 | 80 | 81 | 82 | %BODY% 83 | 84 | 85 | -------------------------------------------------------------------------------- /StorytimeTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /StorytimeTests/StorytimeTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // StorytimeTests.m 3 | // StorytimeTests 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import "STTBoard.h" 10 | #import 11 | 12 | @interface StorytimeTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation StorytimeTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | NSURL *storyURL = [NSURL fileURLWithPath:@"/Users/hezi/Desktop/storyboard.storyboard"]; //@"/Users/hezi/TalkTheTime/TalkTheTime/Base.lproj/Main.storyboard" 30 | STTBoard *board = [[STTBoard alloc] initWithURL:storyURL]; 31 | 32 | [[board htmlRepresentation] writeToURL:[NSURL URLWithString:@"file:///Users/hezi/Desktop/untitles.html"] atomically:YES encoding:NSUTF8StringEncoding error:nil]; 33 | } 34 | 35 | - (void)testPerformanceExample { 36 | // This is an example of a performance test case. 37 | [self measureBlock:^{ 38 | // Put the code you want to measure the time of here. 39 | }]; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /StorytimeiOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /StorytimeiOS/StorytimeiOS.h: -------------------------------------------------------------------------------- 1 | // 2 | // StorytimeiOS.h 3 | // StorytimeiOS 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | //! Project version number for StorytimeiOS. 13 | FOUNDATION_EXPORT double StorytimeiOSVersionNumber; 14 | 15 | //! Project version string for StorytimeiOS. 16 | FOUNDATION_EXPORT const unsigned char StorytimeiOSVersionString[]; 17 | 18 | // In this header, you should import all the public headers of your framework using statements like #import 19 | -------------------------------------------------------------------------------- /StorytimeiOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /StorytimeiOSTests/StorytimeiOSTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // StorytimeiOSTests.m 3 | // StorytimeiOSTests 4 | // 5 | // Created by Jorge Cohen on 3/25/18. 6 | // Copyright © 2018 Jorge Cohen. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StorytimeiOSTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation StorytimeiOSTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Vendor/TouchXML/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/ 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData -------------------------------------------------------------------------------- /Vendor/TouchXML/.travis.yml: -------------------------------------------------------------------------------- 1 | #before_script: cd 'Cocoa Examples' 2 | language: objective-c 3 | xcode_project: 'TouchXML.xcodeproj' 4 | xcode_scheme: "TouchXML_Mac" 5 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXHTMLDocument.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXHTMLDocument.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLDocument.h" 33 | 34 | @interface CXHTMLDocument : CXMLDocument { 35 | } 36 | 37 | - (id)initWithXHTMLData:(NSData *)inData encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError; 38 | - (id)initWithXHTMLString:(NSString *)inString options:(NSUInteger)inOptions error:(NSError **)outError; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXHTMLDocument.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXHTMLDocument.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | // This is an experiment to see if we can utilize the HTMLParser functionality 33 | // of libXML to serve as a XHTML parser, I question if this is a good idea or not 34 | // need to test some of the following 35 | // [-] How are xml namespaces handled 36 | // [-] Can we support DTD 37 | // [-] 38 | 39 | #import "CXHTMLDocument.h" 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #import "CXMLElement.h" 47 | #import "CXMLNode_PrivateExtensions.h" 48 | 49 | #if TOUCHXMLUSETIDY 50 | #import "CTidy.h" 51 | #endif /* TOUCHXMLUSETIDY */ 52 | 53 | @implementation CXHTMLDocument 54 | 55 | // Differs from initWithXMLString by using libXML's HTML parser, which automatically decodes XHTML/HTML entities found within the document 56 | // which eliminates the need to resanitize strings extracted from the document 57 | // libXML treats a htmlDocPtr the same as xmlDocPtr 58 | - (id)initWithXHTMLString:(NSString *)inString options:(NSUInteger)inOptions error:(NSError **)outError { 59 | #pragma unused(inOptions) 60 | if ((self = [super init]) != NULL) { 61 | NSError *theError = NULL; 62 | 63 | htmlDocPtr theDoc = htmlParseDoc(BAD_CAST[inString UTF8String], xmlGetCharEncodingName(XML_CHAR_ENCODING_UTF8)); 64 | if (theDoc != NULL) { 65 | // TODO: change code to not depend on XPATH, should be a task simple enough to do 66 | // alternatively see if we can prevent the HTML parser from adding implied tags 67 | 68 | xmlXPathContextPtr xpathContext = xmlXPathNewContext(theDoc); 69 | 70 | xmlXPathObjectPtr xpathObject = NULL; 71 | if (xpathContext) 72 | xpathObject = xmlXPathEvalExpression(BAD_CAST("/html/body"), xpathContext); 73 | 74 | xmlNodePtr bodyNode = NULL; 75 | if (xpathObject && xpathObject->nodesetval->nodeMax) 76 | bodyNode = xpathObject->nodesetval->nodeTab[0]; 77 | 78 | // TODO: Determine if this is sufficient to handle memory in libXML, is the old root removed / deleted, etc 79 | if (bodyNode) 80 | xmlDocSetRootElement(theDoc, bodyNode->children); 81 | 82 | _node = (xmlNodePtr)theDoc; 83 | NSAssert(_node->_private == NULL, @"TODO"); 84 | _node->_private = (__bridge void *)self; // Note. NOT retained (TODO think more about _private usage) 85 | 86 | if (xpathObject) 87 | xmlXPathFreeObject(xpathObject); 88 | 89 | if (xpathContext) 90 | xmlXPathFreeContext(xpathContext); 91 | } else { 92 | xmlErrorPtr theLastErrorPtr = xmlGetLastError(); 93 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 94 | theLastErrorPtr ? [NSString stringWithUTF8String:theLastErrorPtr->message] : @"unknown", NSLocalizedDescriptionKey, 95 | NULL]; 96 | 97 | theError = [NSError errorWithDomain:@"CXMLErrorDomain" code:1 userInfo:theUserInfo]; 98 | 99 | xmlResetLastError(); 100 | } 101 | 102 | if (outError) { 103 | *outError = theError; 104 | } 105 | 106 | if (theError != NULL) { 107 | self = NULL; 108 | } 109 | } 110 | return (self); 111 | } 112 | 113 | - (id)initWithXHTMLData:(NSData *)inData encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError { 114 | #pragma unused(inOptions) 115 | if ((self = [super init]) != NULL) { 116 | NSError *theError = NULL; 117 | 118 | if (theError == NULL) { 119 | xmlDocPtr theDoc = NULL; 120 | if (inData && inData.length > 0) { 121 | CFStringEncoding cfenc = CFStringConvertNSStringEncodingToEncoding(encoding); 122 | CFStringRef cfencstr = CFStringConvertEncodingToIANACharSetName(cfenc); 123 | const char *enc = CFStringGetCStringPtr(cfencstr, 0); 124 | theDoc = htmlReadMemory([inData bytes], (int)[inData length], NULL, enc, HTML_PARSE_NONET | HTML_PARSE_NOBLANKS | HTML_PARSE_NOWARNING); 125 | } 126 | 127 | if (theDoc != NULL) { 128 | _node = (xmlNodePtr)theDoc; 129 | _node->_private = (__bridge void *)self; // Note. NOT retained (TODO think more about _private usage) 130 | } else { 131 | theError = [NSError errorWithDomain:@"CXMLErrorDomain" code:-1 userInfo:NULL]; 132 | } 133 | } 134 | 135 | if (outError) { 136 | *outError = theError; 137 | } 138 | 139 | if (theError != NULL) { 140 | self = NULL; 141 | } 142 | } 143 | return (self); 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLDocument.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLDocument.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode.h" 33 | 34 | /* 35 | Tidy is disabled by default. In order to enable it correctly you need to: 36 | 1) set preprocessor macros TOUCHXMLUSETIDY=1 37 | 2) download and build libtidy into your app (you cannot link against system provided build, because you would use Apple private APIs) 38 | */ 39 | enum { 40 | CXMLDocumentTidyHTML = 1 << 9, // Based on NSXMLDocumentTidyHTML 41 | CXMLDocumentTidyXML = 1 << 10, // Based on NSXMLDocumentTidyXML 42 | }; 43 | 44 | @class CXMLElement; 45 | 46 | @interface CXMLDocument : CXMLNode { 47 | NSMutableSet *nodePool; 48 | } 49 | 50 | /* 51 | Please note that, if you use tidy to repair your HTML/XML source, your node 52 | graph may change. 53 | 54 | For example CTidy adds XHTML namespace to your HTML by default: 55 | 56 | An HTML source like this: 57 | 58 | 59 | My Title 60 | ... 61 | 62 | becomes: 63 | 65 | 66 | 67 | 69 | My Title 70 | ... 71 | 72 | This affects the way you will query this document with XPath, because you will 73 | need to pass namespace mappings dictionary and to add "xmlns" to your queries 74 | (e.g: "//xmlns:title" to reach "" element). 75 | */ 76 | - (id)initWithData:(NSData *)inData options:(NSUInteger)inOptions error:(NSError **)outError; 77 | - (id)initWithData:(NSData *)inData encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError; 78 | - (id)initWithXMLString:(NSString *)inString options:(NSUInteger)inOptions error:(NSError **)outError; 79 | - (id)initWithContentsOfURL:(NSURL *)inURL options:(NSUInteger)inOptions error:(NSError **)outError; 80 | - (id)initWithContentsOfURL:(NSURL *)inURL encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError; 81 | 82 | //- (NSString *)characterEncoding; 83 | //- (NSString *)version; 84 | //- (BOOL)isStandalone; 85 | //- (CXMLDocumentContentKind)documentContentKind; 86 | //- (NSString *)MIMEType; 87 | //- (CXMLDTD *)DTD; 88 | 89 | - (CXMLElement *)rootElement; 90 | 91 | - (NSData *)XMLData; 92 | - (NSData *)XMLDataWithOptions:(NSUInteger)options; 93 | 94 | //- (id)objectByApplyingXSLT:(NSData *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error; 95 | //- (id)objectByApplyingXSLTString:(NSString *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error; 96 | //- (id)objectByApplyingXSLTAtURL:(NSURL *)xsltURL arguments:(NSDictionary *)argument error:(NSError **)error; 97 | 98 | - (id)XMLStringWithOptions:(NSUInteger)options; 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLDocument.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLDocument.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLDocument.h" 33 | 34 | #include <libxml/parser.h> 35 | 36 | #import "CXMLElement.h" 37 | #import "CXMLNode_PrivateExtensions.h" 38 | 39 | #if TOUCHXMLUSETIDY 40 | #import "CTidy.h" 41 | #endif /* TOUCHXMLUSETIDY */ 42 | 43 | @implementation CXMLDocument 44 | 45 | - (id)initWithXMLString:(NSString *)inString options:(NSUInteger)inOptions error:(NSError **)outError { 46 | #if !TOUCHXMLUSETIDY 47 | #pragma unused(inOptions) 48 | #endif 49 | 50 | self = [super init]; 51 | if (self) { 52 | NSError *theError = NULL; 53 | 54 | #if TOUCHXMLUSETIDY 55 | const char *tidyEncodingCString = [[CTidy tidyEncodingFromStringEncoding:NSUTF8StringEncoding] UTF8String]; 56 | 57 | if (inOptions & CXMLDocumentTidyHTML) { 58 | CTidy *tidy = [[CTidy alloc] init]; 59 | inString = [tidy tidyString:inString inputFormat:TidyFormat_HTML outputFormat:TidyFormat_XHTML encoding:tidyEncodingCString diagnostics:NULL error:&theError]; 60 | } else if (inOptions & CXMLDocumentTidyXML) { 61 | CTidy *tidy = [[CTidy alloc] init]; 62 | inString = [tidy tidyString:inString inputFormat:TidyFormat_XML outputFormat:TidyFormat_XML encoding:tidyEncodingCString diagnostics:NULL error:&theError]; 63 | } 64 | #endif 65 | 66 | if (theError == NULL) { 67 | xmlDocPtr theDoc = xmlParseDoc((xmlChar *)[inString UTF8String]); 68 | if (theDoc != NULL) { 69 | _node = (xmlNodePtr)theDoc; 70 | NSAssert(_node->_private == NULL, @"TODO"); 71 | _node->_private = (__bridge void *)self; // Note. NOT retained (TODO think more about _private usage) 72 | } else { 73 | NSDictionary *theUserInfo = nil; 74 | 75 | xmlErrorPtr theLastErrorPtr = xmlGetLastError(); 76 | if (theLastErrorPtr) { 77 | theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 78 | [NSString stringWithUTF8String:theLastErrorPtr->message], NSLocalizedDescriptionKey, 79 | NULL]; 80 | } 81 | theError = [NSError errorWithDomain:@"CXMLErrorDomain" code:1 userInfo:theUserInfo]; 82 | 83 | xmlResetLastError(); 84 | } 85 | 86 | if (outError) { 87 | *outError = theError; 88 | } 89 | 90 | if (theError != NULL) { 91 | self = NULL; 92 | } 93 | } 94 | } 95 | 96 | return (self); 97 | } 98 | 99 | - (id)initWithData:(NSData *)inData options:(NSUInteger)inOptions error:(NSError **)outError { 100 | return [self initWithData:inData encoding:NSUTF8StringEncoding options:inOptions error:outError]; 101 | } 102 | 103 | - (id)initWithData:(NSData *)inData encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError { 104 | #if !TOUCHXMLUSETIDY 105 | #pragma unused(inOptions) 106 | #endif 107 | 108 | self = [super init]; 109 | if (self) { 110 | NSError *theError = NULL; 111 | 112 | #if TOUCHXMLUSETIDY 113 | NSString *tidyEncoding = [CTidy tidyEncodingFromStringEncoding:encoding]; 114 | tidyEncoding = (tidyEncoding ?: [CTidy tidyEncodingFromStringEncoding:NSUTF8StringEncoding]); 115 | const char *tidyEncodingCString = [tidyEncoding UTF8String]; 116 | 117 | if (inOptions & CXMLDocumentTidyHTML) { 118 | CTidy *tidy = [[CTidy alloc] init]; 119 | inData = [tidy tidyData:inData inputFormat:TidyFormat_HTML outputFormat:TidyFormat_XHTML encoding:tidyEncodingCString diagnostics:NULL error:&theError]; 120 | } else if (inOptions & CXMLDocumentTidyXML) { 121 | CTidy *tidy = [[CTidy alloc] init]; 122 | inData = [tidy tidyData:inData inputFormat:TidyFormat_XML outputFormat:TidyFormat_XML encoding:tidyEncodingCString diagnostics:NULL error:&theError]; 123 | } 124 | #endif 125 | 126 | if (theError == NULL) { 127 | xmlDocPtr theDoc = NULL; 128 | if (inData && inData.length > 0) { 129 | CFStringEncoding cfenc = CFStringConvertNSStringEncodingToEncoding(encoding); 130 | CFStringRef cfencstr = CFStringConvertEncodingToIANACharSetName(cfenc); 131 | const char *enc = CFStringGetCStringPtr(cfencstr, 0); 132 | theDoc = xmlReadMemory([inData bytes], (int)[inData length], NULL, enc, XML_PARSE_RECOVER | XML_PARSE_NOWARNING); 133 | } 134 | 135 | if (theDoc != NULL && xmlDocGetRootElement(theDoc) != NULL) { 136 | _node = (xmlNodePtr)theDoc; 137 | _node->_private = (__bridge void *)self; // Note. NOT retained (TODO think more about _private usage) 138 | } else { 139 | xmlErrorPtr theLastErrorPtr = xmlGetLastError(); 140 | NSString *message = [NSString stringWithUTF8String: 141 | (theLastErrorPtr ? theLastErrorPtr->message : "Unknown error")]; 142 | NSDictionary *theUserInfo = [NSDictionary dictionaryWithObjectsAndKeys: 143 | message, NSLocalizedDescriptionKey, NULL]; 144 | theError = [NSError errorWithDomain:@"CXMLErrorDomain" code:1 userInfo:theUserInfo]; 145 | 146 | xmlResetLastError(); 147 | } 148 | } 149 | 150 | if (outError) 151 | *outError = theError; 152 | 153 | if (theError != NULL) { 154 | self = NULL; 155 | } 156 | } 157 | return (self); 158 | } 159 | 160 | - (id)initWithContentsOfURL:(NSURL *)inURL options:(NSUInteger)inOptions error:(NSError **)outError { 161 | return [self initWithContentsOfURL:inURL encoding:NSUTF8StringEncoding options:inOptions error:outError]; 162 | } 163 | 164 | - (id)initWithContentsOfURL:(NSURL *)inURL encoding:(NSStringEncoding)encoding options:(NSUInteger)inOptions error:(NSError **)outError { 165 | if (outError) 166 | *outError = NULL; 167 | 168 | NSData *theData = [NSData dataWithContentsOfURL:inURL options:NSUncachedRead error:outError]; 169 | if (theData) { 170 | self = [self initWithData:theData encoding:encoding options:inOptions error:outError]; 171 | } else { 172 | self = NULL; 173 | } 174 | 175 | return (self); 176 | } 177 | 178 | - (void)dealloc { 179 | // Fix for #35 http://code.google.com/p/touchcode/issues/detail?id=35 -- clear up the node objects first (inside a pool so I _know_ they're cleared) and then freeing the document 180 | 181 | @autoreleasepool { 182 | 183 | nodePool = NULL; 184 | } 185 | // 186 | xmlUnlinkNode(_node); 187 | xmlFreeDoc((xmlDocPtr)_node); 188 | _node = NULL; 189 | } 190 | 191 | //- (NSString *)characterEncoding; 192 | //- (NSString *)version; 193 | //- (BOOL)isStandalone; 194 | //- (CXMLDocumentContentKind)documentContentKind; 195 | //- (NSString *)MIMEType; 196 | //- (CXMLDTD *)DTD; 197 | 198 | - (CXMLElement *)rootElement { 199 | xmlNodePtr theLibXMLNode = xmlDocGetRootElement((xmlDocPtr)_node); 200 | return ([CXMLNode nodeWithLibXMLNode:theLibXMLNode freeOnDealloc:NO]); 201 | } 202 | 203 | - (NSData *)XMLData { 204 | return ([self XMLDataWithOptions:0]); 205 | } 206 | 207 | - (NSData *)XMLDataWithOptions:(NSUInteger)options { 208 | #pragma unused(options) 209 | xmlChar *theBuffer = NULL; 210 | int theBufferSize = 0; 211 | xmlDocDumpMemory((xmlDocPtr)self->_node, &theBuffer, &theBufferSize); 212 | 213 | NSData *theData = [NSData dataWithBytes:theBuffer length:theBufferSize]; 214 | 215 | xmlFree(theBuffer); 216 | 217 | return (theData); 218 | } 219 | 220 | //- (id)objectByApplyingXSLT:(NSData *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error; 221 | //- (id)objectByApplyingXSLTString:(NSString *)xslt arguments:(NSDictionary *)arguments error:(NSError **)error; 222 | //- (id)objectByApplyingXSLTAtURL:(NSURL *)xsltURL arguments:(NSDictionary *)argument error:(NSError **)error; 223 | - (id)XMLStringWithOptions:(NSUInteger)options { 224 | CXMLElement *theRoot = [self rootElement]; 225 | NSMutableString *xmlString = [NSMutableString string]; 226 | [xmlString appendString:[theRoot XMLStringWithOptions:options]]; 227 | return xmlString; 228 | } 229 | 230 | - (NSString *)description { 231 | NSAssert(_node != NULL, @"TODO"); 232 | 233 | NSMutableString *result = [NSMutableString stringWithFormat:@"<%@ %p [%p]> ", NSStringFromClass([self class]), self, self->_node]; 234 | xmlChar *xmlbuff; 235 | int buffersize; 236 | 237 | xmlDocDumpFormatMemory((xmlDocPtr)(self->_node), &xmlbuff, &buffersize, 1); 238 | NSString *dump = [[NSString alloc] initWithBytes:xmlbuff length:buffersize encoding:NSUTF8StringEncoding]; 239 | xmlFree(xmlbuff); 240 | 241 | [result appendString:dump]; 242 | return result; 243 | } 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLDocument_PrivateExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLDocument_PrivateExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLDocument.h" 33 | 34 | #include <libxml/parser.h> 35 | 36 | @interface CXMLDocument (CXMLDocument_PrivateExtensions) 37 | 38 | //- (id)initWithLibXmlParserContext:(xmlParserCtxtPtr)inContext options:(NSUInteger)inOptions error:(NSError **)outError; 39 | 40 | - (NSMutableSet *)nodePool; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLDocument_PrivateExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLDocument_PrivateExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLDocument_PrivateExtensions.h" 33 | 34 | @implementation CXMLDocument (CXMLDocument_PrivateExtensions) 35 | 36 | /* 37 | - (id)initWithLibXmlParserContext:(xmlParserCtxtPtr)inContext options:(NSUInteger)inOptions error:(NSError **)outError 38 | { 39 | 40 | xmlParseDocument(inContext); 41 | 42 | } 43 | */ 44 | 45 | - (NSMutableSet *)nodePool { 46 | if (nodePool == NULL) { 47 | nodePool = [[NSMutableSet alloc] init]; 48 | } 49 | return (nodePool); 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLElement.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode.h" 33 | 34 | // NSXMLElement 35 | @interface CXMLElement : CXMLNode { 36 | } 37 | 38 | - (NSArray *)elementsForName:(NSString *)name; 39 | - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI; 40 | 41 | - (NSArray *)attributes; 42 | - (CXMLNode *)attributeForName:(NSString *)name; 43 | - (CXMLNode *)attributeForLocalName:(NSString *)localName URI:(NSString *)URI; 44 | 45 | - (NSArray *)namespaces; 46 | - (CXMLNode *)namespaceForPrefix:(NSString *)name; 47 | - (CXMLNode *)resolveNamespaceForName:(NSString *)name; 48 | - (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI; 49 | 50 | //- (NSString*)_XMLStringWithOptions:(NSUInteger)options appendingToString:(NSMutableString*)str; 51 | @end 52 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLElement.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLElement.h" 33 | 34 | #import "CXMLNamespaceNode.h" 35 | #import "CXMLNode_CreationExtensions.h" 36 | #import "CXMLNode_PrivateExtensions.h" 37 | 38 | @implementation CXMLElement 39 | 40 | - (NSArray *)elementsForName:(NSString *)name { 41 | NSMutableArray *theElements = [NSMutableArray array]; 42 | 43 | // TODO -- native xml api? 44 | const xmlChar *theName = (const xmlChar *)[name UTF8String]; 45 | 46 | xmlNodePtr theCurrentNode = _node->children; 47 | while (theCurrentNode != NULL) { 48 | if (theCurrentNode->type == XML_ELEMENT_NODE && xmlStrcmp(theName, theCurrentNode->name) == 0) { 49 | CXMLNode *theNode = [CXMLNode nodeWithLibXMLNode:(xmlNodePtr)theCurrentNode freeOnDealloc:NO]; 50 | [theElements addObject:theNode]; 51 | } 52 | theCurrentNode = theCurrentNode->next; 53 | } 54 | return (theElements); 55 | } 56 | 57 | - (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI { 58 | if (URI == nil || [URI length] == 0) { 59 | return [self elementsForName:localName]; 60 | } 61 | 62 | NSMutableArray *theElements = [NSMutableArray array]; 63 | const xmlChar *theLocalName = (const xmlChar *)[localName UTF8String]; 64 | const xmlChar *theNamespaceName = (const xmlChar *)[URI UTF8String]; 65 | 66 | xmlNodePtr theCurrentNode = _node->children; 67 | while (theCurrentNode != NULL) { 68 | if (theCurrentNode->type == XML_ELEMENT_NODE 69 | && xmlStrcmp(theLocalName, theCurrentNode->name) == 0 70 | && theCurrentNode->ns 71 | && xmlStrcmp(theNamespaceName, theCurrentNode->ns->href) == 0) { 72 | CXMLNode *theNode = [CXMLNode nodeWithLibXMLNode:(xmlNodePtr)theCurrentNode freeOnDealloc:NO]; 73 | [theElements addObject:theNode]; 74 | } 75 | theCurrentNode = theCurrentNode->next; 76 | } 77 | 78 | return theElements; 79 | } 80 | 81 | - (NSArray *)attributes { 82 | NSMutableArray *theAttributes = [NSMutableArray array]; 83 | xmlAttrPtr theCurrentNode = _node->properties; 84 | while (theCurrentNode != NULL) { 85 | CXMLNode *theAttribute = [CXMLNode nodeWithLibXMLNode:(xmlNodePtr)theCurrentNode freeOnDealloc:NO]; 86 | [theAttributes addObject:theAttribute]; 87 | theCurrentNode = theCurrentNode->next; 88 | } 89 | return (theAttributes); 90 | } 91 | 92 | - (CXMLNode *)attributeForName:(NSString *)name { 93 | // TODO -- look for native libxml2 function for finding a named attribute (like xmlGetProp) 94 | 95 | NSRange split = [name rangeOfString:@":"]; 96 | 97 | xmlChar *theLocalName = NULL; 98 | xmlChar *thePrefix = NULL; 99 | 100 | if (split.length > 0) { 101 | theLocalName = (xmlChar *)[[name substringFromIndex:split.location + 1] UTF8String]; 102 | thePrefix = (xmlChar *)[[name substringToIndex:split.location] UTF8String]; 103 | } else { 104 | theLocalName = (xmlChar *)[name UTF8String]; 105 | } 106 | 107 | xmlAttrPtr theCurrentNode = _node->properties; 108 | while (theCurrentNode != NULL) { 109 | if (xmlStrcmp(theLocalName, theCurrentNode->name) == 0) { 110 | if (thePrefix == NULL || (theCurrentNode->ns && theCurrentNode->ns->prefix && xmlStrcmp(thePrefix, theCurrentNode->ns->prefix) == 0)) { 111 | CXMLNode *theAttribute = [CXMLNode nodeWithLibXMLNode:(xmlNodePtr)theCurrentNode freeOnDealloc:NO]; 112 | return (theAttribute); 113 | } 114 | } 115 | theCurrentNode = theCurrentNode->next; 116 | } 117 | return (NULL); 118 | } 119 | 120 | - (CXMLNode *)attributeForLocalName:(NSString *)localName URI:(NSString *)URI { 121 | if (URI == nil) { 122 | return [self attributeForName:localName]; 123 | } 124 | 125 | // TODO -- look for native libxml2 function for finding a named attribute (like xmlGetProp) 126 | const xmlChar *theLocalName = (const xmlChar *)[localName UTF8String]; 127 | const xmlChar *theNamespaceName = (const xmlChar *)[URI UTF8String]; 128 | 129 | xmlAttrPtr theCurrentNode = _node->properties; 130 | while (theCurrentNode != NULL) { 131 | if (theCurrentNode->ns && theCurrentNode->ns->href && xmlStrcmp(theLocalName, theCurrentNode->name) == 0 && xmlStrcmp(theNamespaceName, theCurrentNode->ns->href) == 0) { 132 | CXMLNode *theAttribute = [CXMLNode nodeWithLibXMLNode:(xmlNodePtr)theCurrentNode freeOnDealloc:NO]; 133 | return (theAttribute); 134 | } 135 | theCurrentNode = theCurrentNode->next; 136 | } 137 | return (NULL); 138 | } 139 | 140 | - (NSArray *)namespaces { 141 | NSMutableArray *theNamespaces = [[NSMutableArray alloc] init]; 142 | xmlNsPtr theCurrentNamespace = _node->nsDef; 143 | 144 | while (theCurrentNamespace != NULL) { 145 | NSString *thePrefix = theCurrentNamespace->prefix ? [NSString stringWithUTF8String:(const char *)theCurrentNamespace->prefix] : @""; 146 | NSString *theURI = [NSString stringWithUTF8String:(const char *)theCurrentNamespace->href]; 147 | CXMLNamespaceNode *theNode = [[CXMLNamespaceNode alloc] initWithPrefix:thePrefix URI:theURI parentElement:self]; 148 | [theNamespaces addObject:theNode]; 149 | 150 | theCurrentNamespace = theCurrentNamespace->next; 151 | } 152 | 153 | return theNamespaces; 154 | } 155 | 156 | - (CXMLNode *)namespaceForPrefix:(NSString *)name { 157 | const xmlChar *thePrefix = (const xmlChar *)[name UTF8String]; 158 | xmlNsPtr theCurrentNamespace = _node->nsDef; 159 | 160 | while (theCurrentNamespace != NULL) { 161 | if (xmlStrcmp(theCurrentNamespace->prefix, thePrefix) == 0) { 162 | NSString *thePrefixString = theCurrentNamespace->prefix ? [NSString stringWithUTF8String:(const char *)theCurrentNamespace->prefix] : @""; 163 | NSString *theURI = [NSString stringWithUTF8String:(const char *)theCurrentNamespace->href]; 164 | return [[CXMLNamespaceNode alloc] initWithPrefix:thePrefixString URI:theURI parentElement:self]; 165 | } 166 | theCurrentNamespace = theCurrentNamespace->next; 167 | } 168 | return nil; 169 | } 170 | 171 | - (CXMLNode *)resolveNamespaceForName:(NSString *)name { 172 | NSRange split = [name rangeOfString:@":"]; 173 | 174 | if (split.length > 0) 175 | return [self namespaceForPrefix:[name substringToIndex:split.location]]; 176 | 177 | xmlNsPtr theCurrentNamespace = _node->nsDef; 178 | 179 | while (theCurrentNamespace != NULL) { 180 | if (theCurrentNamespace->prefix == 0 181 | || (theCurrentNamespace->prefix)[0] == 0) { 182 | NSString *thePrefix = theCurrentNamespace->prefix ? [NSString stringWithUTF8String:(const char *)theCurrentNamespace->prefix] : @""; 183 | NSString *theURI = [NSString stringWithUTF8String:(const char *)theCurrentNamespace->href]; 184 | return [[CXMLNamespaceNode alloc] initWithPrefix:thePrefix URI:theURI parentElement:self]; 185 | } 186 | theCurrentNamespace = theCurrentNamespace->next; 187 | } 188 | 189 | return nil; 190 | } 191 | 192 | - (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI { 193 | const xmlChar *theXMLURI = (const xmlChar *)[namespaceURI UTF8String]; 194 | 195 | xmlNsPtr theCurrentNamespace = _node->nsDef; 196 | 197 | while (theCurrentNamespace != NULL) { 198 | if (xmlStrcmp(theCurrentNamespace->href, theXMLURI) == 0) { 199 | if (theCurrentNamespace->prefix) 200 | return [NSString stringWithUTF8String:(const char *)theCurrentNamespace->prefix]; 201 | 202 | return @""; 203 | } 204 | theCurrentNamespace = theCurrentNamespace->next; 205 | } 206 | return nil; 207 | } 208 | 209 | //- (NSString*)_XMLStringWithOptions:(NSUInteger)options appendingToString:(NSMutableString*)str 210 | //{ 211 | //NSString* name = [self name]; 212 | //[str appendString:[NSString stringWithFormat:@"<%@", name]]; 213 | // 214 | //for (id attribute in [self attributes] ) 215 | // { 216 | // [attribute _XMLStringWithOptions:options appendingToString:str]; 217 | // } 218 | // 219 | //if ( ! _node->children ) 220 | // { 221 | // bool isEmpty = NO; 222 | // NSArray *emptyTags = [NSArray arrayWithObjects: @"br", @"area", @"link", @"img", @"param", @"hr", @"input", @"col", @"base", @"meta", nil ]; 223 | // for (id s in emptyTags) 224 | // { 225 | // if ( [s isEqualToString:@"base"] ) 226 | // { 227 | // isEmpty = YES; 228 | // break; 229 | // } 230 | // } 231 | // if ( isEmpty ) 232 | // { 233 | // [str appendString:@"/>"]; 234 | // return str; 235 | // } 236 | // } 237 | // 238 | //[str appendString:@">"]; 239 | // 240 | //if ( _node->children ) 241 | // { 242 | // for (id child in [self children]) 243 | // [child _XMLStringWithOptions:options appendingToString:str]; 244 | // } 245 | //[str appendString:[NSString stringWithFormat:@"</%@>", name]]; 246 | //return str; 247 | //} 248 | 249 | - (NSString *)description { 250 | NSAssert(_node != NULL, @"TODO"); 251 | 252 | return ([NSString stringWithFormat:@"<%@ %p [%p] %@ %@>", NSStringFromClass([self class]), self, self->_node, [self name], [self XMLStringWithOptions:0]]); 253 | } 254 | 255 | @end 256 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLElement_CreationExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLElement_CreationExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/01/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLElement.h" 33 | 34 | @interface CXMLElement (CXMLElement_CreationExtensions) 35 | 36 | - (void)addChild:(CXMLNode *)inNode; 37 | 38 | - (void)addNamespace:(CXMLNode *)inNamespace; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLElement_CreationExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLElement_CreationExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/01/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLElement_CreationExtensions.h" 33 | 34 | @implementation CXMLElement (CXMLElement_CreationExtensions) 35 | 36 | - (void)addChild:(CXMLNode *)inNode { 37 | NSAssert(inNode->_node->doc == NULL, @"Cannot addChild with a node that already is part of a document. Copy it first!"); 38 | NSAssert(self->_node != NULL, @"_node should not be null"); 39 | NSAssert(inNode->_node != NULL, @"_node should not be null"); 40 | xmlAddChild(self->_node, inNode->_node); 41 | // now XML element is tracked by document, do not release on dealloc 42 | inNode->_freeNodeOnRelease = NO; 43 | } 44 | 45 | - (void)addNamespace:(CXMLNode *)inNamespace { 46 | xmlSetNs(self->_node, (xmlNsPtr)inNamespace->_node); 47 | } 48 | 49 | - (void)setStringValue:(NSString *)inStringValue { 50 | NSAssert(inStringValue != NULL, @"CXMLElement setStringValue should not be null"); 51 | xmlNodePtr theContentNode = xmlNewText((const xmlChar *)[inStringValue UTF8String]); 52 | NSAssert(self->_node != NULL, @"_node should not be null"); 53 | xmlAddChild(self->_node, theContentNode); 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLElement_ElementTreeExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLElement_ElementTreeExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 11/14/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLElement.h" 33 | 34 | @interface CXMLElement (CXMLElement_ElementTreeExtensions) 35 | 36 | - (CXMLElement *)subelement:(NSString *)inName; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLElement_ElementTreeExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLElement_ElementTreeExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 11/14/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLElement_ElementTreeExtensions.h" 33 | 34 | #import "CXMLElement_CreationExtensions.h" 35 | #import "CXMLNode_CreationExtensions.h" 36 | 37 | @implementation CXMLElement (CXMLElement_ElementTreeExtensions) 38 | 39 | - (CXMLElement *)subelement:(NSString *)inName; 40 | { 41 | CXMLElement *theSubelement = [CXMLNode elementWithName:inName]; 42 | [self addChild:theSubelement]; 43 | return (theSubelement); 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNamespaceNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNamespaceNode.h 3 | // TouchXML 4 | // 5 | // Created by Jonathan Wight on 1/1/2000. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLElement.h" 33 | #import "CXMLNode.h" 34 | #import <Foundation/Foundation.h> 35 | 36 | @interface CXMLNamespaceNode : CXMLNode { 37 | 38 | NSString *_prefix; 39 | NSString *_uri; 40 | CXMLElement *_parent; 41 | } 42 | 43 | - (id)initWithPrefix:(NSString *)prefix URI:(NSString *)uri parentElement:(CXMLElement *)parent; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNamespaceNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNamespaceNode.m 3 | // TouchXML 4 | // 5 | // Created by Jonathan Wight on 1/1/2000. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNamespaceNode.h" 33 | 34 | @implementation CXMLNamespaceNode 35 | 36 | #pragma mark - 37 | #pragma mark Init and dealloc 38 | 39 | - (id)initWithPrefix:(NSString *)prefix URI:(NSString *)uri parentElement:(CXMLElement *)parent { 40 | if ((self = [super init]) != NULL) { 41 | _prefix = [prefix copy]; 42 | _uri = [uri copy]; 43 | _parent = parent; // Don't retain parent 44 | } 45 | 46 | return self; 47 | } 48 | 49 | - (void)dealloc { 50 | _prefix = nil; 51 | _uri = nil; 52 | _parent = nil; // Parent not retained 53 | } 54 | 55 | #pragma mark - 56 | #pragma mark Overidden methods 57 | 58 | // NB: We need to override every method that relies on _node as namespaces in libXML don't have a xmlNode 59 | 60 | - (CXMLNodeKind)kind { 61 | return CXMLNamespaceKind; 62 | } 63 | 64 | - (NSString *)name { 65 | return _prefix ? [_prefix copy] : @""; 66 | } 67 | 68 | - (NSString *)stringValue { 69 | return _uri ? [_uri copy] : @""; 70 | } 71 | 72 | - (NSUInteger)index { 73 | return 0; // TODO: Write tets, Fix 74 | } 75 | 76 | - (NSUInteger)level { 77 | return _parent ? [_parent level] + 1 : 2; 78 | } 79 | 80 | - (CXMLDocument *)rootDocument { 81 | return [_parent rootDocument]; 82 | } 83 | 84 | - (CXMLNode *)parent { 85 | return _parent; 86 | } 87 | 88 | - (NSUInteger)childCount { 89 | return 0; 90 | } 91 | 92 | - (NSArray *)children { 93 | return nil; 94 | } 95 | 96 | - (CXMLNode *)childAtIndex:(NSUInteger)index { 97 | return nil; 98 | } 99 | 100 | - (CXMLNode *)previousSibling { 101 | return nil; // TODO: Write tets, Fix 102 | } 103 | 104 | - (CXMLNode *)nextSibling { 105 | return nil; // TODO: Write tets, Fix 106 | } 107 | 108 | //- (CXMLNode *)previousNode; 109 | //- (CXMLNode *)nextNode; 110 | //- (NSString *)XPath; 111 | 112 | - (NSString *)localName { 113 | return [self name]; 114 | } 115 | 116 | - (NSString *)prefix { 117 | return @""; 118 | } 119 | 120 | - (NSString *)URI { 121 | return nil; 122 | } 123 | 124 | //+ (NSString *)localNameForName:(NSString *)name; 125 | //+ (NSString *)prefixForName:(NSString *)name; 126 | //+ (CXMLNode *)predefinedNamespaceForPrefix:(NSString *)name; 127 | 128 | - (NSString *)description { 129 | if (_prefix && [_prefix length] > 0) 130 | return [NSString stringWithFormat:@"xmlns:%@=\"%@\"", _prefix, _uri]; 131 | 132 | return [NSString stringWithFormat:@"xmlns=\"%@\"", _uri]; 133 | } 134 | 135 | - (NSString *)XMLString { 136 | return [self description]; 137 | } 138 | 139 | - (NSString *)XMLStringWithOptions:(NSUInteger)options { 140 | return [self description]; 141 | } 142 | 143 | //- (NSString *)canonicalXMLStringPreservingComments:(BOOL)comments; 144 | 145 | - (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error { 146 | return nil; 147 | } 148 | 149 | @end 150 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNode.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import <Foundation/Foundation.h> 33 | 34 | #include <libxml/tree.h> 35 | 36 | typedef enum { 37 | CXMLInvalidKind = 0, 38 | CXMLElementKind = XML_ELEMENT_NODE, 39 | CXMLAttributeKind = XML_ATTRIBUTE_NODE, 40 | CXMLTextKind = XML_TEXT_NODE, 41 | CXMLProcessingInstructionKind = XML_PI_NODE, 42 | CXMLCommentKind = XML_COMMENT_NODE, 43 | CXMLNotationDeclarationKind = XML_NOTATION_NODE, 44 | CXMLDTDKind = XML_DTD_NODE, 45 | CXMLElementDeclarationKind = XML_ELEMENT_DECL, 46 | CXMLAttributeDeclarationKind = XML_ATTRIBUTE_DECL, 47 | CXMLEntityDeclarationKind = XML_ENTITY_DECL, 48 | CXMLNamespaceKind = XML_NAMESPACE_DECL, 49 | CXMLEntityReferenceKind = XML_ENTITY_REF_NODE 50 | } CXMLNodeKind; 51 | 52 | @class CXMLDocument; 53 | 54 | // NSXMLNode 55 | @interface CXMLNode : NSObject <NSCopying> { 56 | xmlNodePtr _node; 57 | BOOL _freeNodeOnRelease; 58 | } 59 | 60 | - (CXMLNodeKind)kind; 61 | - (NSString *)name; 62 | - (NSString *)stringValue; 63 | - (NSUInteger)index; 64 | - (NSUInteger)level; 65 | - (CXMLDocument *)rootDocument; 66 | - (CXMLNode *)parent; 67 | - (NSUInteger)childCount; 68 | - (NSArray *)children; 69 | - (CXMLNode *)childAtIndex:(NSUInteger)index; 70 | - (CXMLNode *)previousSibling; 71 | - (CXMLNode *)nextSibling; 72 | //- (CXMLNode *)previousNode; 73 | //- (CXMLNode *)nextNode; 74 | //- (NSString *)XPath; 75 | - (NSString *)localName; 76 | - (NSString *)prefix; 77 | - (NSString *)URI; 78 | + (NSString *)localNameForName:(NSString *)name; 79 | + (NSString *)prefixForName:(NSString *)name; 80 | + (CXMLNode *)predefinedNamespaceForPrefix:(NSString *)name; 81 | - (NSString *)description; 82 | - (NSString *)XMLString; 83 | - (NSString *)XMLStringWithOptions:(NSUInteger)options; 84 | //- (NSString *)canonicalXMLStringPreservingComments:(BOOL)comments; 85 | - (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error; 86 | @end 87 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNode.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode.h" 33 | 34 | #import "CXMLDocument.h" 35 | #import "CXMLElement.h" 36 | #import "CXMLNode_CreationExtensions.h" 37 | #import "CXMLNode_PrivateExtensions.h" 38 | 39 | #include <libxml/xmlIO.h> 40 | #include <libxml/xpath.h> 41 | #include <libxml/xpathInternals.h> 42 | 43 | static int MyXmlOutputWriteCallback(void *context, const char *buffer, int len); 44 | static int MyXmlOutputCloseCallback(void *context); 45 | 46 | @implementation CXMLNode 47 | 48 | - (void)dealloc { 49 | [self invalidate]; 50 | } 51 | 52 | - (id)copyWithZone:(NSZone *)zone; 53 | { 54 | #pragma unused(zone) 55 | xmlNodePtr theNewNode = xmlCopyNode(_node, 1); 56 | CXMLNode *theNode = [[[self class] alloc] initWithLibXMLNode:theNewNode freeOnDealloc:YES]; 57 | theNewNode->_private = (__bridge void *)theNode; 58 | return (theNode); 59 | } 60 | 61 | #pragma mark - 62 | 63 | - (CXMLNodeKind)kind { 64 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 65 | return ((CXMLNodeKind)_node->type); // TODO this isn't 100% accurate! 66 | } 67 | 68 | - (NSString *)name { 69 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 70 | // TODO use xmlCheckUTF8 to check name 71 | if (_node->name == NULL) 72 | return (NULL); 73 | 74 | NSString *localName = [NSString stringWithUTF8String:(const char *)_node->name]; 75 | 76 | if (_node->ns == NULL || _node->ns->prefix == NULL) 77 | return localName; 78 | 79 | return [NSString stringWithFormat:@"%@:%@", [NSString stringWithUTF8String:(const char *)_node->ns->prefix], localName]; 80 | } 81 | 82 | - (NSString *)stringValue { 83 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 84 | 85 | if (_node->type == XML_TEXT_NODE || _node->type == XML_CDATA_SECTION_NODE) 86 | return [NSString stringWithUTF8String:(const char *)_node->content]; 87 | 88 | if (_node->type == XML_ATTRIBUTE_NODE) 89 | return [NSString stringWithUTF8String:(const char *)_node->children->content]; 90 | 91 | NSMutableString *theStringValue = [[NSMutableString alloc] init]; 92 | 93 | for (CXMLNode *child in [self children]) { 94 | [theStringValue appendString:[child stringValue]]; 95 | } 96 | 97 | return theStringValue; 98 | } 99 | 100 | - (NSUInteger)index { 101 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 102 | 103 | xmlNodePtr theCurrentNode = _node->prev; 104 | NSUInteger N; 105 | for (N = 0; theCurrentNode != NULL; ++N, theCurrentNode = theCurrentNode->prev) 106 | ; 107 | return (N); 108 | } 109 | 110 | - (NSUInteger)level { 111 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 112 | 113 | xmlNodePtr theCurrentNode = _node->parent; 114 | NSUInteger N; 115 | for (N = 0; theCurrentNode != NULL; ++N, theCurrentNode = theCurrentNode->parent) 116 | ; 117 | return (N); 118 | } 119 | 120 | - (CXMLDocument *)rootDocument { 121 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 122 | 123 | return ((__bridge CXMLDocument *)_node->doc->_private); 124 | } 125 | 126 | - (CXMLNode *)parent { 127 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 128 | 129 | if (_node->parent == NULL) 130 | return (NULL); 131 | else 132 | return ((__bridge CXMLDocument *)_node->parent->_private); 133 | } 134 | 135 | - (NSUInteger)childCount { 136 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 137 | 138 | if (_node->type == CXMLAttributeKind) 139 | return 0; // NSXMLNodes of type NSXMLAttributeKind can't have children 140 | 141 | xmlNodePtr theCurrentNode = _node->children; 142 | NSUInteger N; 143 | for (N = 0; theCurrentNode != NULL; ++N, theCurrentNode = theCurrentNode->next) 144 | ; 145 | return (N); 146 | } 147 | 148 | - (NSArray *)children { 149 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 150 | 151 | NSMutableArray *theChildren = [NSMutableArray array]; 152 | 153 | if (_node->type != CXMLAttributeKind) // NSXML Attribs don't have children. 154 | { 155 | xmlNodePtr theCurrentNode = _node->children; 156 | while (theCurrentNode != NULL) { 157 | CXMLNode *theNode = [CXMLNode nodeWithLibXMLNode:theCurrentNode freeOnDealloc:NO]; 158 | [theChildren addObject:theNode]; 159 | theCurrentNode = theCurrentNode->next; 160 | } 161 | } 162 | return (theChildren); 163 | } 164 | 165 | - (CXMLNode *)childAtIndex:(NSUInteger)index { 166 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 167 | 168 | xmlNodePtr theCurrentNode = _node->children; 169 | NSUInteger N; 170 | for (N = 0; theCurrentNode != NULL && N != index; ++N, theCurrentNode = theCurrentNode->next) 171 | ; 172 | if (theCurrentNode) 173 | return ([CXMLNode nodeWithLibXMLNode:theCurrentNode freeOnDealloc:NO]); 174 | return (NULL); 175 | } 176 | 177 | - (CXMLNode *)previousSibling { 178 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 179 | 180 | if (_node->prev == NULL) 181 | return (NULL); 182 | else 183 | return ([CXMLNode nodeWithLibXMLNode:_node->prev freeOnDealloc:NO]); 184 | } 185 | 186 | - (CXMLNode *)nextSibling { 187 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 188 | 189 | if (_node->next == NULL) 190 | return (NULL); 191 | else 192 | return ([CXMLNode nodeWithLibXMLNode:_node->next freeOnDealloc:NO]); 193 | } 194 | 195 | //- (CXMLNode *)previousNode; 196 | //- (CXMLNode *)nextNode; 197 | //- (NSString *)XPath; 198 | 199 | - (NSString *)localName { 200 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 201 | // TODO use xmlCheckUTF8 to check name 202 | if (_node->name == NULL) 203 | return (NULL); 204 | else 205 | return ([NSString stringWithUTF8String:(const char *)_node->name]); 206 | } 207 | 208 | - (NSString *)prefix { 209 | if (_node->ns && _node->ns->prefix) 210 | return ([NSString stringWithUTF8String:(const char *)_node->ns->prefix]); 211 | else 212 | return (@""); 213 | } 214 | 215 | - (NSString *)URI { 216 | if (_node->ns) 217 | return ([NSString stringWithUTF8String:(const char *)_node->ns->href]); 218 | else 219 | return (NULL); 220 | } 221 | 222 | + (NSString *)localNameForName:(NSString *)name { 223 | NSRange split = [name rangeOfString:@":"]; 224 | 225 | if (split.length > 0) 226 | return [name substringFromIndex:split.location + 1]; 227 | 228 | return name; 229 | } 230 | 231 | + (NSString *)prefixForName:(NSString *)name { 232 | NSRange split = [name rangeOfString:@":"]; 233 | 234 | if (split.length > 0) 235 | return [name substringToIndex:split.location]; 236 | 237 | return @""; 238 | } 239 | 240 | + (CXMLNode *)predefinedNamespaceForPrefix:(NSString *)name { 241 | if ([name isEqualToString:@"xml"]) 242 | return [CXMLNode namespaceWithName:@"xml" stringValue:@"http://www.w3.org/XML/1998/namespace"]; 243 | 244 | if ([name isEqualToString:@"xs"]) 245 | return [CXMLNode namespaceWithName:@"xs" stringValue:@"http://www.w3.org/2001/XMLSchema"]; 246 | 247 | if ([name isEqualToString:@"xsi"]) 248 | return [CXMLNode namespaceWithName:@"xsi" stringValue:@"http://www.w3.org/2001/XMLSchema-instance"]; 249 | 250 | if ([name isEqualToString:@"xmlns"]) // Not in Cocoa, but should be as it's reserved by W3C 251 | return [CXMLNode namespaceWithName:@"xmlns" stringValue:@"http://www.w3.org/2000/xmlns/"]; 252 | 253 | return nil; 254 | } 255 | 256 | - (NSString *)description { 257 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 258 | 259 | return ([NSString stringWithFormat:@"<%@ %p [%p] %@ %@>", NSStringFromClass([self class]), self, self->_node, [self name], [self XMLStringWithOptions:0]]); 260 | } 261 | 262 | - (NSString *)XMLString { 263 | return ([self XMLStringWithOptions:0]); 264 | } 265 | 266 | - (NSString *)XMLStringWithOptions:(NSUInteger)options { 267 | #pragma unused(options) 268 | 269 | NSMutableData *theData = [[NSMutableData alloc] init]; 270 | 271 | xmlOutputBufferPtr theOutputBuffer = xmlOutputBufferCreateIO(MyXmlOutputWriteCallback, MyXmlOutputCloseCallback, (__bridge void *)theData, NULL); 272 | 273 | xmlNodeDumpOutput(theOutputBuffer, _node->doc, _node, 0, 0, "utf-8"); 274 | 275 | xmlOutputBufferFlush(theOutputBuffer); 276 | 277 | NSString *theString = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]; 278 | 279 | xmlOutputBufferClose(theOutputBuffer); 280 | 281 | return (theString); 282 | } 283 | //- (NSString *)canonicalXMLStringPreservingComments:(BOOL)comments; 284 | 285 | - (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error { 286 | #pragma unused(error) 287 | 288 | NSAssert(_node != NULL, @"CXMLNode does not have attached libxml2 _node."); 289 | 290 | NSArray *theResult = NULL; 291 | 292 | xmlXPathContextPtr theXPathContext = xmlXPathNewContext(_node->doc); 293 | theXPathContext->node = _node; 294 | 295 | // TODO considering putting xmlChar <-> UTF8 into a NSString category 296 | xmlXPathObjectPtr theXPathObject = xmlXPathEvalExpression((const xmlChar *)[xpath UTF8String], theXPathContext); 297 | if (theXPathObject == NULL) { 298 | if (error) 299 | *error = [NSError errorWithDomain:@"TODO_DOMAIN" code:-1 userInfo:NULL]; 300 | return (NULL); 301 | } 302 | if (xmlXPathNodeSetIsEmpty(theXPathObject->nodesetval)) 303 | theResult = [NSArray array]; // TODO better to return NULL? 304 | else { 305 | NSMutableArray *theArray = [NSMutableArray array]; 306 | int N; 307 | for (N = 0; N < theXPathObject->nodesetval->nodeNr; N++) { 308 | xmlNodePtr theNode = theXPathObject->nodesetval->nodeTab[N]; 309 | [theArray addObject:[CXMLNode nodeWithLibXMLNode:theNode freeOnDealloc:NO]]; 310 | } 311 | 312 | theResult = theArray; 313 | } 314 | 315 | xmlXPathFreeObject(theXPathObject); 316 | xmlXPathFreeContext(theXPathContext); 317 | return (theResult); 318 | } 319 | 320 | //- (NSArray *)objectsForXQuery:(NSString *)xquery constants:(NSDictionary *)constants error:(NSError **)error; 321 | //- (NSArray *)objectsForXQuery:(NSString *)xquery error:(NSError **)error; 322 | 323 | @end 324 | 325 | static int MyXmlOutputWriteCallback(void *context, const char *buffer, int len) { 326 | NSMutableData *theData = (__bridge NSMutableData *)context; 327 | [theData appendBytes:buffer length:len]; 328 | return (len); 329 | } 330 | 331 | static int MyXmlOutputCloseCallback(void *context) { 332 | return (0); 333 | } 334 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNode_PrivateExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode_PrivateExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode.h" 33 | 34 | @interface CXMLNode (CXMLNode_PrivateExtensions) 35 | 36 | @property (readonly, nonatomic, assign) xmlNodePtr node; 37 | 38 | - (id)initWithLibXMLNode:(xmlNodePtr)inLibXMLNode freeOnDealloc:(BOOL)infreeOnDealloc; 39 | 40 | + (id)nodeWithLibXMLNode:(xmlNodePtr)inLibXMLNode freeOnDealloc:(BOOL)infreeOnDealloc; 41 | 42 | + (Class)nodeClassForLibXMLNode:(xmlNodePtr)inLibXMLNode; 43 | 44 | - (void)invalidate; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNode_PrivateExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode_PrivateExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode_PrivateExtensions.h" 33 | 34 | #import "CXMLDocument_PrivateExtensions.h" 35 | #import "CXMLElement.h" 36 | #import "CXMLUnsupportedNode.h" 37 | 38 | @implementation CXMLNode (CXMLNode_PrivateExtensions) 39 | 40 | - (id)initWithLibXMLNode:(xmlNodePtr)inLibXMLNode freeOnDealloc:(BOOL)infreeOnDealloc { 41 | if (inLibXMLNode == NULL) 42 | return nil; 43 | 44 | if ((self = [super init]) != NULL) { 45 | _node = inLibXMLNode; 46 | _freeNodeOnRelease = infreeOnDealloc; 47 | } 48 | return (self); 49 | } 50 | 51 | + (id)nodeWithLibXMLNode:(xmlNodePtr)inLibXMLNode freeOnDealloc:(BOOL)infreeOnDealloc { 52 | // TODO more checking. 53 | if (inLibXMLNode == NULL) 54 | return nil; 55 | 56 | if (inLibXMLNode->_private) 57 | return ((__bridge id)inLibXMLNode->_private); 58 | 59 | Class theClass = [self nodeClassForLibXMLNode:inLibXMLNode]; 60 | 61 | CXMLNode *theNode = [[theClass alloc] initWithLibXMLNode:inLibXMLNode freeOnDealloc:infreeOnDealloc]; 62 | 63 | if (inLibXMLNode->doc != NULL) { 64 | CXMLDocument *theXMLDocument = (__bridge CXMLDocument *)inLibXMLNode->doc->_private; 65 | if (theXMLDocument != NULL) { 66 | NSAssert([theXMLDocument isKindOfClass:[CXMLDocument class]] == YES, @"TODO"); 67 | 68 | [[theXMLDocument nodePool] addObject:theNode]; 69 | 70 | theNode->_node->_private = (__bridge void *)theNode; 71 | } 72 | } 73 | return (theNode); 74 | } 75 | 76 | + (Class)nodeClassForLibXMLNode:(xmlNodePtr)inLibXMLNode { 77 | Class theClass; 78 | 79 | switch (inLibXMLNode->type) { 80 | case XML_ELEMENT_NODE: 81 | theClass = [CXMLElement class]; 82 | break; 83 | case XML_DOCUMENT_NODE: 84 | theClass = [CXMLDocument class]; 85 | break; 86 | case XML_ATTRIBUTE_NODE: 87 | case XML_TEXT_NODE: 88 | case XML_CDATA_SECTION_NODE: 89 | case XML_COMMENT_NODE: 90 | theClass = [CXMLNode class]; 91 | break; 92 | default: 93 | theClass = [CXMLUnsupportedNode class]; 94 | } 95 | 96 | return theClass; 97 | } 98 | 99 | - (xmlNodePtr)node { 100 | return (_node); 101 | } 102 | 103 | - (void)invalidate; 104 | { 105 | if (_node) { 106 | if (_freeNodeOnRelease) { 107 | xmlUnlinkNode(_node); 108 | xmlFreeNode(_node); 109 | } 110 | 111 | _node = NULL; 112 | } 113 | } 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNode_XPathExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode_XPathExtensions.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/01/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode.h" 33 | 34 | @interface CXMLNode (CXMLNode_XPathExtensions) 35 | 36 | - (NSArray *)nodesForXPath:(NSString *)xpath namespaceMappings:(NSDictionary *)inNamespaceMappings error:(NSError **)error; 37 | - (CXMLNode *)nodeForXPath:(NSString *)xpath namespaceMappings:(NSDictionary *)inNamespaceMappings error:(NSError **)error; 38 | - (CXMLNode *)nodeForXPath:(NSString *)xpath error:(NSError **)outError; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLNode_XPathExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // CXMLNode_XPathExtensions.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 04/01/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #import "CXMLNode_XPathExtensions.h" 33 | 34 | #import "CXMLDocument.h" 35 | #import "CXMLNode_PrivateExtensions.h" 36 | 37 | #include <libxml/xpath.h> 38 | #include <libxml/xpathInternals.h> 39 | 40 | @implementation CXMLNode (CXMLNode_XPathExtensions) 41 | 42 | - (NSArray *)nodesForXPath:(NSString *)xpath namespaceMappings:(NSDictionary *)inNamespaceMappings error:(NSError **)error; 43 | { 44 | #pragma unused(error) 45 | 46 | NSAssert(_node != NULL, @"TODO"); 47 | 48 | NSArray *theResult = NULL; 49 | 50 | xmlXPathContextPtr theXPathContext = xmlXPathNewContext(_node->doc); 51 | theXPathContext->node = _node; 52 | 53 | for (NSString *thePrefix in inNamespaceMappings) { 54 | xmlXPathRegisterNs(theXPathContext, (xmlChar *)[thePrefix UTF8String], (xmlChar *)[[inNamespaceMappings objectForKey:thePrefix] UTF8String]); 55 | } 56 | 57 | // TODO considering putting xmlChar <-> UTF8 into a NSString category 58 | xmlXPathObjectPtr theXPathObject = xmlXPathEvalExpression((const xmlChar *)[xpath UTF8String], theXPathContext); 59 | if (xmlXPathNodeSetIsEmpty(theXPathObject->nodesetval)) 60 | theResult = [NSArray array]; // TODO better to return NULL? 61 | else { 62 | NSMutableArray *theArray = [NSMutableArray array]; 63 | int N; 64 | for (N = 0; N < theXPathObject->nodesetval->nodeNr; N++) { 65 | xmlNodePtr theNode = theXPathObject->nodesetval->nodeTab[N]; 66 | [theArray addObject:[CXMLNode nodeWithLibXMLNode:theNode freeOnDealloc:NO]]; 67 | } 68 | 69 | theResult = theArray; 70 | } 71 | 72 | xmlXPathFreeObject(theXPathObject); 73 | 74 | xmlXPathFreeContext(theXPathContext); 75 | return (theResult); 76 | } 77 | 78 | - (CXMLNode *)nodeForXPath:(NSString *)xpath namespaceMappings:(NSDictionary *)inNamespaceMappings error:(NSError **)error { 79 | return [[self nodesForXPath:xpath namespaceMappings:inNamespaceMappings error:error] lastObject]; 80 | } 81 | 82 | - (CXMLNode *)nodeForXPath:(NSString *)xpath error:(NSError **)outError { 83 | return ([[self nodesForXPath:xpath error:outError] lastObject]); 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLUnsupportedNode.h: -------------------------------------------------------------------------------- 1 | /** 2 | This is a "special" class which marks nodes types not supported by TouchXML. 3 | They could work... or not... becareful when you encounter them. 4 | */ 5 | 6 | #import "CXMLNode.h" 7 | 8 | @interface CXMLUnsupportedNode : CXMLNode 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Vendor/TouchXML/CXMLUnsupportedNode.m: -------------------------------------------------------------------------------- 1 | #import "CXMLUnsupportedNode.h" 2 | 3 | @implementation CXMLUnsupportedNode 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Vendor/TouchXML/Tidy/CTidy.h: -------------------------------------------------------------------------------- 1 | // 2 | // CTidy.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #ifdef TOUCHXMLUSETIDY 33 | 34 | #import <Foundation/Foundation.h> 35 | 36 | #include "buffio.h" 37 | #include "tidy.h" 38 | 39 | typedef enum { 40 | TidyFormat_HTML, 41 | TidyFormat_XML, 42 | TidyFormat_XHTML, 43 | } CTidyFormat; 44 | 45 | @interface CTidy : NSObject 46 | + (NSString *)tidyEncodingFromStringEncoding:(NSStringEncoding)encoding; 47 | 48 | - (NSData *)tidyData:(NSData *)inData inputFormat:(CTidyFormat)inInputFormat outputFormat:(CTidyFormat)inOutputFormat encoding:(const char *)encoding diagnostics:(NSString **)outDiagnostics error:(NSError **)outError; 49 | 50 | - (NSString *)tidyString:(NSString *)inString inputFormat:(CTidyFormat)inInputFormat outputFormat:(CTidyFormat)inOutputFormat encoding:(const char *)encoding diagnostics:(NSString **)outDiagnostics error:(NSError **)outError; 51 | @end 52 | 53 | #endif /* TOUCHXMLUSETIDY */ 54 | -------------------------------------------------------------------------------- /Vendor/TouchXML/Tidy/CTidy.m: -------------------------------------------------------------------------------- 1 | // 2 | // CTidy.m 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 03/07/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | #ifdef TOUCHXMLUSETIDY 33 | 34 | #import "CTidy.h" 35 | 36 | @interface CTidy () 37 | @end 38 | 39 | @implementation CTidy 40 | 41 | /* 42 | Values include: ascii, latin1, raw, utf8, iso2022, mac, win1252, utf16le, utf16be, utf16, big5 and shiftjis. Case in-sensitive. 43 | http://tidy.sourceforge.net/docs/api/group__Basic.html#g2612e184472c2a59ca822a37d030e9af 44 | */ 45 | + (NSString *)tidyEncodingFromStringEncoding:(NSStringEncoding)encoding { 46 | NSString *tidyEncoding; 47 | 48 | switch (encoding) { 49 | case NSASCIIStringEncoding: 50 | tidyEncoding = @"ascii"; 51 | break; 52 | 53 | case NSISOLatin1StringEncoding: 54 | tidyEncoding = @"latin1"; 55 | break; 56 | 57 | // raw? 58 | 59 | case NSUTF8StringEncoding: 60 | tidyEncoding = @"utf8"; 61 | break; 62 | 63 | case NSISO2022JPStringEncoding: 64 | tidyEncoding = @"iso2022"; 65 | break; 66 | 67 | case NSMacOSRomanStringEncoding: 68 | tidyEncoding = @"mac"; 69 | break; 70 | 71 | case NSWindowsCP1252StringEncoding: 72 | tidyEncoding = @"win1252"; 73 | break; 74 | 75 | case NSUTF16LittleEndianStringEncoding: 76 | tidyEncoding = @"utf16le"; 77 | break; 78 | 79 | case NSUTF16BigEndianStringEncoding: 80 | tidyEncoding = @"utf16be"; 81 | break; 82 | 83 | case NSUTF16StringEncoding: 84 | tidyEncoding = @"utf16"; 85 | break; 86 | 87 | // big5 not enumerated in NSStringEncoding 88 | 89 | case NSShiftJISStringEncoding: 90 | tidyEncoding = @"shiftjis"; 91 | break; 92 | 93 | default: 94 | tidyEncoding = nil; 95 | break; 96 | } 97 | 98 | return tidyEncoding; 99 | } 100 | 101 | - (NSData *)tidyData:(NSData *)inData inputFormat:(CTidyFormat)inInputFormat outputFormat:(CTidyFormat)inOutputFormat encoding:(const char *)encoding diagnostics:(NSString **)outDiagnostics error:(NSError **)outError { 102 | TidyDoc theTidyDocument = tidyCreate(); 103 | 104 | int theResultCode = 0; 105 | 106 | // Set input format if input is XML (xhtml & html are the tidy 'default') 107 | if (inInputFormat == TidyFormat_XML) { 108 | theResultCode = tidyOptSetBool(theTidyDocument, TidyXmlTags, YES); 109 | NSAssert(theResultCode >= 0, @"tidyOptSetBool() should return 0"); 110 | } 111 | 112 | // Set output format 113 | TidyOptionId theOutputValue = TidyXmlOut; 114 | if (inOutputFormat == TidyFormat_HTML) { 115 | theOutputValue = TidyHtmlOut; 116 | } 117 | 118 | else if (inOutputFormat == TidyFormat_XHTML) { 119 | theOutputValue = TidyXhtmlOut; 120 | } 121 | theResultCode = tidyOptSetBool(theTidyDocument, theOutputValue, YES); 122 | NSAssert(theResultCode >= 0, @"tidyOptSetBool() should return 0"); 123 | 124 | // Force output even if errors found 125 | theResultCode = tidyOptSetBool(theTidyDocument, TidyForceOutput, YES); 126 | NSAssert(theResultCode >= 0, @"tidyOptSetBool() should return 0"); 127 | 128 | // Set encoding - same for input and output 129 | theResultCode = tidySetInCharEncoding(theTidyDocument, encoding); 130 | NSAssert(theResultCode >= 0, @"tidySetInCharEncoding() should return 0"); 131 | theResultCode = tidySetOutCharEncoding(theTidyDocument, encoding); 132 | NSAssert(theResultCode >= 0, @"tidySetOutCharEncoding() should return 0"); 133 | 134 | // Create an error buffer 135 | TidyBuffer theErrorBuffer; 136 | tidyBufInit(&theErrorBuffer); 137 | theResultCode = tidySetErrorBuffer(theTidyDocument, &theErrorBuffer); 138 | NSAssert(theResultCode >= 0, @"tidySetErrorBuffer() should return 0"); 139 | 140 | // ############################################################################# 141 | 142 | // Create an input buffer and copy input to it (TODO uses 2X memory == bad!) 143 | TidyBuffer theInputBuffer; 144 | /* 145 | Without this line following memcpy crashes compiling with LLVM 4, because 146 | realloc does not find a NULL pointer to malloc in tidyBufAlloc() call 147 | */ 148 | theInputBuffer.bp = NULL; 149 | tidyBufAlloc(&theInputBuffer, [inData length]); 150 | memcpy(theInputBuffer.bp, [inData bytes], [inData length]); 151 | theInputBuffer.size = [inData length]; 152 | 153 | // Parse the data. 154 | theResultCode = tidyParseBuffer(theTidyDocument, &theInputBuffer); 155 | if (theResultCode < 0) { 156 | if (outError) { 157 | NSDictionary *theUserInfo = [[NSDictionary alloc] initWithObjectsAndKeys:[NSString stringWithUTF8String:(char *)theErrorBuffer.bp], NSLocalizedDescriptionKey, nil]; 158 | 159 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:theResultCode userInfo:theUserInfo]; 160 | } 161 | 162 | return nil; 163 | } 164 | 165 | // Clean up input buffer. 166 | tidyBufFree(&theInputBuffer); 167 | 168 | // Repair the data 169 | theResultCode = tidyCleanAndRepair(theTidyDocument); 170 | if (theResultCode < 0) { 171 | return nil; 172 | } 173 | 174 | //theResultCode = tidyRunDiagnostics(theTidyDocument); 175 | 176 | // 177 | TidyBuffer theOutputBuffer; 178 | tidyBufInit(&theOutputBuffer); 179 | theResultCode = tidySaveBuffer(theTidyDocument, &theOutputBuffer); 180 | if (theResultCode < 0) { 181 | return nil; 182 | } 183 | 184 | NSAssert(theOutputBuffer.bp != NULL, @"The buffer should not be null."); 185 | NSData *theOutput = [[NSData alloc] initWithBytes:theOutputBuffer.bp length:theOutputBuffer.size]; 186 | tidyBufFree(&theOutputBuffer); 187 | 188 | // 189 | if (outDiagnostics && theErrorBuffer.bp != NULL) { 190 | NSData *theErrorData = [[NSData alloc] initWithBytes:theErrorBuffer.bp length:theErrorBuffer.size]; 191 | *outDiagnostics = [[NSString alloc] initWithData:theErrorData encoding:NSUTF8StringEncoding]; 192 | } 193 | tidyBufFree(&theErrorBuffer); 194 | 195 | // ############################################################################# 196 | 197 | tidyRelease(theTidyDocument); 198 | 199 | return theOutput; 200 | } 201 | 202 | - (NSString *)tidyString:(NSString *)inString inputFormat:(CTidyFormat)inInputFormat outputFormat:(CTidyFormat)inOutputFormat encoding:(const char *)encoding diagnostics:(NSString **)outDiagnostics error:(NSError **)outError { 203 | TidyDoc theTidyDocument = tidyCreate(); 204 | 205 | int theResultCode = 0; 206 | 207 | // Set input format if input is XML (xhtml & html are the tidy 'default') 208 | if (inInputFormat == TidyFormat_XML) { 209 | theResultCode = tidyOptSetBool(theTidyDocument, TidyXmlTags, YES); 210 | NSAssert(theResultCode >= 0, @"tidyOptSetBool() should return 0"); 211 | } 212 | 213 | // Set output format 214 | TidyOptionId theOutputValue = TidyXmlOut; 215 | if (inOutputFormat == TidyFormat_HTML) { 216 | theOutputValue = TidyHtmlOut; 217 | } else if (inOutputFormat == TidyFormat_XHTML) { 218 | theOutputValue = TidyXhtmlOut; 219 | } 220 | theResultCode = tidyOptSetBool(theTidyDocument, theOutputValue, YES); 221 | NSAssert(theResultCode >= 0, @"tidyOptSetBool() should return 0"); 222 | 223 | // Force output even if errors found 224 | theResultCode = tidyOptSetBool(theTidyDocument, TidyForceOutput, YES); 225 | NSAssert(theResultCode >= 0, @"tidyOptSetBool() should return 0"); 226 | 227 | // Set encoding - same for input and output 228 | theResultCode = tidySetInCharEncoding(theTidyDocument, encoding); 229 | NSAssert(theResultCode >= 0, @"tidySetInCharEncoding() should return 0"); 230 | theResultCode = tidySetOutCharEncoding(theTidyDocument, encoding); 231 | NSAssert(theResultCode >= 0, @"tidySetOutCharEncoding() should return 0"); 232 | 233 | // Create an error buffer 234 | TidyBuffer theErrorBuffer; 235 | tidyBufInit(&theErrorBuffer); 236 | theResultCode = tidySetErrorBuffer(theTidyDocument, &theErrorBuffer); 237 | NSAssert(theResultCode >= 0, @"tidySetErrorBuffer() should return 0"); 238 | 239 | // ############################################################################# 240 | 241 | // Parse the data. 242 | theResultCode = tidyParseString(theTidyDocument, [inString UTF8String]); 243 | if (theResultCode < 0) { 244 | if (outError) { 245 | NSDictionary *theUserInfo = [[NSDictionary alloc] initWithObjectsAndKeys:[NSString stringWithUTF8String:(char *)theErrorBuffer.bp], NSLocalizedDescriptionKey, nil]; 246 | *outError = [NSError errorWithDomain:@"TODO_DOMAIN" code:theResultCode userInfo:theUserInfo]; 247 | } 248 | return nil; 249 | } 250 | 251 | // Repair the data 252 | theResultCode = tidyCleanAndRepair(theTidyDocument); 253 | if (theResultCode < 0) { 254 | return nil; 255 | } 256 | 257 | //theResultCode = tidyRunDiagnostics(theTidyDocument); 258 | 259 | // 260 | uint theBufferLength = 0; 261 | 262 | theResultCode = tidySaveString(theTidyDocument, NULL, &theBufferLength); 263 | 264 | NSMutableData *theOutputBuffer = [[NSMutableData alloc] initWithLength:theBufferLength]; 265 | 266 | theResultCode = tidySaveString(theTidyDocument, [theOutputBuffer mutableBytes], &theBufferLength); 267 | 268 | NSString *theString = [[NSString alloc] initWithData:theOutputBuffer encoding:NSUTF8StringEncoding]; 269 | 270 | // 271 | if (outDiagnostics && theErrorBuffer.bp != NULL) { 272 | NSData *theErrorData = [[NSData alloc] initWithBytes:theErrorBuffer.bp length:theErrorBuffer.size]; 273 | *outDiagnostics = [[NSString alloc] initWithData:theErrorData encoding:NSUTF8StringEncoding]; 274 | } 275 | tidyBufFree(&theErrorBuffer); 276 | 277 | // ############################################################################# 278 | 279 | tidyRelease(theTidyDocument); 280 | 281 | return theString; 282 | } 283 | 284 | @end 285 | 286 | #endif /* TOUCHXMLUSETIDY */ 287 | -------------------------------------------------------------------------------- /Vendor/TouchXML/TouchXML.h: -------------------------------------------------------------------------------- 1 | // 2 | // TouchXML.h 3 | // TouchCode 4 | // 5 | // Created by Jonathan Wight on 07/11/08. 6 | // Copyright 2011 toxicsoftware.com. All rights reserved. 7 | // 8 | // Redistribution and use in source and binary forms, with or without modification, are 9 | // permitted provided that the following conditions are met: 10 | // 11 | // 1. Redistributions of source code must retain the above copyright notice, this list of 12 | // conditions and the following disclaimer. 13 | // 14 | // 2. Redistributions in binary form must reproduce the above copyright notice, this list 15 | // of conditions and the following disclaimer in the documentation and/or other materials 16 | // provided with the distribution. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY TOXICSOFTWARE.COM ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL TOXICSOFTWARE.COM OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | // The views and conclusions contained in the software and documentation are those of the 29 | // authors and should not be interpreted as representing official policies, either expressed 30 | // or implied, of toxicsoftware.com. 31 | 32 | //! Project version number for TouchXML. 33 | FOUNDATION_EXPORT double TouchXMLVersionNumber; 34 | 35 | //! Project version string for TouchXML. 36 | FOUNDATION_EXPORT const unsigned char TouchXMLVersionString[]; 37 | 38 | // In this header, you should import all the public headers of your framework using statements like #import <TouchXML/PublicHeader.h> 39 | 40 | #import <TouchXML/CXMLDocument.h> 41 | #import <TouchXML/CXMLDocument_CreationExtensions.h> 42 | #import <TouchXML/CXMLElement.h> 43 | #import <TouchXML/CXMLElement_CreationExtensions.h> 44 | #import <TouchXML/CXMLElement_ElementTreeExtensions.h> 45 | #import <TouchXML/CXMLNode.h> 46 | #import <TouchXML/CXMLNode_CreationExtensions.h> 47 | #import <TouchXML/CXMLNode_XPathExtensions.h> 48 | #import <TouchXML/CXMLUnsupportedNode.h> 49 | -------------------------------------------------------------------------------- /fix_format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | base_git=`git rev-parse --show-toplevel` 3 | 4 | files=() 5 | for file in `git diff --cached --name-only --diff-filter=ACMRT | grep -E "\.(m|h)$"`; do 6 | echo "fixing format for file: ${file}" 7 | clang-format ${base_git}/${file} -i 8 | done -------------------------------------------------------------------------------- /readme/appstore-badge.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 4 | <svg version="1.1" id="US_UK_Download_on_the" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 5 | x="0px" y="0px" width="135px" height="40px" viewBox="0 0 135 40" enable-background="new 0 0 135 40" xml:space="preserve"> 6 | <g> 7 | <path fill="#A6A6A6" d="M130.197,40H4.729C2.122,40,0,37.872,0,35.267V4.726C0,2.12,2.122,0,4.729,0h125.468 8 | C132.803,0,135,2.12,135,4.726v30.541C135,37.872,132.803,40,130.197,40L130.197,40z"/> 9 | <path d="M134.032,35.268c0,2.116-1.714,3.83-3.834,3.83H4.729c-2.119,0-3.839-1.714-3.839-3.83V4.725 10 | c0-2.115,1.72-3.835,3.839-3.835h125.468c2.121,0,3.834,1.72,3.834,3.835L134.032,35.268L134.032,35.268z"/> 11 | <g> 12 | <g> 13 | <path fill="#FFFFFF" d="M30.128,19.784c-0.029-3.223,2.639-4.791,2.761-4.864c-1.511-2.203-3.853-2.504-4.676-2.528 14 | c-1.967-0.207-3.875,1.177-4.877,1.177c-1.022,0-2.565-1.157-4.228-1.123c-2.14,0.033-4.142,1.272-5.24,3.196 15 | c-2.266,3.923-0.576,9.688,1.595,12.859c1.086,1.553,2.355,3.287,4.016,3.226c1.625-0.067,2.232-1.036,4.193-1.036 16 | c1.943,0,2.513,1.036,4.207,0.997c1.744-0.028,2.842-1.56,3.89-3.127c1.255-1.78,1.759-3.533,1.779-3.623 17 | C33.507,24.924,30.161,23.647,30.128,19.784z"/> 18 | <path fill="#FFFFFF" d="M26.928,10.306c0.874-1.093,1.472-2.58,1.306-4.089c-1.265,0.056-2.847,0.875-3.758,1.944 19 | c-0.806,0.942-1.526,2.486-1.34,3.938C24.557,12.205,26.016,11.382,26.928,10.306z"/> 20 | </g> 21 | </g> 22 | <g> 23 | <path fill="#FFFFFF" d="M53.645,31.504h-2.271l-1.244-3.909h-4.324l-1.185,3.909h-2.211l4.284-13.308h2.646L53.645,31.504z 24 | M49.755,25.955L48.63,22.48c-0.119-0.355-0.342-1.191-0.671-2.507h-0.04c-0.131,0.566-0.342,1.402-0.632,2.507l-1.105,3.475 25 | H49.755z"/> 26 | <path fill="#FFFFFF" d="M64.662,26.588c0,1.632-0.441,2.922-1.323,3.869c-0.79,0.843-1.771,1.264-2.942,1.264 27 | c-1.264,0-2.172-0.454-2.725-1.362h-0.04v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04 28 | c0.711-1.146,1.79-1.718,3.238-1.718c1.132,0,2.077,0.447,2.833,1.342C64.284,23.949,64.662,25.127,64.662,26.588z M62.49,26.666 29 | c0-0.934-0.21-1.704-0.632-2.31c-0.461-0.632-1.08-0.948-1.856-0.948c-0.526,0-1.004,0.176-1.431,0.523 30 | c-0.428,0.35-0.708,0.807-0.839,1.373c-0.066,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.642,1.768 31 | s0.984,0.721,1.668,0.721c0.803,0,1.428-0.31,1.875-0.928C62.266,28.496,62.49,27.68,62.49,26.666z"/> 32 | <path fill="#FFFFFF" d="M75.699,26.588c0,1.632-0.441,2.922-1.324,3.869c-0.789,0.843-1.77,1.264-2.941,1.264 33 | c-1.264,0-2.172-0.454-2.724-1.362H68.67v5.055h-2.132V25.067c0-1.026-0.027-2.079-0.079-3.159h1.875l0.119,1.521h0.04 34 | c0.71-1.146,1.789-1.718,3.238-1.718c1.131,0,2.076,0.447,2.834,1.342C75.32,23.949,75.699,25.127,75.699,26.588z M73.527,26.666 35 | c0-0.934-0.211-1.704-0.633-2.31c-0.461-0.632-1.078-0.948-1.855-0.948c-0.527,0-1.004,0.176-1.432,0.523 36 | c-0.428,0.35-0.707,0.807-0.838,1.373c-0.065,0.264-0.099,0.48-0.099,0.65v1.6c0,0.698,0.214,1.287,0.64,1.768 37 | c0.428,0.48,0.984,0.721,1.67,0.721c0.803,0,1.428-0.31,1.875-0.928C73.303,28.496,73.527,27.68,73.527,26.666z"/> 38 | <path fill="#FFFFFF" d="M88.039,27.772c0,1.132-0.393,2.053-1.182,2.764c-0.867,0.777-2.074,1.165-3.625,1.165 39 | c-1.432,0-2.58-0.276-3.449-0.829l0.494-1.777c0.936,0.566,1.963,0.85,3.082,0.85c0.803,0,1.428-0.182,1.877-0.544 40 | c0.447-0.362,0.67-0.848,0.67-1.454c0-0.54-0.184-0.995-0.553-1.364c-0.367-0.369-0.98-0.712-1.836-1.029 41 | c-2.33-0.869-3.494-2.142-3.494-3.816c0-1.094,0.408-1.991,1.225-2.689c0.814-0.699,1.9-1.048,3.258-1.048 42 | c1.211,0,2.217,0.211,3.02,0.632l-0.533,1.738c-0.75-0.408-1.598-0.612-2.547-0.612c-0.75,0-1.336,0.185-1.756,0.553 43 | c-0.355,0.329-0.533,0.73-0.533,1.205c0,0.526,0.203,0.961,0.611,1.303c0.355,0.316,1,0.658,1.936,1.027 44 | c1.145,0.461,1.986,1,2.527,1.618C87.77,26.081,88.039,26.852,88.039,27.772z"/> 45 | <path fill="#FFFFFF" d="M95.088,23.508h-2.35v4.659c0,1.185,0.414,1.777,1.244,1.777c0.381,0,0.697-0.033,0.947-0.099l0.059,1.619 46 | c-0.42,0.157-0.973,0.236-1.658,0.236c-0.842,0-1.5-0.257-1.975-0.77c-0.473-0.514-0.711-1.376-0.711-2.587v-4.837h-1.4v-1.6h1.4 47 | v-1.757l2.094-0.632v2.389h2.35V23.508z"/> 48 | <path fill="#FFFFFF" d="M105.691,26.627c0,1.475-0.422,2.686-1.264,3.633c-0.883,0.975-2.055,1.461-3.516,1.461 49 | c-1.408,0-2.529-0.467-3.365-1.401s-1.254-2.113-1.254-3.534c0-1.487,0.43-2.705,1.293-3.652c0.861-0.948,2.023-1.422,3.484-1.422 50 | c1.408,0,2.541,0.467,3.396,1.402C105.283,24.021,105.691,25.192,105.691,26.627z M103.479,26.696 51 | c0-0.885-0.189-1.644-0.572-2.277c-0.447-0.766-1.086-1.148-1.914-1.148c-0.857,0-1.508,0.383-1.955,1.148 52 | c-0.383,0.634-0.572,1.405-0.572,2.317c0,0.885,0.189,1.644,0.572,2.276c0.461,0.766,1.105,1.148,1.936,1.148 53 | c0.814,0,1.453-0.39,1.914-1.168C103.281,28.347,103.479,27.58,103.479,26.696z"/> 54 | <path fill="#FFFFFF" d="M112.621,23.783c-0.211-0.039-0.436-0.059-0.672-0.059c-0.75,0-1.33,0.283-1.738,0.85 55 | c-0.355,0.5-0.533,1.132-0.533,1.895v5.035h-2.131l0.02-6.574c0-1.106-0.027-2.113-0.08-3.021h1.857l0.078,1.836h0.059 56 | c0.225-0.631,0.58-1.139,1.066-1.52c0.475-0.343,0.988-0.514,1.541-0.514c0.197,0,0.375,0.014,0.533,0.039V23.783z"/> 57 | <path fill="#FFFFFF" d="M122.156,26.252c0,0.382-0.025,0.704-0.078,0.967h-6.396c0.025,0.948,0.334,1.673,0.928,2.173 58 | c0.539,0.447,1.236,0.671,2.092,0.671c0.947,0,1.811-0.151,2.588-0.454l0.334,1.48c-0.908,0.396-1.98,0.593-3.217,0.593 59 | c-1.488,0-2.656-0.438-3.506-1.313c-0.848-0.875-1.273-2.05-1.273-3.524c0-1.447,0.395-2.652,1.186-3.613 60 | c0.828-1.026,1.947-1.539,3.355-1.539c1.383,0,2.43,0.513,3.141,1.539C121.873,24.047,122.156,25.055,122.156,26.252z 61 | M120.123,25.699c0.014-0.632-0.125-1.178-0.414-1.639c-0.369-0.593-0.936-0.889-1.699-0.889c-0.697,0-1.264,0.289-1.697,0.869 62 | c-0.355,0.461-0.566,1.014-0.631,1.658H120.123z"/> 63 | </g> 64 | <g> 65 | <g> 66 | <path fill="#FFFFFF" d="M49.05,10.009c0,1.177-0.353,2.063-1.058,2.658c-0.653,0.549-1.581,0.824-2.783,0.824 67 | c-0.596,0-1.106-0.026-1.533-0.078V6.982c0.557-0.09,1.157-0.136,1.805-0.136c1.145,0,2.008,0.249,2.59,0.747 68 | C48.723,8.156,49.05,8.961,49.05,10.009z M47.945,10.038c0-0.763-0.202-1.348-0.606-1.756c-0.404-0.407-0.994-0.611-1.771-0.611 69 | c-0.33,0-0.611,0.022-0.844,0.068v4.889c0.129,0.02,0.365,0.029,0.708,0.029c0.802,0,1.421-0.223,1.857-0.669 70 | S47.945,10.892,47.945,10.038z"/> 71 | <path fill="#FFFFFF" d="M54.909,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.009,0.718-1.727,0.718 72 | c-0.692,0-1.243-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.712-0.698 73 | c0.692,0,1.248,0.229,1.669,0.688C54.708,9.757,54.909,10.333,54.909,11.037z M53.822,11.071c0-0.435-0.094-0.808-0.281-1.119 74 | c-0.22-0.376-0.533-0.564-0.94-0.564c-0.421,0-0.741,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138 75 | c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.714-0.191,0.94-0.574 76 | C53.725,11.882,53.822,11.506,53.822,11.071z"/> 77 | <path fill="#FFFFFF" d="M62.765,8.719l-1.475,4.714h-0.96l-0.611-2.047c-0.155-0.511-0.281-1.019-0.379-1.523h-0.019 78 | c-0.091,0.518-0.217,1.025-0.379,1.523l-0.649,2.047h-0.971l-1.387-4.714h1.077l0.533,2.241c0.129,0.53,0.235,1.035,0.32,1.513 79 | h0.019c0.078-0.394,0.207-0.896,0.389-1.503l0.669-2.25h0.854l0.641,2.202c0.155,0.537,0.281,1.054,0.378,1.552h0.029 80 | c0.071-0.485,0.178-1.002,0.32-1.552l0.572-2.202H62.765z"/> 81 | <path fill="#FFFFFF" d="M68.198,13.433H67.15v-2.7c0-0.832-0.316-1.248-0.95-1.248c-0.311,0-0.562,0.114-0.757,0.343 82 | c-0.193,0.229-0.291,0.499-0.291,0.808v2.796h-1.048v-3.366c0-0.414-0.013-0.863-0.038-1.349h0.921l0.049,0.737h0.029 83 | c0.122-0.229,0.304-0.418,0.543-0.569c0.284-0.176,0.602-0.265,0.95-0.265c0.44,0,0.806,0.142,1.097,0.427 84 | c0.362,0.349,0.543,0.87,0.543,1.562V13.433z"/> 85 | <path fill="#FFFFFF" d="M71.088,13.433h-1.047V6.556h1.047V13.433z"/> 86 | <path fill="#FFFFFF" d="M77.258,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.01,0.718-1.727,0.718 87 | c-0.693,0-1.244-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.711-0.698 88 | c0.693,0,1.248,0.229,1.67,0.688C77.057,9.757,77.258,10.333,77.258,11.037z M76.17,11.071c0-0.435-0.094-0.808-0.281-1.119 89 | c-0.219-0.376-0.533-0.564-0.939-0.564c-0.422,0-0.742,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138 90 | c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.713-0.191,0.939-0.574 91 | C76.074,11.882,76.17,11.506,76.17,11.071z"/> 92 | <path fill="#FFFFFF" d="M82.33,13.433h-0.941l-0.078-0.543h-0.029c-0.322,0.433-0.781,0.65-1.377,0.65 93 | c-0.445,0-0.805-0.143-1.076-0.427c-0.246-0.258-0.369-0.579-0.369-0.96c0-0.576,0.24-1.015,0.723-1.319 94 | c0.482-0.304,1.16-0.453,2.033-0.446V10.3c0-0.621-0.326-0.931-0.979-0.931c-0.465,0-0.875,0.117-1.229,0.349l-0.213-0.688 95 | c0.438-0.271,0.979-0.407,1.617-0.407c1.232,0,1.85,0.65,1.85,1.95v1.736C82.262,12.78,82.285,13.155,82.33,13.433z 96 | M81.242,11.813v-0.727c-1.156-0.02-1.734,0.297-1.734,0.95c0,0.246,0.066,0.43,0.201,0.553c0.135,0.123,0.307,0.184,0.512,0.184 97 | c0.23,0,0.445-0.073,0.641-0.218c0.197-0.146,0.318-0.331,0.363-0.558C81.236,11.946,81.242,11.884,81.242,11.813z"/> 98 | <path fill="#FFFFFF" d="M88.285,13.433h-0.93l-0.049-0.757h-0.029c-0.297,0.576-0.803,0.864-1.514,0.864 99 | c-0.568,0-1.041-0.223-1.416-0.669s-0.562-1.025-0.562-1.736c0-0.763,0.203-1.381,0.611-1.853c0.395-0.44,0.879-0.66,1.455-0.66 100 | c0.633,0,1.076,0.213,1.328,0.64h0.02V6.556h1.049v5.607C88.248,12.622,88.26,13.045,88.285,13.433z M87.199,11.445v-0.786 101 | c0-0.136-0.01-0.246-0.029-0.33c-0.059-0.252-0.186-0.464-0.379-0.635c-0.195-0.171-0.43-0.257-0.701-0.257 102 | c-0.391,0-0.697,0.155-0.922,0.466c-0.223,0.311-0.336,0.708-0.336,1.193c0,0.466,0.107,0.844,0.322,1.135 103 | c0.227,0.31,0.533,0.465,0.916,0.465c0.344,0,0.619-0.129,0.828-0.388C87.1,12.069,87.199,11.781,87.199,11.445z"/> 104 | <path fill="#FFFFFF" d="M97.248,11.037c0,0.725-0.207,1.319-0.621,1.785c-0.434,0.479-1.008,0.718-1.727,0.718 105 | c-0.691,0-1.242-0.229-1.654-0.689c-0.41-0.459-0.615-1.038-0.615-1.736c0-0.73,0.211-1.329,0.635-1.794s0.994-0.698,1.713-0.698 106 | c0.691,0,1.248,0.229,1.668,0.688C97.047,9.757,97.248,10.333,97.248,11.037z M96.162,11.071c0-0.435-0.094-0.808-0.281-1.119 107 | c-0.221-0.376-0.533-0.564-0.941-0.564c-0.42,0-0.74,0.188-0.961,0.564c-0.188,0.311-0.281,0.69-0.281,1.138 108 | c0,0.435,0.094,0.808,0.281,1.119c0.227,0.376,0.543,0.564,0.951,0.564c0.4,0,0.715-0.191,0.941-0.574 109 | C96.064,11.882,96.162,11.506,96.162,11.071z"/> 110 | <path fill="#FFFFFF" d="M102.883,13.433h-1.047v-2.7c0-0.832-0.316-1.248-0.951-1.248c-0.311,0-0.562,0.114-0.756,0.343 111 | s-0.291,0.499-0.291,0.808v2.796h-1.049v-3.366c0-0.414-0.012-0.863-0.037-1.349h0.92l0.049,0.737h0.029 112 | c0.123-0.229,0.305-0.418,0.543-0.569c0.285-0.176,0.602-0.265,0.951-0.265c0.439,0,0.805,0.142,1.096,0.427 113 | c0.363,0.349,0.543,0.87,0.543,1.562V13.433z"/> 114 | <path fill="#FFFFFF" d="M109.936,9.504h-1.154v2.29c0,0.582,0.205,0.873,0.611,0.873c0.188,0,0.344-0.016,0.467-0.049 115 | l0.027,0.795c-0.207,0.078-0.479,0.117-0.814,0.117c-0.414,0-0.736-0.126-0.969-0.378c-0.234-0.252-0.35-0.676-0.35-1.271V9.504 116 | h-0.689V8.719h0.689V7.855l1.027-0.31v1.173h1.154V9.504z"/> 117 | <path fill="#FFFFFF" d="M115.484,13.433h-1.049v-2.68c0-0.845-0.316-1.268-0.949-1.268c-0.486,0-0.818,0.245-1,0.735 118 | c-0.031,0.103-0.049,0.229-0.049,0.377v2.835h-1.047V6.556h1.047v2.841h0.02c0.33-0.517,0.803-0.775,1.416-0.775 119 | c0.434,0,0.793,0.142,1.078,0.427c0.355,0.355,0.533,0.883,0.533,1.581V13.433z"/> 120 | <path fill="#FFFFFF" d="M121.207,10.853c0,0.188-0.014,0.346-0.039,0.475h-3.143c0.014,0.466,0.164,0.821,0.455,1.067 121 | c0.266,0.22,0.609,0.33,1.029,0.33c0.465,0,0.889-0.074,1.271-0.223l0.164,0.728c-0.447,0.194-0.973,0.291-1.582,0.291 122 | c-0.73,0-1.305-0.215-1.721-0.645c-0.418-0.43-0.625-1.007-0.625-1.731c0-0.711,0.193-1.303,0.582-1.775 123 | c0.406-0.504,0.955-0.756,1.648-0.756c0.678,0,1.193,0.252,1.541,0.756C121.068,9.77,121.207,10.265,121.207,10.853z 124 | M120.207,10.582c0.008-0.311-0.061-0.579-0.203-0.805c-0.182-0.291-0.459-0.437-0.834-0.437c-0.342,0-0.621,0.142-0.834,0.427 125 | c-0.174,0.227-0.277,0.498-0.311,0.815H120.207z"/> 126 | </g> 127 | </g> 128 | </g> 129 | </svg> 130 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hezi/Storytime/23a5f9a637fe700a6b57f938b3ead23bbe388c4c/screenshot.png --------------------------------------------------------------------------------